Skip to content

Commit

Permalink
improve: add some macros to generate big testing suite of curves (#129)
Browse files Browse the repository at this point in the history
* refactor: move tests into "tests" module

* improve: add edge cases(ONE and ZERO tests) to field testing suite

* feat: add some macros for curve tests (0)

* feat: add the "curve_testing_suite" macro

* feat: add "test_endo_consistency" to "curve_testing_suite" macro

* refactor: small refactoring in "secp256k1" curve tests

* chore: roll back useless refactorings

* feat: add basic "field_testing_suite" macro

* fix: use the field testing macro for "secp256k1" & "secp256r1"

* fix: replace curve test functions with macros

* fix: use the exported macro for curve testing

* fix: add missing attr to "random_serde_test" macro

* fix: fix the small error in "field_testing_suite" macro

* feat: add "endo_consistency" macro branch

* feat: add the "endo" macro branch

* feat: add the "ecdsa_example" macro branch

* fix: add type casting in "endo" macro branch

* feat: add the "map_to_curve" macro branch

* feat: add the "hash_to_curve" macro branch

* chore: roll back the field testing refactorings

* chore: use better naming for macro

* fix: update the "endo" testing macro

* chore: remove the unnecessary "#[cfg(test)]" attrs

* chore: remove duplicates & add comments

* feat: add the macro to test the curve constants/params

* chore: remove the leftover(println)
  • Loading branch information
duguorong009 authored Jan 23, 2024
1 parent 219b3f5 commit 53dd906
Show file tree
Hide file tree
Showing 7 changed files with 639 additions and 695 deletions.
112 changes: 44 additions & 68 deletions src/bn256/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,23 +199,27 @@ impl G1 {
}

#[cfg(test)]
mod tests {
use crate::arithmetic::CurveEndo;
use crate::bn256::{Fr, G1, G2};
use crate::CurveExt;
use ff::Field;
use ff::{PrimeField, WithSmallOrderMulGroup};
use rand_core::OsRng;

#[test]
fn test_hash_to_curve() {
crate::tests::curve::hash_to_curve_test::<G1>();
}

#[test]
fn test_map_to_curve() {
crate::tests::curve::svdw_map_to_curve_test::<G1>(
G1::SVDW_Z,
mod test {
use super::*;
crate::curve_testing_suite!(G1, G2);
crate::curve_testing_suite!(G1, "hash_to_curve");
crate::curve_testing_suite!(G1, "endo_consistency");
crate::curve_testing_suite!(
G1,
"endo",
// Optional `z_other` param. `z_other` is 3-roots of unity, similar to `ZETA`.
// Reference: https://github.com/privacy-scaling-explorations/halo2curves/blob/main/src/bn256/fr.rs#L145-L151
[
0x8b17ea66b99c90dd,
0x5bfc41088d8daaa7,
0xb3c4d79d41a91758,
0x00,
]
);
crate::curve_testing_suite!(
G1,
"svdw_map_to_curve",
(
// Precomputed constants taken from https://github.com/ConsenSys/gnark-crypto/blob/441dc0ffe639294b8d09e394f24ba7575577229c/internal/generator/config/bn254.go#L26-L32.
[
"4",
Expand Down Expand Up @@ -260,55 +264,27 @@ mod tests {
"0x1ac201a542feca15e77f30370da183514dc99d8a0b2c136d64ede35cd0b51dc0",
),
),
],
);
}

#[test]
fn test_curve() {
crate::tests::curve::curve_tests::<G1>();
crate::tests::curve::curve_tests::<G2>();
}

#[test]
fn test_endo() {
let z_impl = Fr::ZETA;
let z_other = Fr::from_raw([
0x8b17ea66b99c90dd,
0x5bfc41088d8daaa7,
0xb3c4d79d41a91758,
0x00,
]);
assert_eq!(z_impl * z_impl + z_impl, -Fr::ONE);
assert_eq!(z_other * z_other + z_other, -Fr::ONE);

let g = G1::generator();
assert_eq!(g * Fr::ZETA, g.endo());
let g = G2::generator();
assert_eq!(g * Fr::ZETA, g.endo());
for _ in 0..100000 {
let k = Fr::random(OsRng);
let (k1, k1_neg, k2, k2_neg) = G1::decompose_scalar(&k);
if k1_neg & k2_neg {
assert_eq!(k, -Fr::from_u128(k1) + Fr::ZETA * Fr::from_u128(k2))
} else if k1_neg {
assert_eq!(k, -Fr::from_u128(k1) - Fr::ZETA * Fr::from_u128(k2))
} else if k2_neg {
assert_eq!(k, Fr::from_u128(k1) + Fr::ZETA * Fr::from_u128(k2))
} else {
assert_eq!(k, Fr::from_u128(k1) - Fr::ZETA * Fr::from_u128(k2))
}
}
}

#[test]
fn test_serialization() {
crate::tests::curve::random_serialization_test::<G1>();
crate::tests::curve::random_serialization_test::<G2>();
#[cfg(feature = "derive_serde")]
{
crate::tests::curve::random_serde_test::<G1>();
crate::tests::curve::random_serde_test::<G2>();
}
}
]
)
);
crate::curve_testing_suite!(
G1,
"constants",
Fq::MODULUS,
G1_A,
G1_B,
G1_GENERATOR_X,
G1_GENERATOR_Y,
Fr::MODULUS
);
crate::curve_testing_suite!(
G2,
"constants",
Fq2::MODULUS,
G2_A,
G2_B,
G2_GENERATOR_X,
G2_GENERATOR_Y,
Fr::MODULUS
);
}
69 changes: 15 additions & 54 deletions src/grumpkin/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,58 +90,19 @@ impl G1 {
}

