diff --git a/Cargo.lock b/Cargo.lock index 5f5b81c0..a953ceb6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,15 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" +dependencies = [ + "derive_arbitrary", +] + [[package]] name = "atty" version = "0.2.14" @@ -50,6 +59,7 @@ dependencies = [ name = "bls12_381" version = "0.8.0" dependencies = [ + "arbitrary", "criterion", "csv", "digest", @@ -226,6 +236,17 @@ dependencies = [ "memchr", ] +[[package]] +name = "derive_arbitrary" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + [[package]] name = "digest" version = "0.10.7" @@ -455,18 +476,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -580,7 +601,7 @@ checksum = "af487d118eecd09402d70a5d72551860e788df87b464af30e5ea6a38c75c541e" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] @@ -632,6 +653,17 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn" +version = "2.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "tap" version = "1.0.1" @@ -713,7 +745,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-shared", ] @@ -735,7 +767,7 @@ checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", "wasm-bindgen-backend", "wasm-bindgen-shared", ] diff --git a/Cargo.toml b/Cargo.toml index 75754571..533c5df6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ pairing = { version = "0.23", optional = true } rand_core = { version = "0.6", default-features = false } subtle = { version = "2.2.1", default-features = false } zeroize = { version = "1.4", optional = true, default-features = false } +arbitrary = { version = "1.3", features = ["derive"], optional = true } [dev-dependencies] csv = ">= 1.0, < 1.2" # csv 1.2 has MSRV 1.60 @@ -41,6 +42,7 @@ pairings = ["groups", "pairing"] alloc = ["group/alloc"] experimental = ["digest", "groups"] nightly = ["subtle/nightly"] +arbitrary = ["dep:arbitrary"] [[test]] name = "expand_msg" diff --git a/rust-toolchain.toml b/rust-toolchain.toml index de43b230..3eebdfe1 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,3 +1,3 @@ [toolchain] -channel = "1.56.0" +channel = "1.63.0" components = [ "clippy", "rustfmt" ] diff --git a/src/fp.rs b/src/fp.rs index cf968077..b7b6d2bb 100644 --- a/src/fp.rs +++ b/src/fp.rs @@ -11,6 +11,7 @@ use crate::util::{adc, mac, sbb}; // The internal representation of this type is six 64-bit unsigned // integers in little-endian order. `Fp` values are always in // Montgomery form; i.e., Scalar(a) = aR mod p, with R = 2^384. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Copy, Clone)] pub struct Fp(pub(crate) [u64; 6]); diff --git a/src/fp12.rs b/src/fp12.rs index 26b48043..b1493220 100644 --- a/src/fp12.rs +++ b/src/fp12.rs @@ -10,6 +10,7 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use rand_core::RngCore; /// This represents an element $c_0 + c_1 w$ of $\mathbb{F}_{p^12} = \mathbb{F}_{p^6} / w^2 - v$. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct Fp12 { pub c0: Fp6, pub c1: Fp6, diff --git a/src/fp2.rs b/src/fp2.rs index 1ad856fc..2fea3e1b 100644 --- a/src/fp2.rs +++ b/src/fp2.rs @@ -7,6 +7,7 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use crate::fp::Fp; +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Copy, Clone)] pub struct Fp2 { pub c0: Fp, diff --git a/src/fp6.rs b/src/fp6.rs index 55420422..a4053389 100644 --- a/src/fp6.rs +++ b/src/fp6.rs @@ -9,6 +9,7 @@ use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use rand_core::RngCore; /// This represents an element $c_0 + c_1 v + c_2 v^2$ of $\mathbb{F}_{p^6} = \mathbb{F}_{p^2} / v^3 - u - 1$. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] pub struct Fp6 { pub c0: Fp2, pub c1: Fp2, diff --git a/src/g1.rs b/src/g1.rs index 17687495..c14e3cb9 100644 --- a/src/g1.rs +++ b/src/g1.rs @@ -23,11 +23,13 @@ use crate::Scalar; /// /// Values of `G1Affine` are guaranteed to be in the $q$-order subgroup unless an /// "unchecked" API was misused. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(docsrs, doc(cfg(feature = "groups")))] #[derive(Copy, Clone, Debug)] pub struct G1Affine { pub(crate) x: Fp, pub(crate) y: Fp, + #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::util::arbitrary_choice))] infinity: Choice, } @@ -437,6 +439,7 @@ fn endomorphism(p: &G1Affine) -> G1Affine { } /// This is an element of $\mathbb{G}_1$ represented in the projective coordinate space. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(docsrs, doc(cfg(feature = "groups")))] #[derive(Copy, Clone, Debug)] pub struct G1Projective { diff --git a/src/g2.rs b/src/g2.rs index 3a6848ad..cf0e0131 100644 --- a/src/g2.rs +++ b/src/g2.rs @@ -24,11 +24,13 @@ use crate::Scalar; /// /// Values of `G2Affine` are guaranteed to be in the $q$-order subgroup unless an /// "unchecked" API was misused. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(docsrs, doc(cfg(feature = "groups")))] #[derive(Copy, Clone, Debug)] pub struct G2Affine { pub(crate) x: Fp2, pub(crate) y: Fp2, + #[cfg_attr(feature = "arbitrary", arbitrary(with = crate::util::arbitrary_choice))] infinity: Choice, } @@ -490,6 +492,7 @@ impl G2Affine { } /// This is an element of $\mathbb{G}_2$ represented in the projective coordinate space. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(docsrs, doc(cfg(feature = "groups")))] #[derive(Copy, Clone, Debug)] pub struct G2Projective { diff --git a/src/lib.rs b/src/lib.rs index cfb6dcc3..34689c63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ //! * This implementation does not require the Rust standard library. //! * All operations are constant time unless explicitly noted. -#![no_std] +#![cfg_attr(not(feature = "arbitrary"), no_std)] #![cfg_attr(docsrs, feature(doc_cfg))] // Catch documentation errors caused by code changes. #![deny(rustdoc::broken_intra_doc_links)] diff --git a/src/pairings.rs b/src/pairings.rs index 43992e3e..fcac888a 100644 --- a/src/pairings.rs +++ b/src/pairings.rs @@ -21,6 +21,7 @@ use pairing::MultiMillerLoop; /// Represents results of a Miller loop, one of the most expensive portions /// of the pairing function. `MillerLoopResult`s cannot be compared with each /// other until `.final_exponentiation()` is called, which is also expensive. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(docsrs, doc(cfg(feature = "pairings")))] #[derive(Copy, Clone, Debug)] pub struct MillerLoopResult(pub(crate) Fp12); @@ -206,6 +207,7 @@ impl<'b> AddAssign<&'b MillerLoopResult> for MillerLoopResult { /// /// Typically, $\mathbb{G}_T$ is written multiplicatively but we will write it additively to /// keep code and abstractions consistent. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[cfg_attr(docsrs, doc(cfg(feature = "pairings")))] #[derive(Copy, Clone, Debug)] pub struct Gt(pub(crate) Fp12); diff --git a/src/scalar.rs b/src/scalar.rs index 5f08e4b2..08a23d84 100644 --- a/src/scalar.rs +++ b/src/scalar.rs @@ -18,6 +18,7 @@ use crate::util::{adc, mac, sbb}; // The internal representation of this type is four 64-bit unsigned // integers in little-endian order. `Scalar` values are always in // Montgomery form; i.e., Scalar(a) = aR mod q, with R = 2^256. +#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))] #[derive(Clone, Copy, Eq)] pub struct Scalar(pub(crate) [u64; 4]); diff --git a/src/util.rs b/src/util.rs index bd25dd06..ec0f724e 100644 --- a/src/util.rs +++ b/src/util.rs @@ -172,3 +172,10 @@ macro_rules! impl_binops_multiplicative { } }; } + +/// Generate arbitrary [`subtle::Choice`] +#[cfg(feature = "arbitrary")] +pub fn arbitrary_choice(u: &mut arbitrary::Unstructured) -> arbitrary::Result { + let raw = u.int_in_range(0..=1)?; + Ok(subtle::Choice::from(raw)) +}