From 8cc62b8ce237d9d84b7723a3a8b8ae0a05b2846f Mon Sep 17 00:00:00 2001 From: Han Date: Wed, 21 Jun 2023 19:02:57 +0800 Subject: [PATCH] Implement `CurveExt::hash_to_curve` for `{bn256::G1,grumpkin::G1}` (#47) --- .github/workflows/ci.yml | 25 +---- Cargo.toml | 1 + src/bn256/curve.rs | 68 +++++++++++- src/bn256/engine.rs | 2 +- src/bn256/fr.rs | 4 +- src/derive/curve.rs | 5 +- src/grumpkin/curve.rs | 11 ++ src/hash_to_curve.rs | 222 +++++++++++++++++++++++++++++++++++++++ src/lib.rs | 7 +- src/secp256k1/curve.rs | 1 + src/secp256r1/curve.rs | 1 + src/secp256r1/fp.rs | 4 +- src/secp256r1/fq.rs | 14 +-- src/tests/curve.rs | 33 +++++- src/tests/field.rs | 22 ++-- src/tests/mod.rs | 15 +++ 16 files changed, 377 insertions(+), 58 deletions(-) create mode 100644 src/hash_to_curve.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69b699e4..13abb797 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -13,17 +13,11 @@ jobs: strategy: matrix: include: - - rust: 1.63.0 - feature: default - - rust: nightly - feature: asm - + - feature: default + - feature: asm steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 - with: - override: true - toolchain: ${{ matrix.rust }} - name: Build uses: actions-rs/cargo@v1 with: @@ -37,17 +31,11 @@ jobs: strategy: matrix: include: - - rust: 1.63.0 - feature: default - - rust: nightly - feature: asm - + - feature: default + - feature: asm steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 - with: - override: true - toolchain: ${{ matrix.rust }} - name: Test uses: actions-rs/cargo@v1 with: @@ -79,8 +67,6 @@ jobs: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: - override: true - toolchain: nightly components: clippy - name: Run clippy uses: actions-rs/cargo@v1 @@ -96,9 +82,6 @@ jobs: steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 - with: - override: true - toolchain: nightly - name: Bench arithmetic uses: actions-rs/cargo@v1 with: diff --git a/Cargo.toml b/Cargo.toml index 226483e8..0524dbe1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,7 @@ num-traits = "0.2" paste = "1.0.11" serde = { version = "1.0", default-features = false, optional = true } serde_arrays = { version = "0.1.0", optional = true } +blake2b_simd = "1" [features] default = ["reexport", "bits"] diff --git a/src/bn256/curve.rs b/src/bn256/curve.rs index 2a6b9123..3ffb4597 100644 --- a/src/bn256/curve.rs +++ b/src/bn256/curve.rs @@ -10,6 +10,7 @@ use crate::ff::WithSmallOrderMulGroup; use crate::ff::{Field, PrimeField}; use crate::group::Curve; use crate::group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Group, GroupEncoding}; +use crate::hash_to_curve::svdw_hash_to_curve; use crate::{ batch_add, impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, @@ -38,6 +39,7 @@ new_curve_impl!( G1_A, G1_B, "bn256_g1", + |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z), ); new_curve_impl!( @@ -51,6 +53,7 @@ new_curve_impl!( G2_A, G2_B, "bn256_g2", + |_, _| unimplemented!(), ); impl CurveAffineExt for G1Affine { @@ -212,17 +215,76 @@ impl CofactorGroup for G2 { } } +impl G1 { + const SVDW_Z: Fq = Fq::ONE; +} + #[cfg(test)] mod tests { - use crate::arithmetic::CurveEndo; use crate::bn256::{Fr, G1, G2}; use crate::CurveExt; use ff::Field; - use ff::PrimeField; - use ff::WithSmallOrderMulGroup; + use ff::{PrimeField, WithSmallOrderMulGroup}; use rand_core::OsRng; + #[test] + fn test_hash_to_curve() { + crate::tests::curve::hash_to_curve_test::(); + } + + #[test] + fn test_map_to_curve() { + crate::tests::curve::svdw_map_to_curve_test::( + G1::SVDW_Z, + // Precomputed constants taken from https://github.com/ConsenSys/gnark-crypto/blob/441dc0ffe639294b8d09e394f24ba7575577229c/internal/generator/config/bn254.go#L26-L32. + [ + "4", + "10944121435919637611123202872628637544348155578648911831344518947322613104291", + "8815841940592487685674414971303048083897117035520822607866", + "7296080957279758407415468581752425029565437052432607887563012631548408736189", + ], + // List of (u, (Q.x, Q.y)) taken from https://github.com/ConsenSys/gnark-crypto/blob/441dc0ffe639294b8d09e394f24ba7575577229c/ecc/bn254/hash_vectors_test.go#L4-L28 + [ + ( + "0xcb81538a98a2e3580076eed495256611813f6dae9e16d3d4f8de7af0e9833e1", + ( + "0x1bb8810e2ceaf04786d4efd216fc2820ddd9363712efc736ada11049d8af5925", + "0x1efbf8d54c60d865cce08437668ea30f5bf90d287dbd9b5af31da852915e8f11", + ), + ), + ( + "0xba35e127276e9000b33011860904ddee28f1d48ddd3577e2a797ef4a5e62319", + ( + "0xda4a96147df1f35b0f820bd35c6fac3b80e8e320de7c536b1e054667b22c332", + "0x189bd3fbffe4c8740d6543754d95c790e44cd2d162858e3b733d2b8387983bb7", + ), + ), + ( + "0x11852286660cd970e9d7f46f99c7cca2b75554245e91b9b19d537aa6147c28fc", + ( + "0x2ff727cfaaadb3acab713fa22d91f5fddab3ed77948f3ef6233d7ea9b03f4da1", + "0x304080768fd2f87a852155b727f97db84b191e41970506f0326ed4046d1141aa", + ), + ), + ( + "0x174d1c85d8a690a876cc1deba0166d30569fafdb49cb3ed28405bd1c5357a1cc", + ( + "0x11a2eaa8e3e89de056d1b3a288a7f733c8a1282efa41d28e71af065ab245df9b", + "0x60f37c447ac29fd97b9bb83be98ddccf15e34831a9cdf5493b7fede0777ae06", + ), + ), + ( + "0x73b81432b4cf3a8a9076201500d1b94159539f052a6e0928db7f2df74bff672", + ( + "0x27409dccc6ee4ce90e24744fda8d72c0bc64e79766f778da0c1c0ef1c186ea84", + "0x1ac201a542feca15e77f30370da183514dc99d8a0b2c136d64ede35cd0b51dc0", + ), + ), + ], + ); + } + #[test] fn test_curve() { crate::tests::curve::curve_tests::(); diff --git a/src/bn256/engine.rs b/src/bn256/engine.rs index b4da1e0a..8ed8725b 100644 --- a/src/bn256/engine.rs +++ b/src/bn256/engine.rs @@ -62,7 +62,7 @@ pub struct Gt(pub(crate) Fq12); impl std::fmt::Display for Gt { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self) + write!(f, "{self:?}") } } diff --git a/src/bn256/fr.rs b/src/bn256/fr.rs index 24dc55ed..9f2cda19 100644 --- a/src/bn256/fr.rs +++ b/src/bn256/fr.rs @@ -463,8 +463,8 @@ mod test { let mut rng = ark_std::test_rng(); let base = (0..repeat).map(|_| (rng.next_u32() % (1 << 16)) as u64); - let timer = start_timer!(|| format!("generate {} Bn256 scalar field elements", repeat)); - let _res: Vec<_> = base.map(|b| Fr::from(b)).collect(); + let timer = start_timer!(|| format!("generate {repeat} Bn256 scalar field elements")); + let _res: Vec<_> = base.map(Fr::from).collect(); end_timer!(timer); } diff --git a/src/derive/curve.rs b/src/derive/curve.rs index f733340f..f4173683 100644 --- a/src/derive/curve.rs +++ b/src/derive/curve.rs @@ -203,6 +203,7 @@ macro_rules! new_curve_impl { $constant_a:expr, $constant_b:expr, $curve_id:literal, + $hash_to_curve:expr, ) => { macro_rules! impl_compressed { @@ -615,8 +616,8 @@ macro_rules! new_curve_impl { } - fn hash_to_curve<'a>(_: &'a str) -> Box Self + 'a> { - unimplemented!(); + fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box Self + 'a> { + $hash_to_curve($curve_id, domain_prefix) } fn is_on_curve(&self) -> Choice { diff --git a/src/grumpkin/curve.rs b/src/grumpkin/curve.rs index 4f70259f..259b19f1 100644 --- a/src/grumpkin/curve.rs +++ b/src/grumpkin/curve.rs @@ -4,6 +4,7 @@ use crate::group::Curve; use crate::group::{prime::PrimeCurveAffine, Group, GroupEncoding}; use crate::grumpkin::Fq; use crate::grumpkin::Fr; +use crate::hash_to_curve::svdw_hash_to_curve; use crate::{ batch_add, impl_add_binop_specify_output, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, @@ -31,6 +32,7 @@ new_curve_impl!( G1_A, G1_B, "grumpkin_g1", + |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z), ); impl CurveAffineExt for G1Affine { @@ -74,12 +76,21 @@ impl group::cofactor::CofactorGroup for G1 { } } +impl G1 { + const SVDW_Z: Fq = Fq::ONE; +} + #[cfg(test)] mod tests { use crate::grumpkin::{Fr, G1}; use crate::CurveExt; use ff::WithSmallOrderMulGroup; + #[test] + fn test_hash_to_curve() { + crate::tests::curve::hash_to_curve_test::(); + } + #[test] fn test_curve() { crate::tests::curve::curve_tests::(); diff --git a/src/hash_to_curve.rs b/src/hash_to_curve.rs new file mode 100644 index 00000000..4cef7095 --- /dev/null +++ b/src/hash_to_curve.rs @@ -0,0 +1,222 @@ +#![allow(clippy::op_ref)] + +use ff::{Field, FromUniformBytes, PrimeField}; +use pasta_curves::arithmetic::CurveExt; +use static_assertions::const_assert; +use subtle::{ConditionallySelectable, ConstantTimeEq}; + +/// Hashes over a message and writes the output to all of `buf`. +/// Modified from https://github.com/zcash/pasta_curves/blob/7e3fc6a4919f6462a32b79dd226cb2587b7961eb/src/hashtocurve.rs#L11. +fn hash_to_field>( + method: &str, + curve_id: &str, + domain_prefix: &str, + message: &[u8], + buf: &mut [F; 2], +) { + assert!(domain_prefix.len() < 256); + assert!((18 + method.len() + curve_id.len() + domain_prefix.len()) < 256); + + // Assume that the field size is 32 bytes and k is 256, where k is defined in + // . + const CHUNKLEN: usize = 64; + const_assert!(CHUNKLEN * 2 < 256); + + // Input block size of BLAKE2b. + const R_IN_BYTES: usize = 128; + + let personal = [0u8; 16]; + let empty_hasher = blake2b_simd::Params::new() + .hash_length(CHUNKLEN) + .personal(&personal) + .to_state(); + + let b_0 = empty_hasher + .clone() + .update(&[0; R_IN_BYTES]) + .update(message) + .update(&[0, (CHUNKLEN * 2) as u8, 0]) + .update(domain_prefix.as_bytes()) + .update(b"-") + .update(curve_id.as_bytes()) + .update(b"_XMD:BLAKE2b_") + .update(method.as_bytes()) + .update(b"_RO_") + .update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8]) + .finalize(); + + let b_1 = empty_hasher + .clone() + .update(b_0.as_array()) + .update(&[1]) + .update(domain_prefix.as_bytes()) + .update(b"-") + .update(curve_id.as_bytes()) + .update(b"_XMD:BLAKE2b_") + .update(method.as_bytes()) + .update(b"_RO_") + .update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8]) + .finalize(); + + let b_2 = { + let mut empty_hasher = empty_hasher; + for (l, r) in b_0.as_array().iter().zip(b_1.as_array().iter()) { + empty_hasher.update(&[*l ^ *r]); + } + empty_hasher + .update(&[2]) + .update(domain_prefix.as_bytes()) + .update(b"-") + .update(curve_id.as_bytes()) + .update(b"_XMD:BLAKE2b_") + .update(method.as_bytes()) + .update(b"_RO_") + .update(&[(18 + method.len() + curve_id.len() + domain_prefix.len()) as u8]) + .finalize() + }; + + for (big, buf) in [b_1, b_2].iter().zip(buf.iter_mut()) { + let mut little = [0u8; CHUNKLEN]; + little.copy_from_slice(big.as_array()); + little.reverse(); + *buf = F::from_uniform_bytes(&little); + } +} + +#[allow(clippy::too_many_arguments)] +pub(crate) fn svdw_map_to_curve( + u: C::Base, + c1: C::Base, + c2: C::Base, + c3: C::Base, + c4: C::Base, + z: C::Base, +) -> C +where + C: CurveExt, +{ + let one = C::Base::ONE; + let a = C::a(); + let b = C::b(); + + // 1. tv1 = u^2 + let tv1 = u.square(); + // 2. tv1 = tv1 * c1 + let tv1 = tv1 * c1; + // 3. tv2 = 1 + tv1 + let tv2 = one + tv1; + // 4. tv1 = 1 - tv1 + let tv1 = one - tv1; + // 5. tv3 = tv1 * tv2 + let tv3 = tv1 * tv2; + // 6. tv3 = inv0(tv3) + let tv3 = tv3.invert().unwrap_or(C::Base::ZERO); + // 7. tv4 = u * tv1 + let tv4 = u * tv1; + // 8. tv4 = tv4 * tv3 + let tv4 = tv4 * tv3; + // 9. tv4 = tv4 * c3 + let tv4 = tv4 * c3; + // 10. x1 = c2 - tv4 + let x1 = c2 - tv4; + // 11. gx1 = x1^2 + let gx1 = x1.square(); + // 12. gx1 = gx1 + A + let gx1 = gx1 + a; + // 13. gx1 = gx1 * x1 + let gx1 = gx1 * x1; + // 14. gx1 = gx1 + B + let gx1 = gx1 + b; + // 15. e1 = is_square(gx1) + let e1 = gx1.sqrt().is_some(); + // 16. x2 = c2 + tv4 + let x2 = c2 + tv4; + // 17. gx2 = x2^2 + let gx2 = x2.square(); + // 18. gx2 = gx2 + A + let gx2 = gx2 + a; + // 19. gx2 = gx2 * x2 + let gx2 = gx2 * x2; + // 20. gx2 = gx2 + B + let gx2 = gx2 + b; + // 21. e2 = is_square(gx2) AND NOT e1 # Avoid short-circuit logic ops + let e2 = gx2.sqrt().is_some() & (!e1); + // 22. x3 = tv2^2 + let x3 = tv2.square(); + // 23. x3 = x3 * tv3 + let x3 = x3 * tv3; + // 24. x3 = x3^2 + let x3 = x3.square(); + // 25. x3 = x3 * c4 + let x3 = x3 * c4; + // 26. x3 = x3 + Z + let x3 = x3 + z; + // 27. x = CMOV(x3, x1, e1) # x = x1 if gx1 is square, else x = x3 + let x = C::Base::conditional_select(&x3, &x1, e1); + // 28. x = CMOV(x, x2, e2) # x = x2 if gx2 is square and gx1 is not + let x = C::Base::conditional_select(&x, &x2, e2); + // 29. gx = x^2 + let gx = x.square(); + // 30. gx = gx + A + let gx = gx + a; + // 31. gx = gx * x + let gx = gx * x; + // 32. gx = gx + B + let gx = gx + b; + // 33. y = sqrt(gx) + let y = gx.sqrt().unwrap(); + // 34. e3 = sgn0(u) == sgn0(y) + let e3 = u.is_odd().ct_eq(&y.is_odd()); + // 35. y = CMOV(-y, y, e3) # Select correct sign of y + let y = C::Base::conditional_select(&-y, &y, e3); + // 36. return (x, y) + C::new_jacobian(x, y, one).unwrap() +} + +/// Implementation of https://www.ietf.org/id/draft-irtf-cfrg-hash-to-curve-16.html#name-shallue-van-de-woestijne-met +#[allow(clippy::type_complexity)] +pub(crate) fn svdw_hash_to_curve<'a, C>( + curve_id: &'static str, + domain_prefix: &'a str, + z: C::Base, +) -> Box C + 'a> +where + C: CurveExt, + C::Base: FromUniformBytes<64>, +{ + let [c1, c2, c3, c4] = svdw_precomputed_constants::(z); + + Box::new(move |message| { + let mut us = [C::Base::ZERO; 2]; + hash_to_field("SVDW", curve_id, domain_prefix, message, &mut us); + + let [q0, q1]: [C; 2] = us.map(|u| svdw_map_to_curve(u, c1, c2, c3, c4, z)); + + let r = q0 + &q1; + debug_assert!(bool::from(r.is_on_curve())); + r + }) +} + +pub(crate) fn svdw_precomputed_constants(z: C::Base) -> [C::Base; 4] { + let a = C::a(); + let b = C::b(); + let one = C::Base::ONE; + let three = one + one + one; + let four = three + one; + let tmp = three * z.square() + four * a; + + // 1. c1 = g(Z) + let c1 = (z.square() + a) * z + b; + // 2. c2 = -Z / 2 + let c2 = -z * C::Base::TWO_INV; + // 3. c3 = sqrt(-g(Z) * (3 * Z^2 + 4 * A)) # sgn0(c3) MUST equal 0 + let c3 = { + let c3 = (-c1 * tmp).sqrt().unwrap(); + C::Base::conditional_select(&c3, &-c3, c3.is_odd()) + }; + // 4. c4 = -4 * g(Z) / (3 * Z^2 + 4 * A) + let c4 = -four * c1 * tmp.invert().unwrap(); + + [c1, c2, c3, c4] +} diff --git a/src/lib.rs b/src/lib.rs index 53a3f251..63d76a7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,13 @@ -#![cfg_attr(feature = "asm", feature(asm_const))] - mod arithmetic; +pub mod hash_to_curve; +pub mod pairing; +pub mod serde; pub mod bn256; pub mod grumpkin; -pub mod pairing; pub mod pasta; pub mod secp256k1; pub mod secp256r1; -pub mod serde; #[macro_use] mod derive; diff --git a/src/secp256k1/curve.rs b/src/secp256k1/curve.rs index 2021f19a..5ca03d6a 100644 --- a/src/secp256k1/curve.rs +++ b/src/secp256k1/curve.rs @@ -64,6 +64,7 @@ new_curve_impl!( SECP_A, SECP_B, "secp256k1", + |_, _| unimplemented!(), ); impl CurveAffineExt for Secp256k1Affine { diff --git a/src/secp256r1/curve.rs b/src/secp256r1/curve.rs index c4c4422b..77a87a4f 100644 --- a/src/secp256r1/curve.rs +++ b/src/secp256r1/curve.rs @@ -75,6 +75,7 @@ new_curve_impl!( SECP_A, SECP_B, "secp256r1", + |_, _| unimplemented!(), ); impl CurveAffineExt for Secp256r1Affine { diff --git a/src/secp256r1/fp.rs b/src/secp256r1/fp.rs index 43ebfc6c..d351b64d 100644 --- a/src/secp256r1/fp.rs +++ b/src/secp256r1/fp.rs @@ -187,7 +187,7 @@ impl ff::Field for Fp { /// Computes the square root of this element, if it exists. fn sqrt(&self) -> CtOption { - let tmp = self.pow(&[ + let tmp = self.pow([ 0x0000000000000000, 0x0000000040000000, 0x4000000000000000, @@ -200,7 +200,7 @@ impl ff::Field for Fp { /// Computes the multiplicative inverse of this element, /// failing if the element is zero. fn invert(&self) -> CtOption { - let tmp = self.pow_vartime(&[ + let tmp = self.pow_vartime([ 0xfffffffffffffffd, 0x00000000ffffffff, 0x0000000000000000, diff --git a/src/secp256r1/fq.rs b/src/secp256r1/fq.rs index d628a96e..e28c3fe6 100644 --- a/src/secp256r1/fq.rs +++ b/src/secp256r1/fq.rs @@ -177,7 +177,7 @@ impl ff::Field for Fq { /// Computes the multiplicative inverse of this element, /// failing if the element is zero. fn invert(&self) -> CtOption { - let tmp = self.pow_vartime(&[ + let tmp = self.pow_vartime([ 0xf3b9cac2fc63254f, 0xbce6faada7179e84, 0xffffffffffffffff, @@ -214,7 +214,7 @@ impl ff::Field for Fq { 0x7fffffff8000000, ]; - ff::helpers::sqrt_tonelli_shanks(self, &tm1d2) + ff::helpers::sqrt_tonelli_shanks(self, tm1d2) } fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { @@ -344,18 +344,12 @@ mod test { #[test] fn test_delta() { - assert_eq!( - Fq::DELTA, - Fq::MULTIPLICATIVE_GENERATOR.pow(&[1u64 << Fq::S, 0, 0, 0]) - ); + assert_eq!(Fq::DELTA, Fq::MULTIPLICATIVE_GENERATOR.pow([1u64 << Fq::S])); } #[test] fn test_root_of_unity() { - assert_eq!( - Fq::ROOT_OF_UNITY.pow_vartime(&[1 << Fq::S, 0, 0, 0]), - Fq::one() - ); + assert_eq!(Fq::ROOT_OF_UNITY.pow_vartime([1 << Fq::S]), Fq::one()); } #[test] diff --git a/src/tests/curve.rs b/src/tests/curve.rs index 3a22c588..442868cc 100644 --- a/src/tests/curve.rs +++ b/src/tests/curve.rs @@ -2,9 +2,11 @@ use crate::ff::Field; use crate::group::prime::PrimeCurveAffine; +use crate::tests::fe_from_str; use crate::{group::GroupEncoding, serde::SerdeObject}; -use crate::{CurveAffine, CurveExt}; -use rand_core::OsRng; +use crate::{hash_to_curve, CurveAffine, CurveExt}; +use rand_core::{OsRng, RngCore}; +use std::iter; #[cfg(feature = "derive_serde")] use serde::{Deserialize, Serialize}; @@ -314,3 +316,30 @@ fn multiplication() { assert_eq!(t0, t1); } } + +pub fn hash_to_curve_test() { + let hasher = G::hash_to_curve("test"); + let mut rng = OsRng; + for _ in 0..1000 { + let message = iter::repeat_with(|| rng.next_u32().to_be_bytes()) + .take(32) + .flatten() + .collect::>(); + assert!(bool::from(hasher(&message).is_on_curve())); + } +} + +pub fn svdw_map_to_curve_test( + z: G::Base, + precomputed_constants: [&'static str; 4], + test_vector: impl IntoIterator, +) { + let [c1, c2, c3, c4] = hash_to_curve::svdw_precomputed_constants::(z); + assert_eq!([c1, c2, c3, c4], precomputed_constants.map(fe_from_str)); + for (u, (x, y)) in test_vector.into_iter() { + let u = fe_from_str(u); + let expected = G::AffineExt::from_xy(fe_from_str(x), fe_from_str(y)).unwrap(); + let output = hash_to_curve::svdw_map_to_curve::(u, c1, c2, c3, c4, z).to_affine(); + assert_eq!(output, expected); + } +} diff --git a/src/tests/field.rs b/src/tests/field.rs index 67ff6952..a85b3f0e 100644 --- a/src/tests/field.rs +++ b/src/tests/field.rs @@ -48,7 +48,7 @@ pub fn random_field_tests(type_name: String) { } fn random_multiplication_tests(mut rng: R, type_name: String) { - let _message = format!("multiplication {}", type_name); + let _message = format!("multiplication {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let a = F::random(&mut rng); @@ -74,7 +74,7 @@ fn random_multiplication_tests(mut rng: R, type_name: Stri } fn random_addition_tests(mut rng: R, type_name: String) { - let _message = format!("addition {}", type_name); + let _message = format!("addition {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let a = F::random(&mut rng); @@ -100,7 +100,7 @@ fn random_addition_tests(mut rng: R, type_name: String) { } fn random_subtraction_tests(mut rng: R, type_name: String) { - let _message = format!("subtraction {}", type_name); + let _message = format!("subtraction {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let a = F::random(&mut rng); @@ -121,7 +121,7 @@ fn random_subtraction_tests(mut rng: R, type_name: String) } fn random_negation_tests(mut rng: R, type_name: String) { - let _message = format!("negation {}", type_name); + let _message = format!("negation {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let a = F::random(&mut rng); @@ -135,7 +135,7 @@ fn random_negation_tests(mut rng: R, type_name: String) { } fn random_doubling_tests(mut rng: R, type_name: String) { - let _message = format!("doubling {}", type_name); + let _message = format!("doubling {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let mut a = F::random(&mut rng); @@ -149,7 +149,7 @@ fn random_doubling_tests(mut rng: R, type_name: String) { } fn random_squaring_tests(mut rng: R, type_name: String) { - let _message = format!("squaring {}", type_name); + let _message = format!("squaring {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let mut a = F::random(&mut rng); @@ -165,7 +165,7 @@ fn random_squaring_tests(mut rng: R, type_name: String) { fn random_inversion_tests(mut rng: R, type_name: String) { assert!(bool::from(F::ZERO.invert().is_none())); - let _message = format!("inversion {}", type_name); + let _message = format!("inversion {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let mut a = F::random(&mut rng); @@ -178,7 +178,7 @@ fn random_inversion_tests(mut rng: R, type_name: String) { } fn random_expansion_tests(mut rng: R, type_name: String) { - let _message = format!("expansion {}", type_name); + let _message = format!("expansion {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { // Compare (a + b)(c + d) and (a*c + b*c + a*d + b*d) @@ -218,7 +218,7 @@ pub fn random_bits_tests(type_name: String) { 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); - let _message = format!("to_le_bits {}", type_name); + let _message = format!("to_le_bits {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let a = F::random(&mut rng); @@ -236,7 +236,7 @@ pub fn random_serialization_test(type_name: String) { 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); - let _message = format!("serialization with SerdeObject {}", type_name); + let _message = format!("serialization with SerdeObject {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let a = F::random(&mut rng); @@ -260,7 +260,7 @@ where 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, ]); - let _message = format!("serialization with serde {}", type_name); + let _message = format!("serialization with serde {type_name}"); let start = start_timer!(|| _message); for _ in 0..1000000 { let a = F::random(&mut rng); diff --git a/src/tests/mod.rs b/src/tests/mod.rs index f773c8d7..5c6cd819 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,2 +1,17 @@ +use ff::PrimeField; +use num_bigint::BigUint; +use num_traits::Num; +use std::borrow::Cow; + pub mod curve; pub mod field; + +pub(crate) fn fe_from_str(string: impl AsRef) -> F { + let string = string.as_ref(); + let oct = if let Some(hex) = string.strip_prefix("0x") { + Cow::Owned(BigUint::from_str_radix(hex, 16).unwrap().to_string()) + } else { + Cow::Borrowed(string) + }; + F::from_str_vartime(&oct).unwrap() +}