#[cfg(test)]
mod tests {
use crate::arithmetic::CurveEndo;
use crate::grumpkin::{Fr, G1};
use crate::CurveExt;
use ff::{Field, PrimeField, WithSmallOrderMulGroup};
use rand_core::OsRng;

#[test]
fn test_hash_to_curve() {
crate::tests::curve::hash_to_curve_test::<G1>();
}

#[test]
fn test_curve() {
crate::tests::curve::curve_tests::<G1>();
}

#[test]
fn test_endo() {
let z_impl = Fr::ZETA;
let z_other = Fr::from_raw([
0xe4bd44e5607cfd48,
0xc28f069fbb966e3d,
0x5e6dd9e7e0acccb0,
0x30644e72e131a029,
]);

assert_eq!(z_impl * z_impl + z_impl, -Fr::ONE);
assert_eq!(z_other * z_other + z_other, -Fr::ONE);

let g = G1::generator();
assert_eq!(g * Fr::ZETA, g.endo());

for _ in 0..100000 {
let k = Fr::random(OsRng);
let (k1, k1_neg, k2, k2_neg) = G1::decompose_scalar(&k);
if k1_neg & k2_neg {
assert_eq!(k, -Fr::from_u128(k1) + Fr::ZETA * Fr::from_u128(k2))
} else if k1_neg {
assert_eq!(k, -Fr::from_u128(k1) - Fr::ZETA * Fr::from_u128(k2))
} else if k2_neg {
assert_eq!(k, Fr::from_u128(k1) + Fr::ZETA * Fr::from_u128(k2))
} else {
assert_eq!(k, Fr::from_u128(k1) - Fr::ZETA * Fr::from_u128(k2))
}
}
}

#[test]
fn test_serialization() {
crate::tests::curve::random_serialization_test::<G1>();
#[cfg(feature = "derive_serde")]
crate::tests::curve::random_serde_test::<G1>();
}
mod test {
use super::*;
crate::curve_testing_suite!(G1);
crate::curve_testing_suite!(G1, "endo_consistency");
crate::curve_testing_suite!(G1, "endo");
crate::curve_testing_suite!(
G1,
"constants",
Fq::MODULUS,
G1_A,
G1_B,
G1_GENERATOR_X,
G1_GENERATOR_Y,
Fr::MODULUS
);
}
78 changes: 36 additions & 42 deletions src/pluto_eris/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -242,46 +242,40 @@ new_curve_impl!(
|_, _| unimplemented!(),
);

#[test]
fn test_curve_pluto() {
crate::tests::curve::curve_tests::<G1>();
}
#[test]
fn test_curve_eris() {
crate::tests::curve::curve_tests::<Eris>();
}
#[test]
fn test_curve_triton() {
crate::tests::curve::curve_tests::<G2>();
}

#[test]
fn test_serialization() {
crate::tests::curve::random_serialization_test::<G1>();
crate::tests::curve::random_serialization_test::<Eris>();
crate::tests::curve::random_serialization_test::<G2>();
#[cfg(feature = "derive_serde")]
crate::tests::curve::random_serde_test::<G1>();
#[cfg(feature = "derive_serde")]
crate::tests::curve::random_serde_test::<Eris>();
#[cfg(feature = "derive_serde")]
crate::tests::curve::random_serde_test::<G2>();
}

#[test]
fn test_hash_to_curve() {
crate::tests::curve::hash_to_curve_test::<G1>();
crate::tests::curve::hash_to_curve_test::<Eris>();
}

#[test]
fn test_endo_consistency() {
let g = Eris::generator();
assert_eq!(g * Fp::ZETA, g.endo());

let g = G1::generator();
assert_eq!(g * Fq::ZETA, g.endo());

let g = G2::generator();
assert_eq!(g * Fq::ZETA, g.endo());
#[cfg(test)]
mod test {
use super::*;
crate::curve_testing_suite!(G1, Eris, G2);
crate::curve_testing_suite!(G1, Eris, "hash_to_curve");
crate::curve_testing_suite!(G1, Eris, "endo_consistency");
crate::curve_testing_suite!(
G1,
"constants",
Fp::MODULUS,
PLUTO_A,
PLUTO_B,
G1_GENERATOR_X,
G1_GENERATOR_Y,
Fq::MODULUS
);
crate::curve_testing_suite!(
Eris,
"constants",
Fq::MODULUS,
ERIS_A,
ERIS_B,
ERIS_GENERATOR_X,
ERIS_GENERATOR_Y,
Fp::MODULUS
);
crate::curve_testing_suite!(
G2,
"constants",
Fp2::MODULUS,
TRITON_A,
TRITON_B,
G2_GENERATOR_X,
G2_GENERATOR_Y,
Fq::MODULUS
);
}
98 changes: 14 additions & 84 deletions src/secp256k1/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,89 +269,19 @@ pub(crate) fn iso_map_secp256k1(rp: IsoSecp256k1) -> Secp256k1 {
}

#[cfg(test)]
mod tests {
mod test {
use super::*;

#[test]
fn test_curve() {
crate::tests::curve::curve_tests::<Secp256k1>();
}

#[test]
fn test_hash_to_curve() {
crate::tests::curve::hash_to_curve_test::<Secp256k1>();
}

#[test]
fn test_serialization() {
crate::tests::curve::random_serialization_test::<Secp256k1>();
#[cfg(feature = "derive_serde")]
crate::tests::curve::random_serde_test::<Secp256k1>();
}

#[test]
fn test_endo_consistency() {
let g = Secp256k1::generator();
assert_eq!(g * Fq::ZETA, g.endo());
}

#[test]
fn ecdsa_example() {
use crate::group::Curve;
use crate::CurveAffine;
use ff::FromUniformBytes;
use rand_core::OsRng;

fn mod_n(x: Fp) -> Fq {
let mut x_repr = [0u8; 32];
x_repr.copy_from_slice(x.to_repr().as_ref());
let mut x_bytes = [0u8; 64];
x_bytes[..32].copy_from_slice(&x_repr[..]);
Fq::from_uniform_bytes(&x_bytes)
}

let g = Secp256k1::generator();

for _ in 0..1000 {
// Generate a key pair
let sk = Fq::random(OsRng);
let pk = (g * sk).to_affine();

// Generate a valid signature
// Suppose `m_hash` is the message hash
let msg_hash = Fq::random(OsRng);

let (r, s) = {
// Draw arandomness
let k = Fq::random(OsRng);
let k_inv = k.invert().unwrap();

// Calculate `r`
let r_point = (g * k).to_affine().coordinates().unwrap();
let x = r_point.x();
let r = mod_n(*x);

// Calculate `s`
let s = k_inv * (msg_hash + (r * sk));

(r, s)
};

{
// Verify
let s_inv = s.invert().unwrap();
let u_1 = msg_hash * s_inv;
let u_2 = r * s_inv;

let v_1 = g * u_1;
let v_2 = pk * u_2;

let r_point = (v_1 + v_2).to_affine().coordinates().unwrap();
let x_candidate = r_point.x();
let r_candidate = mod_n(*x_candidate);

assert_eq!(r, r_candidate);
}
}
}
crate::curve_testing_suite!(Secp256k1);
crate::curve_testing_suite!(Secp256k1, "endo_consistency");
crate::curve_testing_suite!(Secp256k1, "ecdsa_example");
crate::curve_testing_suite!(
Secp256k1,
"constants",
Fp::MODULUS,
SECP_A,
SECP_B,
SECP_GENERATOR_X,
SECP_GENERATOR_Y,
Fq::MODULUS
);
}
Loading

0 comments on commit 53dd906

Please sign in to comment.