From 148657787d510fb9588d09eae63997375a1205c6 Mon Sep 17 00:00:00 2001 From: han0110 Date: Tue, 13 Jun 2023 02:56:08 +0000 Subject: [PATCH] refactor: add `svdw_map_to_curve_test` helper in mod `tests` --- src/bn256/curve.rs | 156 +++++++++++++----------------------------- src/bn256/engine.rs | 2 +- src/grumpkin/curve.rs | 8 ++- src/hash_to_curve.rs | 45 ++++++------ src/tests/curve.rs | 18 ++++- src/tests/mod.rs | 15 ++++ 6 files changed, 108 insertions(+), 136 deletions(-) diff --git a/src/bn256/curve.rs b/src/bn256/curve.rs index da53ea90..9636d998 100644 --- a/src/bn256/curve.rs +++ b/src/bn256/curve.rs @@ -10,7 +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_map_to_curve; +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,7 +38,7 @@ new_curve_impl!( (G1_GENERATOR_X,G1_GENERATOR_Y), G1_B, "bn256_g1", - |curve_id, domain_prefix| svdw_map_to_curve(curve_id, domain_prefix, Fq::ONE), + |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z), ); new_curve_impl!( @@ -207,20 +207,17 @@ impl CofactorGroup for G2 { } } +impl G1 { + const SVDW_Z: Fq = Fq::ONE; +} + #[cfg(test)] mod tests { - use crate::arithmetic::CurveEndo; - use crate::bn256::{Fq, Fr, G1Affine, G1, G2}; - use crate::hash_to_curve::map_to_curve; - use crate::serde::SerdeObject; + use crate::bn256::{Fr, G1, G2}; use crate::CurveExt; use ff::Field; use ff::{PrimeField, WithSmallOrderMulGroup}; - use group::Curve; - use num_bigint::BigUint; - use num_traits::Num; - use pasta_curves::arithmetic::CurveAffine; use rand_core::OsRng; #[test] @@ -229,116 +226,55 @@ mod tests { } #[test] - fn test_map_to_curve_bn256() { - // from https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/bn254/hash_vectors_test.go - let encode_tests = vec![ - ( - //u - "0xcb81538a98a2e3580076eed495256611813f6dae9e16d3d4f8de7af0e9833e1", - // Q + 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 + [ ( - "0x1bb8810e2ceaf04786d4efd216fc2820ddd9363712efc736ada11049d8af5925", - "0x1efbf8d54c60d865cce08437668ea30f5bf90d287dbd9b5af31da852915e8f11", + "0xcb81538a98a2e3580076eed495256611813f6dae9e16d3d4f8de7af0e9833e1", + ( + "0x1bb8810e2ceaf04786d4efd216fc2820ddd9363712efc736ada11049d8af5925", + "0x1efbf8d54c60d865cce08437668ea30f5bf90d287dbd9b5af31da852915e8f11", + ), ), - ), - ( - //u - "0xba35e127276e9000b33011860904ddee28f1d48ddd3577e2a797ef4a5e62319", - // Q ( - "0xda4a96147df1f35b0f820bd35c6fac3b80e8e320de7c536b1e054667b22c332", - "0x189bd3fbffe4c8740d6543754d95c790e44cd2d162858e3b733d2b8387983bb7", + "0xba35e127276e9000b33011860904ddee28f1d48ddd3577e2a797ef4a5e62319", + ( + "0xda4a96147df1f35b0f820bd35c6fac3b80e8e320de7c536b1e054667b22c332", + "0x189bd3fbffe4c8740d6543754d95c790e44cd2d162858e3b733d2b8387983bb7", + ), ), - ), - ( - //u - "0x11852286660cd970e9d7f46f99c7cca2b75554245e91b9b19d537aa6147c28fc", - // Q ( - "0x2ff727cfaaadb3acab713fa22d91f5fddab3ed77948f3ef6233d7ea9b03f4da1", - "0x304080768fd2f87a852155b727f97db84b191e41970506f0326ed4046d1141aa", + "0x11852286660cd970e9d7f46f99c7cca2b75554245e91b9b19d537aa6147c28fc", + ( + "0x2ff727cfaaadb3acab713fa22d91f5fddab3ed77948f3ef6233d7ea9b03f4da1", + "0x304080768fd2f87a852155b727f97db84b191e41970506f0326ed4046d1141aa", + ), ), - ), - ( - //u - "0x174d1c85d8a690a876cc1deba0166d30569fafdb49cb3ed28405bd1c5357a1cc", - // Q ( - "0x11a2eaa8e3e89de056d1b3a288a7f733c8a1282efa41d28e71af065ab245df9b", - "0x60f37c447ac29fd97b9bb83be98ddccf15e34831a9cdf5493b7fede0777ae06", + "0x174d1c85d8a690a876cc1deba0166d30569fafdb49cb3ed28405bd1c5357a1cc", + ( + "0x11a2eaa8e3e89de056d1b3a288a7f733c8a1282efa41d28e71af065ab245df9b", + "0x60f37c447ac29fd97b9bb83be98ddccf15e34831a9cdf5493b7fede0777ae06", + ), ), - ), - ( - //u - "0x73b81432b4cf3a8a9076201500d1b94159539f052a6e0928db7f2df74bff672", - // Q ( - "0x27409dccc6ee4ce90e24744fda8d72c0bc64e79766f778da0c1c0ef1c186ea84", - "0x1ac201a542feca15e77f30370da183514dc99d8a0b2c136d64ede35cd0b51dc0", + "0x73b81432b4cf3a8a9076201500d1b94159539f052a6e0928db7f2df74bff672", + ( + "0x27409dccc6ee4ce90e24744fda8d72c0bc64e79766f778da0c1c0ef1c186ea84", + "0x1ac201a542feca15e77f30370da183514dc99d8a0b2c136d64ede35cd0b51dc0", + ), ), - ), - ]; - - // inspired by TestMapToCurve1 in - // https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/bn254/hash_to_g1_test.go - for (u, pt_q) in encode_tests { - let big_u = BigUint::from_str_radix(&u.strip_prefix("0x").unwrap(), 16) - .unwrap() - .to_string(); - let u = Fq::from_str_vartime(&big_u).unwrap(); - - let to_fq = |arg: [u64; 4]| { - let arg_bytes: [u8; 32] = unsafe { ::std::mem::transmute(arg) }; - Fq::from_raw_bytes_unchecked(&arg_bytes) - }; - - // from https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/bn254/hash_to_g1.go - let z = to_fq([ - 15230403791020821917, - 754611498739239741, - 7381016538464732716, - 1011752739694698287, - ]); - let c1 = to_fq([ - 1248766071674976557, - 10548065924188627562, - 16242874202584236114, - 560012691975822483, - ]); - let c2 = to_fq([ - 12997850613838968789, - 14304628359724097447, - 2950087706404981016, - 1237622763554136189, - ]); - let c3 = to_fq([ - 8972444824031832946, - 5898165201680709844, - 10690697896010808308, - 824354360198587078, - ]); - let c4 = to_fq([ - 12077013577332951089, - 1872782865047492001, - 13514471836495169457, - 415649166299893576, - ]); - - let g: G1 = map_to_curve(u, &c1, c2, &c3, &c4, &G1::a(), &G1::b(), &z); - let g_aff = g.to_affine(); - - let big_x = BigUint::from_str_radix(&pt_q.0.strip_prefix("0x").unwrap(), 16) - .unwrap() - .to_string(); - let big_y = BigUint::from_str_radix(&pt_q.1.strip_prefix("0x").unwrap(), 16) - .unwrap() - .to_string(); - let x = Fq::from_str_vartime(&big_x).unwrap(); - let y = Fq::from_str_vartime(&big_y).unwrap(); - let expected_g = G1Affine::from_xy(x, y).unwrap(); - - assert_eq!(g_aff, expected_g); - } + ], + ); } #[test] 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/grumpkin/curve.rs b/src/grumpkin/curve.rs index 60c5bbd9..8ba58db3 100644 --- a/src/grumpkin/curve.rs +++ b/src/grumpkin/curve.rs @@ -4,7 +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_map_to_curve; +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,7 +31,7 @@ new_curve_impl!( (G1_GENERATOR_X, G1_GENERATOR_Y), G1_B, "grumpkin_g1", - |curve_id, domain_prefix| svdw_map_to_curve(curve_id, domain_prefix, Fq::ONE), + |curve_id, domain_prefix| svdw_hash_to_curve(curve_id, domain_prefix, G1::SVDW_Z), ); impl CurveAffineExt for G1Affine { @@ -74,6 +74,10 @@ impl group::cofactor::CofactorGroup for G1 { } } +impl G1 { + const SVDW_Z: Fq = Fq::ONE; +} + #[cfg(test)] mod tests { use crate::grumpkin::{Fr, G1}; diff --git a/src/hash_to_curve.rs b/src/hash_to_curve.rs index 9339315c..bf90027c 100644 --- a/src/hash_to_curve.rs +++ b/src/hash_to_curve.rs @@ -82,21 +82,20 @@ fn hash_to_field>( } #[allow(clippy::too_many_arguments)] -pub(crate) fn map_to_curve( +pub(crate) fn svdw_map_to_curve( u: C::Base, - c1: &C::Base, + c1: C::Base, c2: C::Base, - c3: &C::Base, - c4: &C::Base, - a: &C::Base, - b: &C::Base, - z: &C::Base, + c3: C::Base, + c4: C::Base, + z: C::Base, ) -> C where C: CurveExt, - C::Base: FromUniformBytes<64>, { let one = C::Base::ONE; + let a = C::a(); + let b = C::b(); // 1. tv1 = u^2 let tv1 = u.square(); @@ -174,7 +173,7 @@ where /// 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_map_to_curve<'a, C>( +pub(crate) fn svdw_hash_to_curve<'a, C>( curve_id: &'static str, domain_prefix: &'a str, z: C::Base, @@ -183,14 +182,25 @@ 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)); + q0 + &q1 + }) +} + +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 a = C::a(); - let b = C::b(); let tmp = three * z.square() + four * a; - // Precomputed constants: // 1. c1 = g(Z) let c1 = (z.square() + a) * z + b; // 2. c2 = -Z / 2 @@ -203,14 +213,5 @@ where // 4. c4 = -4 * g(Z) / (3 * Z^2 + 4 * A) let c4 = -four * c1 * tmp.invert().unwrap(); - 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| map_to_curve(u, &c1, c2, &c3, &c4, &a, &b, &z)); - - let r = q0 + &q1; - debug_assert!(bool::from(r.is_on_curve())); - r - }) + [c1, c2, c3, c4] } diff --git a/src/tests/curve.rs b/src/tests/curve.rs index 2573dc19..442868cc 100644 --- a/src/tests/curve.rs +++ b/src/tests/curve.rs @@ -2,8 +2,9 @@ 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 crate::{hash_to_curve, CurveAffine, CurveExt}; use rand_core::{OsRng, RngCore}; use std::iter; @@ -327,3 +328,18 @@ pub fn hash_to_curve_test() { 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/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() +}