Skip to content

Commit

Permalink
refactor: add svdw_map_to_curve_test helper in mod tests
Browse files Browse the repository at this point in the history
  • Loading branch information
han0110 committed Jun 13, 2023
1 parent 1df1839 commit 1486577
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 136 deletions.
156 changes: 46 additions & 110 deletions src/bn256/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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!(
Expand Down Expand Up @@ -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]
Expand All @@ -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>(
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]
Expand Down
2 changes: 1 addition & 1 deletion src/bn256/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:?}")
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/grumpkin/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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 {
Expand Down Expand Up @@ -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};
Expand Down
45 changes: 23 additions & 22 deletions src/hash_to_curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,21 +82,20 @@ fn hash_to_field<F: FromUniformBytes<64>>(
}

#[allow(clippy::too_many_arguments)]
pub(crate) fn map_to_curve<C>(
pub(crate) fn svdw_map_to_curve<C>(
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();
Expand Down Expand Up @@ -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,
Expand All @@ -183,14 +182,25 @@ where
C: CurveExt,
C::Base: FromUniformBytes<64>,
{
let [c1, c2, c3, c4] = svdw_precomputed_constants::<C>(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<C: CurveExt>(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
Expand All @@ -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]
}
18 changes: 17 additions & 1 deletion src/tests/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -327,3 +328,18 @@ pub fn hash_to_curve_test<G: CurveExt>() {
assert!(bool::from(hasher(&message).is_on_curve()));
}
}

pub fn svdw_map_to_curve_test<G: CurveExt>(
z: G::Base,
precomputed_constants: [&'static str; 4],
test_vector: impl IntoIterator<Item = (&'static str, (&'static str, &'static str))>,
) {
let [c1, c2, c3, c4] = hash_to_curve::svdw_precomputed_constants::<G>(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::<G>(u, c1, c2, c3, c4, z).to_affine();
assert_eq!(output, expected);
}
}
15 changes: 15 additions & 0 deletions src/tests/mod.rs
Original file line number Diff line number Diff line change
@@ -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<F: PrimeField>(string: impl AsRef<str>) -> 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()
}

0 comments on commit 1486577

Please sign in to comment.