From 94e3692cc4e9182b04b5e619b419fda8534326b4 Mon Sep 17 00:00:00 2001 From: David Nevado Date: Wed, 11 Dec 2024 18:44:45 +0100 Subject: [PATCH] Remove `pasta` dependency (#180) * add: CurveAffine trait * rm: pasta_curves dep add: pasta curves impl * chore: tests imports add: rustfmt file chore: cargo fmt --- Cargo.toml | 3 +- benches/curve.rs | 3 +- benches/fft.rs | 7 +- benches/hash_to_curve.rs | 5 +- benches/msm.rs | 15 ++-- derive/src/field/arith.rs | 3 +- derive/src/field/mod.rs | 1 - derive/src/utils.rs | 1 + rustfmt.toml | 10 +++ src/arithmetic.rs | 4 +- src/bls12381/engine.rs | 32 ++++---- src/bls12381/fq.rs | 1 + src/bls12381/fq12.rs | 9 +-- src/bls12381/fq2.rs | 17 ++-- src/bls12381/fq6.rs | 9 ++- src/bls12381/fr.rs | 1 + src/bls12381/g1.rs | 36 +++++---- src/bls12381/g2.rs | 47 +++++------ src/bls12381/mod.rs | 3 +- src/bn256/curve.rs | 45 +++++------ src/bn256/engine.rs | 36 +++++---- src/bn256/fq.rs | 4 +- src/bn256/fq12.rs | 9 +-- src/bn256/fq2.rs | 17 ++-- src/bn256/fq6.rs | 9 ++- src/bn256/fr.rs | 1 + src/curve.rs | 154 ++++++++++++++++++++++++++++++++++++ src/derive/field/common.rs | 6 +- src/ff_ext/cubic.rs | 4 +- src/ff_ext/inverse.rs | 87 +++++++++++--------- src/ff_ext/jacobi.rs | 109 +++++++++++++------------ src/fft.rs | 3 +- src/grumpkin/curve.rs | 39 ++++----- src/grumpkin/mod.rs | 3 +- src/hash_to_curve.rs | 75 +++++++++--------- src/lib.rs | 3 +- src/msm.rs | 20 +++-- src/pasta/curve.rs | 78 ++++++++++++++++++ src/pasta/fp.rs | 30 +++++++ src/pasta/fq.rs | 30 +++++++ src/pasta/mod.rs | 83 +++---------------- src/pasta/pallas.rs | 91 +++++++++++++++++++++ src/pasta/vesta.rs | 91 +++++++++++++++++++++ src/pluto_eris/curve.rs | 26 +++--- src/pluto_eris/engine.rs | 36 +++++---- src/pluto_eris/fp.rs | 4 +- src/pluto_eris/fp12.rs | 12 +-- src/pluto_eris/fp2.rs | 18 +++-- src/pluto_eris/fp6.rs | 15 ++-- src/pluto_eris/fq.rs | 1 + src/pluto_eris/mod.rs | 3 +- src/secp256k1/curve.rs | 27 ++++--- src/secp256k1/fp.rs | 1 + src/secp256k1/fq.rs | 1 + src/secp256r1/curve.rs | 29 ++++--- src/secp256r1/fp.rs | 1 + src/secp256r1/fq.rs | 1 + src/secq256k1/curve.rs | 32 +++++--- src/secq256k1/mod.rs | 3 +- src/serde.rs | 27 ++++--- src/tests/curve.rs | 8 +- src/tests/field.rs | 3 +- src/tests/field/legendre.rs | 3 +- src/tests/mod.rs | 3 +- 64 files changed, 1011 insertions(+), 477 deletions(-) create mode 100644 rustfmt.toml create mode 100644 src/curve.rs create mode 100644 src/pasta/curve.rs create mode 100644 src/pasta/fp.rs create mode 100644 src/pasta/fq.rs create mode 100644 src/pasta/pallas.rs create mode 100644 src/pasta/vesta.rs diff --git a/Cargo.toml b/Cargo.toml index 9df8e2159..4048b6ba8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,6 @@ subtle = "2.5" ff = { version = "0.13.0", default-features = false, features = ["std"] } group = "0.13.0" pairing = "0.23.0" -pasta_curves = "0.5.0" static_assertions = "1.1.0" rand = "0.8" rand_core = { version = "0.6", default-features = false } @@ -53,7 +52,7 @@ default = ["bits"] asm = ["halo2derive/asm"] bits = ["ff/bits"] bn256-table = [] -derive_serde = ["serde/derive", "serde_arrays", "hex", "pasta_curves/serde"] +derive_serde = ["serde/derive", "serde_arrays", "hex"] print-trace = ["ark-std/print-trace"] [profile.bench] diff --git a/benches/curve.rs b/benches/curve.rs index 37da38b4b..c954baa52 100644 --- a/benches/curve.rs +++ b/benches/curve.rs @@ -9,10 +9,11 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughpu use ff::Field; use group::prime::PrimeCurveAffine; use halo2curves::bn256::G1; -use pasta_curves::arithmetic::CurveExt; use rand::SeedableRng; use rand_xorshift::XorShiftRng; +use halo2curves::CurveExt; + fn bench_curve_ops(c: &mut Criterion, name: &'static str) { { let mut rng = XorShiftRng::seed_from_u64(3141519u64); diff --git a/benches/fft.rs b/benches/fft.rs index a9eda9ce6..8918e1a0b 100644 --- a/benches/fft.rs +++ b/benches/fft.rs @@ -13,14 +13,13 @@ #[macro_use] extern crate criterion; +use std::{ops::Range, time::SystemTime}; + use criterion::{BenchmarkId, Criterion}; use group::ff::Field; -use halo2curves::bn256::Fr as Scalar; -use halo2curves::fft::best_fft; +use halo2curves::{bn256::Fr as Scalar, fft::best_fft}; use rand::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; -use std::ops::Range; -use std::time::SystemTime; const RANGE: Range = 3..19; const SEED: [u8; 16] = [ diff --git a/benches/hash_to_curve.rs b/benches/hash_to_curve.rs index dca689b57..57f0a7811 100644 --- a/benches/hash_to_curve.rs +++ b/benches/hash_to_curve.rs @@ -5,13 +5,14 @@ //! //! cargo bench --bench hash_to_curve +use std::iter; + use criterion::{black_box, criterion_group, criterion_main, Criterion, Throughput}; use halo2curves::bn256::G1; -use pasta_curves::arithmetic::CurveExt; +use halo2curves::CurveExt; use rand::SeedableRng; use rand_core::RngCore; use rand_xorshift::XorShiftRng; -use std::iter; const SEED: [u8; 16] = [ 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06, 0xbc, 0xe5, diff --git a/benches/msm.rs b/benches/msm.rs index cf806b76d..8a98bcb51 100644 --- a/benches/msm.rs +++ b/benches/msm.rs @@ -12,16 +12,21 @@ #[macro_use] extern crate criterion; +use std::time::SystemTime; + use criterion::{BenchmarkId, Criterion}; use ff::{Field, PrimeField}; use group::prime::PrimeCurveAffine; -use halo2curves::bn256::{Fr as Scalar, G1Affine as Point}; -use halo2curves::msm::{msm_best, msm_serial}; +use halo2curves::{ + bn256::{Fr as Scalar, G1Affine as Point}, + msm::{msm_best, msm_serial}, +}; use rand_core::{RngCore, SeedableRng}; use rand_xorshift::XorShiftRng; -use rayon::current_thread_index; -use rayon::prelude::{IntoParallelIterator, ParallelIterator}; -use std::time::SystemTime; +use rayon::{ + current_thread_index, + prelude::{IntoParallelIterator, ParallelIterator}, +}; const SAMPLE_SIZE: usize = 10; const SINGLECORE_RANGE: [u8; 6] = [3, 8, 10, 12, 14, 16]; diff --git a/derive/src/field/arith.rs b/derive/src/field/arith.rs index f2edb888e..7ef11c3f3 100644 --- a/derive/src/field/arith.rs +++ b/derive/src/field/arith.rs @@ -1,6 +1,5 @@ use proc_macro2::TokenStream; -use quote::format_ident as fmtid; -use quote::quote; +use quote::{format_ident as fmtid, quote}; fn select(cond: bool, this: TokenStream, other: TokenStream) -> TokenStream { if cond { diff --git a/derive/src/field/mod.rs b/derive/src/field/mod.rs index 566fb9eeb..6ea6fa16b 100644 --- a/derive/src/field/mod.rs +++ b/derive/src/field/mod.rs @@ -548,7 +548,6 @@ pub(crate) fn impl_field(input: TokenStream) -> TokenStream { #[cfg(feature = "asm")] let impl_arith = { if num_limbs == 4 && num_bits < 256 { - println!("implementing asm, {}", identifier); asm::limb4::impl_arith(&field, inv64) } else { arith::impl_arith(&field, num_limbs, inv64) diff --git a/derive/src/utils.rs b/derive/src/utils.rs index 9b5cd3f86..596076526 100644 --- a/derive/src/utils.rs +++ b/derive/src/utils.rs @@ -1,4 +1,5 @@ use core::ops::Shl; + use num_bigint::BigUint; use num_traits::{One, ToPrimitive}; diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..8509df1d8 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,10 @@ +# It's the default. But here for visibility. +comment_width = 80 +# Makes code docs & examples easier to write. +format_code_in_doc_comments = true +# Group imports by crate. +imports_granularity = "Crate" +# This is a standard almost +wrap_comments = true +# Rustlang core team is migrating to this +group_imports = "StdExternalCrate" diff --git a/src/arithmetic.rs b/src/arithmetic.rs index dc8351777..71129bfa1 100644 --- a/src/arithmetic.rs +++ b/src/arithmetic.rs @@ -1,8 +1,8 @@ //! This module provides common utilities, traits and structures for group and //! field arithmetic. //! -//! This module is temporary, and the extension traits defined here are expected to be -//! upstreamed into the `ff` and `group` crates after some refactoring. +//! This module is temporary, and the extension traits defined here are expected +//! to be upstreamed into the `ff` and `group` crates after some refactoring. use crate::CurveExt; diff --git a/src/bls12381/engine.rs b/src/bls12381/engine.rs index a0d9e0e94..18a40bec0 100644 --- a/src/bls12381/engine.rs +++ b/src/bls12381/engine.rs @@ -1,20 +1,19 @@ -use super::fq12::Fq12; -use super::fq2::Fq2; -use super::{Fr, G1Affine, G2Affine, BLS_X, G1, G2}; -use crate::ff_ext::quadratic::QuadSparseMul; -use crate::ff_ext::ExtField; -use core::borrow::Borrow; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; -use ff::Field; -use ff::PrimeField; -use group::prime::PrimeCurveAffine; -use group::Group; +use core::{ + borrow::Borrow, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; +use std::ops::MulAssign; + +use ff::{Field, PrimeField}; +use group::{prime::PrimeCurveAffine, Group}; use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; use rand::RngCore; -use std::ops::MulAssign; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; +use super::{fq12::Fq12, fq2::Fq2, Fr, G1Affine, G2Affine, BLS_X, G1, G2}; +use crate::ff_ext::{quadratic::QuadSparseMul, ExtField}; + crate::impl_gt!(Gt, Fq12, Fr); crate::impl_miller_loop_components!(Bls12381, G1, G1Affine, G2, G2Affine, Fq12, Gt, Fr); @@ -116,11 +115,14 @@ fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) { #[cfg(test)] mod test { - use super::super::{Bls12381, Fr, G1, G2}; - use super::{multi_miller_loop, Fq12, G1Affine, G2Affine, Gt}; use ff::Field; use group::{prime::PrimeCurveAffine, Curve, Group}; use pairing::{Engine as _, MillerLoopResult, PairingCurveAffine}; use rand_core::OsRng; + + use super::{ + super::{Bls12381, Fr, G1, G2}, + multi_miller_loop, Fq12, G1Affine, G2Affine, Gt, + }; crate::test_pairing!(Bls12381, G1, G1Affine, G2, G2Affine, Fq12, Gt, Fr); } diff --git a/src/bls12381/fq.rs b/src/bls12381/fq.rs index 11320f228..2599a92f3 100644 --- a/src/bls12381/fq.rs +++ b/src/bls12381/fq.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; diff --git a/src/bls12381/fq12.rs b/src/bls12381/fq12.rs index e81006d0d..f059204d4 100644 --- a/src/bls12381/fq12.rs +++ b/src/bls12381/fq12.rs @@ -1,6 +1,4 @@ -use super::fq::Fq; -use super::fq2::Fq2; -use super::fq6::Fq6; +use super::{fq::Fq, fq2::Fq2, fq6::Fq6}; use crate::ff_ext::{ quadratic::{QuadExtField, QuadExtFieldArith, QuadSparseMul}, ExtField, @@ -281,11 +279,12 @@ mod test { } }; } - use super::*; - use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; use ff::Field; use rand::RngCore; + use super::*; + use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; + arith_test!(Fq12); // TODO Compile problems with derive_serde feature // serde_test!(fq12); diff --git a/src/bls12381/fq2.rs b/src/bls12381/fq2.rs index d88f286e0..bc3222625 100644 --- a/src/bls12381/fq2.rs +++ b/src/bls12381/fq2.rs @@ -1,11 +1,17 @@ -use super::fq::Fq; -use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::ff_ext::quadratic::{QuadExtField, QuadExtFieldArith, SQRT}; -use crate::ff_ext::{ExtField, Legendre}; use core::convert::TryInto; use std::cmp::Ordering; + use subtle::{Choice, CtOption}; +use super::fq::Fq; +use crate::{ + ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}, + ff_ext::{ + quadratic::{QuadExtField, QuadExtFieldArith, SQRT}, + ExtField, Legendre, + }, +}; + crate::impl_binops_additive!(Fq2, Fq2); crate::impl_binops_multiplicative!(Fq2, Fq2); crate::impl_binops_calls!(Fq2); @@ -64,11 +70,12 @@ impl ExtField for Fq2 { #[cfg(test)] mod test { + use rand_core::RngCore; + use super::*; use crate::{ arith_test, constants_test, f2_test, frobenius_test, legendre_test, serde_test, test, }; - use rand_core::RngCore; constants_test!(Fq2); diff --git a/src/bls12381/fq6.rs b/src/bls12381/fq6.rs index 19fe7b0a1..bf5722c09 100644 --- a/src/bls12381/fq6.rs +++ b/src/bls12381/fq6.rs @@ -1,10 +1,10 @@ -use super::fq::Fq; -use super::fq2::Fq2; +use ff::Field; + +use super::{fq::Fq, fq2::Fq2}; use crate::ff_ext::{ cubic::{CubicExtField, CubicExtFieldArith, CubicSparseMul}, ExtField, }; -use ff::Field; crate::impl_binops_additive!(Fq6, Fq6); crate::impl_binops_multiplicative!(Fq6, Fq6); @@ -276,9 +276,10 @@ pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ #[cfg(test)] mod test { + use rand_core::RngCore; + use super::*; use crate::{arith_test, frobenius_test, setup_f6_test_funcs, test}; - use rand_core::RngCore; macro_rules! test_fq6 { ($test:ident, $size: expr) => { diff --git a/src/bls12381/fr.rs b/src/bls12381/fr.rs index 67a06b29b..28674dfe1 100644 --- a/src/bls12381/fr.rs +++ b/src/bls12381/fr.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; diff --git a/src/bls12381/g1.rs b/src/bls12381/g1.rs index 451f1f0ee..119f5851f 100644 --- a/src/bls12381/g1.rs +++ b/src/bls12381/g1.rs @@ -1,20 +1,23 @@ -use super::fq::Fq; -use super::Fr; -use crate::serde::{Compressed, CompressedFlagConfig}; +use core::{ + cmp, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; + +use ff::{PrimeField, WithSmallOrderMulGroup}; +use group::{ + cofactor::CofactorGroup, ff::Field, prime::PrimeCurveAffine, Curve, Group, GroupEncoding, +}; +use rand_core::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use super::{fq::Fq, Fr}; use crate::{ impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, impl_binops_multiplicative_mixed, new_curve_impl, + serde::{Compressed, CompressedFlagConfig}, + Coordinates, CurveAffine, CurveExt, }; -use core::cmp; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; -use ff::PrimeField; -use ff::WithSmallOrderMulGroup; -use group::cofactor::CofactorGroup; -use group::{ff::Field, prime::PrimeCurveAffine, Curve, Group, GroupEncoding}; -use pasta_curves::arithmetic::{Coordinates, CurveAffine, CurveExt}; -use rand_core::RngCore; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; new_curve_impl!( (pub), @@ -148,7 +151,8 @@ fn iso_map(x: Fq, y: Fq, z: Fq) -> G1 { } } - // x denominator is order 1 less than x numerator, so we need an extra factor of z + // x denominator is order 1 less than x numerator, so we need an extra factor of + // z mapvals[1] *= z; // multiply result of Y map by the y-coord, y / z @@ -172,11 +176,11 @@ pub(crate) fn hash_to_curve<'a>( #[cfg(test)] mod test { - use crate::arithmetic::CurveEndo; - use crate::tests::curve::TestH2C; use group::UncompressedEncoding; + use rand_core::OsRng; use super::*; + use crate::{arithmetic::CurveEndo, serde::SerdeObject, tests::curve::TestH2C}; crate::curve_testing_suite!(G1); crate::curve_testing_suite!(G1, "endo_consistency"); crate::curve_testing_suite!(G1, "endo"); diff --git a/src/bls12381/g2.rs b/src/bls12381/g2.rs index df77bb517..3154551f9 100644 --- a/src/bls12381/g2.rs +++ b/src/bls12381/g2.rs @@ -1,23 +1,23 @@ -use crate::bls12381::fq::Fq; -use crate::bls12381::fq2::Fq2; -use crate::bls12381::fr::Fr; -use crate::ff::WithSmallOrderMulGroup; -use crate::ff::{Field, PrimeField}; -use crate::ff_ext::ExtField; -use crate::group::Curve; -use crate::group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Group, GroupEncoding}; -use crate::serde::{Compressed, CompressedFlagConfig}; +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; + +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + use crate::{ + bls12381::{fq::Fq, fq2::Fq2, fr::Fr}, + ff::{Field, PrimeField, WithSmallOrderMulGroup}, + ff_ext::ExtField, + group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Curve, Group, GroupEncoding}, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, impl_binops_multiplicative_mixed, new_curve_impl, + serde::{Compressed, CompressedFlagConfig}, + Coordinates, CurveAffine, CurveExt, }; -use crate::{Coordinates, CurveAffine, CurveExt}; -use core::cmp; -use core::fmt::Debug; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; const G2_GENERATOR_X: Fq2 = Fq2 { c0: Fq([ @@ -126,9 +126,9 @@ impl group::cofactor::CofactorGroup for G2 { CtOption::new(self, 1.into()) } - /// Returns true if this point is free of an $h$-torsion component, and so it - /// exists within the $q$-order subgroup $\mathbb{G}_2$. This should always return true - /// unless an "unchecked" API was used. + /// Returns true if this point is free of an $h$-torsion component, and so + /// it exists within the $q$-order subgroup $\mathbb{G}_2$. This should + /// always return true unless an "unchecked" API was used. fn is_torsion_free(&self) -> Choice { // Algorithm from Section 4 of https://eprint.iacr.org/2021/1130 // Updated proof of correctness in https://eprint.iacr.org/2022/352 @@ -305,7 +305,8 @@ fn iso_map(x: Fq2, y: Fq2, z: Fq2) -> G2 { } } - // x denominator is order 1 less than x numerator, so we need an extra factor of z + // x denominator is order 1 less than x numerator, so we need an extra factor of + // z mapvals[1] *= z; // multiply result of Y map by the y-coord, y / z @@ -329,9 +330,11 @@ pub(crate) fn hash_to_curve<'a>( #[cfg(test)] mod test { - use super::*; - use crate::arithmetic::CurveEndo; use group::UncompressedEncoding; + use rand_core::OsRng; + + use super::*; + use crate::{arithmetic::CurveEndo, serde::SerdeObject}; crate::curve_testing_suite!(G2); crate::curve_testing_suite!(G2, "endo_consistency"); diff --git a/src/bls12381/mod.rs b/src/bls12381/mod.rs index 5ab08f150..08577e5bd 100644 --- a/src/bls12381/mod.rs +++ b/src/bls12381/mod.rs @@ -30,7 +30,8 @@ const ENDO_PARAMS: EndoParameters = EndoParameters { b2: [0x0000000100000000, 0xac45a4010001a402, 0x0, 0x0], }; -use crate::arithmetic::{mul_512, sbb, CurveEndo, EndoParameters}; use ff::{PrimeField, WithSmallOrderMulGroup}; + +use crate::arithmetic::{mul_512, sbb, CurveEndo, EndoParameters}; crate::endo!(G1, Fr, ENDO_PARAMS); crate::endo!(G2, Fr, ENDO_PARAMS); diff --git a/src/bn256/curve.rs b/src/bn256/curve.rs index dadf31d6f..14c6d9f25 100644 --- a/src/bn256/curve.rs +++ b/src/bn256/curve.rs @@ -1,28 +1,24 @@ -use crate::arithmetic::mul_512; -use crate::arithmetic::sbb; -use crate::arithmetic::CurveEndo; -use crate::arithmetic::EndoParameters; -use crate::bn256::Fq; -use crate::bn256::Fq2; -use crate::bn256::Fr; -use crate::endo; -use crate::ff::WithSmallOrderMulGroup; -use crate::ff::{Field, PrimeField}; -use crate::group::Curve; -use crate::group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Group, GroupEncoding}; -use crate::{ - impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, new_curve_impl, +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, }; -use crate::{Coordinates, CurveAffine, CurveExt}; -use core::cmp; -use core::fmt::Debug; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; use std::convert::TryInto; + +use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use crate::{ + arithmetic::{mul_512, sbb, CurveEndo, EndoParameters}, + bn256::{Fq, Fq2, Fr}, + endo, + ff::{Field, PrimeField, WithSmallOrderMulGroup}, + group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Curve, Group, GroupEncoding}, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, new_curve_impl, Coordinates, CurveAffine, CurveExt, +}; + impl crate::serde::endian::EndianRepr for Fq2 { const ENDIAN: crate::serde::endian::Endian = Fq::ENDIAN; @@ -164,7 +160,7 @@ impl group::cofactor::CofactorGroup for G1 { fn exp_by_x(g2: &G2) -> G2 { let x = super::BN_X; - (0..62).rev().fold(g2.clone(), |mut acc, i| { + (0..62).rev().fold(*g2, |mut acc, i| { println!("{}", ((x >> i) & 1) == 1); acc = acc.double(); @@ -264,10 +260,11 @@ impl G2 { #[cfg(test)] mod test { - use crate::tests::curve::TestH2C; + use group::UncompressedEncoding; + use rand_core::OsRng; use super::*; - use group::UncompressedEncoding; + use crate::{serde::SerdeObject, tests::curve::TestH2C}; crate::curve_testing_suite!(G2, "clear_cofactor"); crate::curve_testing_suite!(G1, G2); diff --git a/src/bn256/engine.rs b/src/bn256/engine.rs index 630a36f28..fa1c81877 100644 --- a/src/bn256/engine.rs +++ b/src/bn256/engine.rs @@ -1,22 +1,21 @@ -use crate::bn256::curve::*; -use crate::bn256::fq::*; -use crate::bn256::fq12::*; -use crate::bn256::fq2::*; -use crate::bn256::fq6::FROBENIUS_COEFF_FQ6_C1; -use crate::bn256::fr::*; -use crate::ff::PrimeField; -use crate::ff_ext::quadratic::QuadSparseMul; -use crate::ff_ext::ExtField; -use crate::group::cofactor::CofactorCurveAffine; -use crate::group::Group; -use core::borrow::Borrow; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; +use core::{ + borrow::Borrow, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; +use std::ops::MulAssign; + use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; use rand_core::RngCore; -use std::ops::MulAssign; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; +use crate::{ + bn256::{curve::*, fq::*, fq12::*, fq2::*, fq6::FROBENIUS_COEFF_FQ6_C1, fr::*}, + ff::PrimeField, + ff_ext::{quadratic::QuadSparseMul, ExtField}, + group::{cofactor::CofactorCurveAffine, Group}, +}; + crate::impl_gt!(Gt, Fq12, Fr); crate::impl_miller_loop_components!(Bn256, G1, G1Affine, G2, G2Affine, Fq12, Gt, Fr); @@ -208,11 +207,14 @@ fn ell(f: &mut Fq12, coeffs: &(Fq2, Fq2, Fq2), p: &G1Affine) { #[cfg(test)] mod test { - use super::super::{Bn256, Fr, G1, G2}; - use super::{multi_miller_loop, Fq12, G1Affine, G2Affine, Gt}; use ff::Field; use group::{prime::PrimeCurveAffine, Curve, Group}; use pairing::{Engine, MillerLoopResult, PairingCurveAffine}; use rand_core::OsRng; + + use super::{ + super::{Bn256, Fr, G1, G2}, + multi_miller_loop, Fq12, G1Affine, G2Affine, Gt, + }; crate::test_pairing!(Bn256, G1, G1Affine, G2, G2Affine, Fq12, Gt, Fr); } diff --git a/src/bn256/fq.rs b/src/bn256/fq.rs index d3fa7fbc1..f234c1a8b 100644 --- a/src/bn256/fq.rs +++ b/src/bn256/fq.rs @@ -1,9 +1,11 @@ -use crate::ff_ext::ExtField; use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use crate::ff_ext::ExtField; + impl_field!( bn256_base, Fq, diff --git a/src/bn256/fq12.rs b/src/bn256/fq12.rs index c6186ac71..e14b6e93d 100644 --- a/src/bn256/fq12.rs +++ b/src/bn256/fq12.rs @@ -1,6 +1,4 @@ -use super::fq::Fq; -use super::fq2::Fq2; -use super::fq6::Fq6; +use super::{fq::Fq, fq2::Fq2, fq6::Fq6}; use crate::ff_ext::{ quadratic::{QuadExtField, QuadExtFieldArith, QuadSparseMul}, ExtField, @@ -209,11 +207,12 @@ mod test { } }; } - use super::*; - use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; use ff::Field; use rand::RngCore; + use super::*; + use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; + arith_test!(Fq12); // F12 specific diff --git a/src/bn256/fq2.rs b/src/bn256/fq2.rs index 2aa478ac8..6201f7036 100644 --- a/src/bn256/fq2.rs +++ b/src/bn256/fq2.rs @@ -1,11 +1,17 @@ -use super::fq::Fq; -use crate::ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}; -use crate::ff_ext::quadratic::{QuadExtField, QuadExtFieldArith, SQRT}; -use crate::ff_ext::{ExtField, Legendre}; use core::convert::TryInto; use std::cmp::Ordering; + use subtle::{Choice, CtOption}; +use super::fq::Fq; +use crate::{ + ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}, + ff_ext::{ + quadratic::{QuadExtField, QuadExtFieldArith, SQRT}, + ExtField, Legendre, + }, +}; + crate::impl_binops_additive!(Fq2, Fq2); crate::impl_binops_multiplicative!(Fq2, Fq2); crate::impl_binops_calls!(Fq2); @@ -67,11 +73,12 @@ impl ExtField for Fq2 { #[cfg(test)] mod test { + use rand_core::RngCore; + use super::*; use crate::{ arith_test, constants_test, f2_test, frobenius_test, legendre_test, serde_test, test, }; - use rand_core::RngCore; constants_test!(Fq2); arith_test!(Fq2); diff --git a/src/bn256/fq6.rs b/src/bn256/fq6.rs index fcdef910d..ed3e33717 100644 --- a/src/bn256/fq6.rs +++ b/src/bn256/fq6.rs @@ -1,10 +1,10 @@ -use super::fq::Fq; -use super::fq2::Fq2; +use ff::Field; + +use super::{fq::Fq, fq2::Fq2}; use crate::ff_ext::{ cubic::{CubicExtField, CubicExtFieldArith, CubicSparseMul}, ExtField, }; -use ff::Field; // -BETA is a cubic non-residue in Fp2. Fp6 = Fp2[X]/(X^3 + BETA) // We introduce the variable v such that v^3 = -BETA @@ -203,9 +203,10 @@ pub const FROBENIUS_COEFF_FQ6_C2: [Fq2; 6] = [ #[cfg(test)] mod test { + use rand_core::RngCore; + use super::*; use crate::{arith_test, frobenius_test, setup_f6_test_funcs, test}; - use rand_core::RngCore; macro_rules! test_fq6 { ($test:ident, $size: expr) => { diff --git a/src/bn256/fr.rs b/src/bn256/fr.rs index edc1e02c0..c8bd3a0f3 100644 --- a/src/bn256/fr.rs +++ b/src/bn256/fr.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; diff --git a/src/curve.rs b/src/curve.rs new file mode 100644 index 000000000..1740f640e --- /dev/null +++ b/src/curve.rs @@ -0,0 +1,154 @@ +//! This module contains the `Curve`/`CurveAffine` abstractions that allow us to +//! write code that generalizes over a pair of groups. + +use core::ops::{Add, Mul, Sub}; + +use group::prime::{PrimeCurve, PrimeCurveAffine}; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +/// This trait is a common interface for dealing with elements of an elliptic +/// curve group in a "projective" form, where that arithmetic is usually more +/// efficient. +/// +/// Requires the `alloc` feature flag because of `hash_to_curve`. +pub trait CurveExt: + PrimeCurve::AffineExt> + + group::Group::ScalarExt> + + Default + + ConditionallySelectable + + ConstantTimeEq + + From<::Affine> +{ + /// The scalar field of this elliptic curve. + type ScalarExt: ff::WithSmallOrderMulGroup<3>; + /// The base field over which this elliptic curve is constructed. + type Base: ff::WithSmallOrderMulGroup<3>; + /// The affine version of the curve + type AffineExt: CurveAffine::ScalarExt> + + Mul + + for<'r> Mul; + + /// CURVE_ID used for hash-to-curve. + const CURVE_ID: &'static str; + + /// Apply the curve endomorphism by multiplying the x-coordinate + /// by an element of multiplicative order 3. + fn endo(&self) -> Self; + + /// Return the Jacobian coordinates of this point. + fn jacobian_coordinates(&self) -> (Self::Base, Self::Base, Self::Base); + + /// Requests a hasher that accepts messages and returns near-uniformly + /// distributed elements in the group, given domain prefix `domain_prefix`. + /// + /// This method is suitable for use as a random oracle. + fn hash_to_curve<'a>(domain_prefix: &'a str) -> Box Self + 'a>; + + /// Returns whether or not this element is on the curve; should + /// always be true unless an "unchecked" API was used. + fn is_on_curve(&self) -> Choice; + + /// Returns the curve constant a. + fn a() -> Self::Base; + + /// Returns the curve constant b. + fn b() -> Self::Base; + + /// Obtains a point given Jacobian coordinates $X : Y : Z$, failing + /// if the coordinates are not on the curve. + fn new_jacobian(x: Self::Base, y: Self::Base, z: Self::Base) -> CtOption; +} +/// This trait is the affine counterpart to `Curve` and is used for +/// serialization, storage in memory, and inspection of $x$ and $y$ coordinates. +/// +/// Requires the `alloc` feature flag because of `hash_to_curve` on +/// [`CurveExt`]. +pub trait CurveAffine: + PrimeCurveAffine< + Scalar = ::ScalarExt, + Curve = ::CurveExt, + > + Default + + Add::Curve> + + Sub::Curve> + + ConditionallySelectable + + ConstantTimeEq + + From<::Curve> +{ + /// The scalar field of this elliptic curve. + type ScalarExt: ff::WithSmallOrderMulGroup<3> + Ord; + /// The base field over which this elliptic curve is constructed. + type Base: ff::WithSmallOrderMulGroup<3> + Ord; + /// The projective form of the curve + type CurveExt: CurveExt::ScalarExt>; + + /// Gets the coordinates of this point. + /// + /// Returns None if this is the identity. + fn coordinates(&self) -> CtOption>; + + /// Obtains a point given $(x, y)$, failing if it is not on the + /// curve. + fn from_xy(x: Self::Base, y: Self::Base) -> CtOption; + + /// Returns whether or not this element is on the curve; should + /// always be true unless an "unchecked" API was used. + fn is_on_curve(&self) -> Choice; + + /// Returns the curve constant $a$. + fn a() -> Self::Base; + + /// Returns the curve constant $b$. + fn b() -> Self::Base; +} + +/// The affine coordinates of a point on an elliptic curve. +#[derive(Clone, Copy, Debug, Default)] +pub struct Coordinates { + pub(crate) x: C::Base, + pub(crate) y: C::Base, +} + +impl Coordinates { + /// Obtains a `Coordinates` value given $(x, y)$, failing if it is not on + /// the curve. + pub fn from_xy(x: C::Base, y: C::Base) -> CtOption { + // We use CurveAffine::from_xy to validate the coordinates. + C::from_xy(x, y).map(|_| Coordinates { x, y }) + } + /// Returns the x-coordinate. + /// + /// Equivalent to `Coordinates::u`. + pub fn x(&self) -> &C::Base { + &self.x + } + + /// Returns the y-coordinate. + /// + /// Equivalent to `Coordinates::v`. + pub fn y(&self) -> &C::Base { + &self.y + } + + /// Returns the u-coordinate. + /// + /// Equivalent to `Coordinates::x`. + pub fn u(&self) -> &C::Base { + &self.x + } + + /// Returns the v-coordinate. + /// + /// Equivalent to `Coordinates::y`. + pub fn v(&self) -> &C::Base { + &self.y + } +} + +impl ConditionallySelectable for Coordinates { + fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { + Coordinates { + x: C::Base::conditional_select(&a.x, &b.x, choice), + y: C::Base::conditional_select(&a.y, &b.y, choice), + } + } +} diff --git a/src/derive/field/common.rs b/src/derive/field/common.rs index 3a2f7e9a9..95c2ce643 100644 --- a/src/derive/field/common.rs +++ b/src/derive/field/common.rs @@ -84,9 +84,9 @@ macro_rules! impl_from_bool { }; } -/// A macro to help define serialization and deserialization for prime field implementations -/// that use `$field::Repr`` representations. This assumes the concerned type implements PrimeField -/// (for from_repr, to_repr). +/// A macro to help define serialization and deserialization for prime field +/// implementations that use `$field::Repr`` representations. This assumes the +/// concerned type implements PrimeField (for from_repr, to_repr). #[macro_export] macro_rules! serialize_deserialize_primefield { ($field:ident) => { diff --git a/src/ff_ext/cubic.rs b/src/ff_ext/cubic.rs index 70af416cb..671f3250c 100644 --- a/src/ff_ext/cubic.rs +++ b/src/ff_ext/cubic.rs @@ -187,7 +187,9 @@ where impl ff::Field for CubicExtField where - CubicExtField: CubicExtFieldArith + ExtField, // kind of cyclic being `ExtField: Field` but it seems alright + CubicExtField: CubicExtFieldArith + ExtField, /* kind of cyclic being + * `ExtField: Field` but it seems + * alright */ { const ZERO: Self = Self::zero(); const ONE: Self = Self::one(); diff --git a/src/ff_ext/inverse.rs b/src/ff_ext/inverse.rs index d149b3ec1..116eaf249 100644 --- a/src/ff_ext/inverse.rs +++ b/src/ff_ext/inverse.rs @@ -219,26 +219,31 @@ impl Mul> for i64 { } } -/// Type of the modular multiplicative inverter based on the Bernstein-Yang method. -/// The inverter can be created for a specified modulus M and adjusting parameter A -/// to compute the adjusted multiplicative inverses of positive integers, i.e. for -/// computing (1 / x) * A (mod M) for a positive integer x. +/// Type of the modular multiplicative inverter based on the Bernstein-Yang +/// method. The inverter can be created for a specified modulus M and adjusting +/// parameter A to compute the adjusted multiplicative inverses of positive +/// integers, i.e. for computing (1 / x) * A (mod M) for a positive integer x. /// -/// The adjusting parameter allows computing the multiplicative inverses in the case of -/// using the Montgomery representation for the input or the expected output. If R is -/// the Montgomery factor, the multiplicative inverses in the appropriate representation -/// can be computed provided that the value of A is chosen as follows: +/// The adjusting parameter allows computing the multiplicative inverses in the +/// case of using the Montgomery representation for the input or the expected +/// output. If R is the Montgomery factor, the multiplicative inverses in the +/// appropriate representation can be computed provided that the value of A is +/// chosen as follows: /// - A = 1, if both the input and the expected output are in the standard form -/// - A = R^2 mod M, if both the input and the expected output are in the Montgomery form -/// - A = R mod M, if either the input or the expected output is in the Montgomery form, +/// - A = R^2 mod M, if both the input and the expected output are in the +/// Montgomery form +/// - A = R mod M, if either the input or the expected output is in the +/// Montgomery form, /// but not both of them /// -/// The public methods of this type receive and return unsigned big integers as arrays of -/// 64-bit chunks, the ordering of which is little-endian. Both the modulus and the integer -/// to be inverted should not exceed 2 ^ (62 * L - 64) +/// The public methods of this type receive and return unsigned big integers as +/// arrays of 64-bit chunks, the ordering of which is little-endian. Both the +/// modulus and the integer to be inverted should not exceed 2 ^ (62 * L - 64) /// -/// For better understanding the implementation, the following resources are recommended: -/// - D. Bernstein, B.-Y. Yang, "Fast constant-time gcd computation and modular inversion", +/// For better understanding the implementation, the following resources are +/// recommended: +/// - D. Bernstein, B.-Y. Yang, "Fast constant-time gcd computation and modular +/// inversion", /// https://gcd.cr.yp.to/safegcd-20190413.pdf /// - P. Wuille, "The safegcd implementation in libsecp256k1 explained", /// https://github.com/bitcoin-core/secp256k1/blob/master/doc/safegcd_implementation.md @@ -257,9 +262,10 @@ pub struct BYInverter { type Matrix = [[i64; 2]; 2]; impl BYInverter { - /// Returns the Bernstein-Yang transition matrix multiplied by 2^62 and the new value - /// of the delta variable for the 62 basic steps of the Bernstein-Yang method, which - /// are to be performed sequentially for specified initial values of f, g and delta + /// Returns the Bernstein-Yang transition matrix multiplied by 2^62 and the + /// new value of the delta variable for the 62 basic steps of the + /// Bernstein-Yang method, which are to be performed sequentially for + /// specified initial values of f, g and delta fn jump(f: &CInt<62, L>, g: &CInt<62, L>, mut delta: i64) -> (i64, Matrix) { let (mut steps, mut f, mut g) = (62, f.lowest() as i64, g.lowest() as i128); let mut t: Matrix = [[1, 0], [0, 1]]; @@ -290,8 +296,10 @@ impl BYInverter { (delta, t) } - /// Returns the updated values of the variables f and g for specified initial ones and Bernstein-Yang transition - /// matrix multiplied by 2^62. The returned vector is "matrix * (f, g)' / 2^62", where "'" is the transpose operator + /// Returns the updated values of the variables f and g for specified + /// initial ones and Bernstein-Yang transition matrix multiplied by + /// 2^62. The returned vector is "matrix * (f, g)' / 2^62", where "'" is the + /// transpose operator fn fg(f: CInt<62, L>, g: CInt<62, L>, t: Matrix) -> (CInt<62, L>, CInt<62, L>) { ( (t[0][0] * &f + t[0][1] * &g).shift(), @@ -299,10 +307,12 @@ impl BYInverter { ) } - /// Returns the updated values of the variables d and e for specified initial ones and Bernstein-Yang transition - /// matrix multiplied by 2^62. The returned vector is congruent modulo M to "matrix * (d, e)' / 2^62 (mod M)", - /// where M is the modulus the inverter was created for and "'" stands for the transpose operator. Both the input - /// and output values lie in the interval (-2 * M, M) + /// Returns the updated values of the variables d and e for specified + /// initial ones and Bernstein-Yang transition matrix multiplied by + /// 2^62. The returned vector is congruent modulo M to "matrix * (d, e)' / + /// 2^62 (mod M)", where M is the modulus the inverter was created for + /// and "'" stands for the transpose operator. Both the input and output + /// values lie in the interval (-2 * M, M) fn de(&self, d: CInt<62, L>, e: CInt<62, L>, t: Matrix) -> (CInt<62, L>, CInt<62, L>) { let mask = CInt::<62, L>::MASK as i64; let mut md = t[0][0] * d.is_negative() as i64 + t[0][1] * e.is_negative() as i64; @@ -326,9 +336,10 @@ impl BYInverter { (cd.shift(), ce.shift()) } - /// Returns either "value (mod M)" or "-value (mod M)", where M is the modulus the - /// inverter was created for, depending on "negate", which determines the presence - /// of "-" in the used formula. The input integer lies in the interval (-2 * M, M) + /// Returns either "value (mod M)" or "-value (mod M)", where M is the + /// modulus the inverter was created for, depending on "negate", which + /// determines the presence of "-" in the used formula. The input + /// integer lies in the interval (-2 * M, M) fn norm(&self, mut value: CInt<62, L>, negate: bool) -> CInt<62, L> { if value.is_negative() { value = value + &self.modulus; @@ -345,11 +356,13 @@ impl BYInverter { value } - /// Returns a big unsigned integer as an array of O-bit chunks, which is equal modulo - /// 2 ^ (O * S) to the input big unsigned integer stored as an array of I-bit chunks. - /// The ordering of the chunks in these arrays is little-endian + /// Returns a big unsigned integer as an array of O-bit chunks, which is + /// equal modulo 2 ^ (O * S) to the input big unsigned integer stored as + /// an array of I-bit chunks. The ordering of the chunks in these arrays + /// is little-endian const fn convert(input: &[u64]) -> [u64; S] { - // This function is defined because the method "min" of the usize type is not constant + // This function is defined because the method "min" of the usize type is not + // constant const fn min(a: usize, b: usize) -> usize { if a > b { b @@ -377,9 +390,10 @@ impl BYInverter { output } - /// Returns the multiplicative inverse of the argument modulo 2^62. The implementation is based - /// on the Hurchalla's method for computing the multiplicative inverse modulo a power of two. - /// For better understanding the implementation, the following paper is recommended: + /// Returns the multiplicative inverse of the argument modulo 2^62. The + /// implementation is based on the Hurchalla's method for computing the + /// multiplicative inverse modulo a power of two. For better + /// understanding the implementation, the following paper is recommended: /// J. Hurchalla, "An Improved Integer Multiplicative Inverse (modulo 2^w)", /// https://arxiv.org/pdf/2204.04342.pdf const fn inv(value: u64) -> i64 { @@ -400,8 +414,9 @@ impl BYInverter { } } - /// Returns either the adjusted modular multiplicative inverse for the argument or None - /// depending on invertibility of the argument, i.e. its coprimality with the modulus + /// Returns either the adjusted modular multiplicative inverse for the + /// argument or None depending on invertibility of the argument, i.e. + /// its coprimality with the modulus pub fn invert(&self, value: &[u64]) -> Option<[u64; S]> { let (mut d, mut e) = (CInt::ZERO, self.adjuster.clone()); let mut g = CInt::<62, L>(Self::convert::<64, 62, L>(value)); diff --git a/src/ff_ext/jacobi.rs b/src/ff_ext/jacobi.rs index ed577b5e8..0f6585659 100644 --- a/src/ff_ext/jacobi.rs +++ b/src/ff_ext/jacobi.rs @@ -37,19 +37,21 @@ impl LInt { self.0[L - 1] > (u64::MAX >> 1) } - /// Returns a tuple representing the sum of the first two arguments and the bit - /// described by the third argument. The first element of the tuple is this sum - /// modulo 2^64, the second one indicates whether the sum is no less than 2^64 + /// Returns a tuple representing the sum of the first two arguments and the + /// bit described by the third argument. The first element of the tuple + /// is this sum modulo 2^64, the second one indicates whether the sum is + /// no less than 2^64 #[inline] fn sum(first: u64, second: u64, carry: bool) -> (u64, bool) { - // The implementation is inspired with the "carrying_add" function from this source: - // https://github.com/rust-lang/rust/blob/master/library/core/src/num/uint_macros.rs + // The implementation is inspired with the "carrying_add" function from this + // source: https://github.com/rust-lang/rust/blob/master/library/core/src/num/uint_macros.rs let (second, carry) = second.overflowing_add(carry as u64); let (first, high) = first.overflowing_add(second); (first, carry || high) } - /// Returns "(low, high)", where "high * 2^64 + low = first * second + carry + summand" + /// Returns "(low, high)", where "high * 2^64 + low = first * second + carry + /// + summand" #[inline] fn prodsum(first: u64, second: u64, summand: u64, carry: u64) -> (u64, u64) { let all = (first as u128) * (second as u128) + (carry as u128) + (summand as u128); @@ -65,9 +67,10 @@ impl PartialEq for LInt { impl Shr for &LInt { type Output = LInt; - /// Returns the result of applying the arithmetic right shift to the current number. - /// The specified bit quantity the number is shifted by must lie in {1, 2, ..., 63}. - /// For the quantities outside of the range, the behavior of the method is undefined + /// Returns the result of applying the arithmetic right shift to the current + /// number. The specified bit quantity the number is shifted by must lie + /// in {1, 2, ..., 63}. For the quantities outside of the range, the + /// behavior of the method is undefined fn shr(self, bits: u32) -> Self::Output { debug_assert!( (bits > 0) && (bits < 64), @@ -248,18 +251,19 @@ impl Mul> for i64 { } } -/// Returns the "approximations" of the arguments and the flag indicating whether -/// both arguments are equal to their "approximations". Both the arguments must be -/// non-negative, and at least one of them must be non-zero. For an incorrect input, -/// the behavior of the function is undefined. These "approximations" are defined -/// in the following way. Let n be the bit length of the largest argument without -/// leading zeros. For n > 64 the "approximation" of the argument, which equals v, -/// is (v div 2 ^ (n - 32)) * 2 ^ 32 + (v mod 2 ^ 32), i.e. it retains the high and -/// low bits of the n-bit representation of v. If n does not exceed 64, an argument -/// and its "approximation" are equal. These "approximations" are defined slightly -/// differently from the ones in the Pornin's method for modular inversion: instead -/// of taking the 33 high and 31 low bits of the n-bit representation of an argument, -/// the 32 high and 32 low bits are taken +/// Returns the "approximations" of the arguments and the flag indicating +/// whether both arguments are equal to their "approximations". Both the +/// arguments must be non-negative, and at least one of them must be non-zero. +/// For an incorrect input, the behavior of the function is undefined. These +/// "approximations" are defined in the following way. Let n be the bit length +/// of the largest argument without leading zeros. For n > 64 the +/// "approximation" of the argument, which equals v, is (v div 2 ^ (n - 32)) * 2 +/// ^ 32 + (v mod 2 ^ 32), i.e. it retains the high and low bits of the n-bit +/// representation of v. If n does not exceed 64, an argument +/// and its "approximation" are equal. These "approximations" are defined +/// slightly differently from the ones in the Pornin's method for modular +/// inversion: instead of taking the 33 high and 31 low bits of the n-bit +/// representation of an argument, the 32 high and 32 low bits are taken fn approximate(x: &LInt, y: &LInt) -> (u64, u64, bool) { debug_assert!( !(x.is_negative() || y.is_negative()), @@ -317,13 +321,14 @@ fn jacobinary(mut n: u64, mut d: u64, mut t: u64) -> i64 { /// big integers in the form of arrays of 64-bit chunks, the ordering of which /// is little-endian. The value of "d" must be odd in accordance with the Jacobi /// symbol definition. Both the arguments must be less than 2 ^ (64 * L - 31). -/// For an incorrect input, the behavior of the function is undefined. The method -/// differs from the Pornin's method for modular inversion in absence of the parts, -/// which are not necessary to compute the greatest common divisor of arguments, -/// presence of the parts used to compute the Jacobi symbol, which are based on -/// the properties of the modified Jacobi symbol (x / |y|) described by M. Hamburg, -/// and some original optimizations. Only these differences have been commented; -/// the aforesaid Pornin's method and the used ideas of M. Hamburg were given here: +/// For an incorrect input, the behavior of the function is undefined. The +/// method differs from the Pornin's method for modular inversion in absence of +/// the parts, which are not necessary to compute the greatest common divisor of +/// arguments, presence of the parts used to compute the Jacobi symbol, which +/// are based on the properties of the modified Jacobi symbol (x / |y|) +/// described by M. Hamburg, and some original optimizations. Only these +/// differences have been commented; the aforesaid Pornin's method and the used +/// ideas of M. Hamburg were given here: /// - T. Pornin, "Optimized Binary GCD for Modular Inversion", /// https://eprint.iacr.org/2020/972.pdf /// - M. Hamburg, "Computing the Jacobi symbol using Bernstein-Yang", @@ -341,21 +346,24 @@ pub fn jacobi(n: &[u64], d: &[u64]) -> i64 { "Both the arguments must be less than 2 ^ (64 * L - 31)!" ); loop { - // The inner loop performs 30 iterations instead of 31 ones in the aforementioned - // Pornin's method, and the "approximations" of "n" and "d" retain 32 of the lowest - // bits instead of 31 in that method. These modifications allow the values of the - // "approximation" variables to be equal modulo 8 to the corresponding "precise" - // variables' values, which would have been computed, if the "precise" variables - // had been updated in the inner loop along with the "approximations". This equality - // modulo 8 is used to update the second-lowest bit of "t" in accordance with the - // properties of the modified Jacobi symbol (x / |y|). The admissibility of these - // modifications has been proven using the appropriately modified Pornin's theorems + // The inner loop performs 30 iterations instead of 31 ones in the + // aforementioned Pornin's method, and the "approximations" of "n" and + // "d" retain 32 of the lowest bits instead of 31 in that method. These + // modifications allow the values of the "approximation" variables to be + // equal modulo 8 to the corresponding "precise" variables' values, + // which would have been computed, if the "precise" variables + // had been updated in the inner loop along with the "approximations". This + // equality modulo 8 is used to update the second-lowest bit of "t" in + // accordance with the properties of the modified Jacobi symbol (x / + // |y|). The admissibility of these modifications has been proven using + // the appropriately modified Pornin's theorems let (mut u, mut v, mut i) = ((1i64, 0i64), (0i64, 1i64), 30); let (mut a, mut b, precise) = approximate(&n, &d); - // When each "approximation" variable has the same value as the corresponding "precise" - // one, the computation is accomplished using the short-arithmetic method of the Jacobi - // symbol calculation by means of the binary Euclidean algorithm. This approach aims at - // avoiding the parts of the final computations, which are related to long arithmetic + // When each "approximation" variable has the same value as the corresponding + // "precise" one, the computation is accomplished using the + // short-arithmetic method of the Jacobi symbol calculation by means of + // the binary Euclidean algorithm. This approach aims at avoiding the + // parts of the final computations, which are related to long arithmetic if precise { return jacobinary(a, b, t); } @@ -395,21 +403,24 @@ pub fn jacobi(n: &[u64], d: &[u64]) -> i64 { // This fragment is present to guarantee the correct behavior of the function // in the case of arguments, whose greatest common divisor is no less than 2^64 if n == LInt::ZERO { - // In both the aforesaid Pornin's method and its modification the pair of the values - // of "n" and "d" after the divergence point contains a positive number and a negative - // one. Since the value of "n" is 0, the divergence point has not been reached by the - // inner loop this time, so there is no need to check whether "d" is equal to -1 + // In both the aforesaid Pornin's method and its modification the pair of the + // values of "n" and "d" after the divergence point contains a + // positive number and a negative one. Since the value of "n" is 0, + // the divergence point has not been reached by the inner loop this + // time, so there is no need to check whether "d" is equal to -1 return (d == LInt::ONE) as i64 * (1 - (t & 2) as i64); } if n.is_negative() { - // Since in both the aforesaid Pornin's method and its modification "d" is always odd - // and cannot become negative simultaneously with "n", the value of "d" is positive. - // The modified Jacobi symbol (-1 / |y|) for a positive y is -1, iff y mod 4 = 3 + // Since in both the aforesaid Pornin's method and its modification "d" is + // always odd and cannot become negative simultaneously with "n", + // the value of "d" is positive. The modified Jacobi symbol (-1 / + // |y|) for a positive y is -1, iff y mod 4 = 3 t ^= d.0[0]; n = -n; } else if d.is_negative() { - // The modified Jacobi symbols (x / |y|) and (x / |-y|) are equal, so "t" is not updated + // The modified Jacobi symbols (x / |y|) and (x / |-y|) are equal, so "t" is not + // updated d = -d; } } diff --git a/src/fft.rs b/src/fft.rs index 00eca39ae..729652557 100644 --- a/src/fft.rs +++ b/src/fft.rs @@ -1,7 +1,8 @@ -pub use crate::{CurveAffine, CurveExt}; use ff::Field; use group::{GroupOpsOwned, ScalarMulOwned}; +pub use crate::{CurveAffine, CurveExt}; + /// This represents an element of a group with basic operations that can be /// performed. This allows an FFT implementation (for example) to operate /// generically over either a field or elliptic curve group. diff --git a/src/grumpkin/curve.rs b/src/grumpkin/curve.rs index e212ad83b..e950673f5 100644 --- a/src/grumpkin/curve.rs +++ b/src/grumpkin/curve.rs @@ -1,25 +1,23 @@ -use crate::arithmetic::mul_512; -use crate::arithmetic::sbb; -use crate::arithmetic::CurveEndo; -use crate::arithmetic::EndoParameters; -use crate::ff::WithSmallOrderMulGroup; -use crate::ff::{Field, PrimeField}; -use crate::group::Curve; -use crate::group::{prime::PrimeCurveAffine, Group, GroupEncoding}; -use crate::grumpkin::Fq; -use crate::grumpkin::Fr; -use crate::{ - endo, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, new_curve_impl, +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, }; -use crate::{Coordinates, CurveAffine, CurveExt}; -use core::cmp; -use core::fmt::Debug; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; + use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use crate::{ + arithmetic::{mul_512, sbb, CurveEndo, EndoParameters}, + endo, + ff::{Field, PrimeField, WithSmallOrderMulGroup}, + group::{prime::PrimeCurveAffine, Curve, Group, GroupEncoding}, + grumpkin::{Fq, Fr}, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, new_curve_impl, Coordinates, CurveAffine, CurveExt, +}; + new_curve_impl!( (pub), G1, @@ -95,8 +93,11 @@ impl G1 { #[cfg(test)] mod test { - use super::*; use group::UncompressedEncoding; + use rand_core::OsRng; + + use super::*; + use crate::serde::SerdeObject; crate::curve_testing_suite!(G1); crate::curve_testing_suite!(G1, "endo_consistency"); crate::curve_testing_suite!(G1, "endo"); diff --git a/src/grumpkin/mod.rs b/src/grumpkin/mod.rs index eb972244f..58a191c63 100644 --- a/src/grumpkin/mod.rs +++ b/src/grumpkin/mod.rs @@ -1,4 +1,5 @@ mod curve; -pub use crate::bn256::{Fq as Fr, Fr as Fq}; pub use curve::*; + +pub use crate::bn256::{Fq as Fr, Fr as Fq}; diff --git a/src/hash_to_curve.rs b/src/hash_to_curve.rs index e4c287c16..add8488fa 100644 --- a/src/hash_to_curve.rs +++ b/src/hash_to_curve.rs @@ -1,17 +1,18 @@ #![allow(clippy::op_ref)] -use crate::ff_ext::Legendre; use digest::{core_api::BlockSizeUser, Digest}; use ff::{Field, FromUniformBytes, PrimeField}; -use pasta_curves::arithmetic::CurveExt; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use crate::{ff_ext::Legendre, CurveExt}; + pub enum Method { SSWU(Iso), SVDW, } -/// Map the homogeneous coordinates of a point from the isogenous curve to a point in the original curve. +/// Map the homogeneous coordinates of a point from the isogenous curve to a +/// point in the original curve. #[allow(clippy::type_complexity)] pub struct Iso { pub(crate) a: C::Base, @@ -101,8 +102,8 @@ where C::Base: Legendre + FromUniformBytes, { pub(crate) fn new(domain: &[u8], z: C::Base, method: Method) -> Self { - // Check for the target bits of security `k`. Currently, the target security is 128 bits. - // See: + // Check for the target bits of security `k`. Currently, the target security is + // 128 bits. See: assert!((C::Base::NUM_BITS as usize + 128) / 8 <= L); let map_to_curve: Box C> = match method { @@ -202,8 +203,8 @@ where // Since z is non-square, a and b are either both zero (and both square), or // only one of them is square. We can therefore choose the square root to return - // based on whether a is square, but for the boolean output we need to handle the - // num != 0 && div == 0 case specifically. + // based on whether a is square, but for the boolean output we need to handle + // the num != 0 && div == 0 case specifically. let a = div.invert().unwrap_or(F::ZERO) * num; let b = a * z; @@ -224,61 +225,62 @@ where ) } - //1. tv1 = u^2 + // 1. tv1 = u^2 let tv1 = u.square(); - //2. tv1 = Z * tv1 + // 2. tv1 = Z * tv1 let tv1 = z * tv1; - //3. tv2 = tv1^2 + // 3. tv2 = tv1^2 let tv2 = tv1.square(); - //4. tv2 = tv2 + tv1 + // 4. tv2 = tv2 + tv1 let tv2 = tv2 + tv1; - //5. tv3 = tv2 + 1 + // 5. tv3 = tv2 + 1 let tv3 = tv2 + C::Base::ONE; - //6. tv3 = B * tv3 + // 6. tv3 = B * tv3 let tv3 = b * tv3; - //7. tv4 = CMOV(Z, -tv2, tv2 != 0) # tv4 = z if tv2 is 0 else tv4 = -tv2 + // 7. tv4 = CMOV(Z, -tv2, tv2 != 0) # tv4 = z if tv2 is 0 else tv4 = -tv2 let tv2_is_not_zero = !tv2.ct_eq(&C::Base::ZERO); let tv4 = C::Base::conditional_select(&z, &-tv2, tv2_is_not_zero); - //8. tv4 = A * tv4 + // 8. tv4 = A * tv4 let tv4 = a * tv4; - //9. tv2 = tv3^2 + // 9. tv2 = tv3^2 let tv2 = tv3.square(); - //10. tv6 = tv4^2 + // 10. tv6 = tv4^2 let tv6 = tv4.square(); - //11. tv5 = A * tv6 + // 11. tv5 = A * tv6 let tv5 = a * tv6; - //12. tv2 = tv2 + tv5 + // 12. tv2 = tv2 + tv5 let tv2 = tv2 + tv5; - //13. tv2 = tv2 * tv3 + // 13. tv2 = tv2 * tv3 let tv2 = tv2 * tv3; - //14. tv6 = tv6 * tv4 + // 14. tv6 = tv6 * tv4 let tv6 = tv6 * tv4; - //15. tv5 = B * tv6 + // 15. tv5 = B * tv6 let tv5 = b * tv6; - //16. tv2 = tv2 + tv5 + // 16. tv2 = tv2 + tv5 let tv2 = tv2 + tv5; - //17. x = tv1 * tv3 + // 17. x = tv1 * tv3 let x = tv1 * tv3; - //18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) + // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6) let (is_gx1_square, y1) = sqrt_ratio(&tv2, &tv6, &z); - //19. y = tv1 * u + // 19. y = tv1 * u let y = tv1 * u; - //20. y = y * y1 + // 20. y = y * y1 let y = y * y1; - //21. x = CMOV(x, tv3, is_gx1_square) + // 21. x = CMOV(x, tv3, is_gx1_square) let x = C::Base::conditional_select(&x, &tv3, is_gx1_square); - //22. y = CMOV(y, y1, is_gx1_square) + // 22. y = CMOV(y, y1, is_gx1_square) let y = C::Base::conditional_select(&y, &y1, is_gx1_square); - //23. e1 = sgn0(u) == sgn0(y) + // 23. e1 = sgn0(u) == sgn0(y) let e1 = u.is_odd().ct_eq(&y.is_odd()); - //24. y = CMOV(-y, y, e1) # Select correct sign of y + // 24. y = CMOV(-y, y, e1) # Select correct sign of y let y = C::Base::conditional_select(&-y, &y, e1); // In the original algorithm: - // 25. x = x / tv4 + // 25. x = x / tv4 // 26. return (x, y) // - // we omit instruction 25. and return the result in homogeneous coordinates (instead of the previous jacobi). + // we omit instruction 25. and return the result in homogeneous coordinates + // (instead of the previous jacobi). (x, y * tv4, tv4) } @@ -377,11 +379,12 @@ where #[cfg(test)] mod test { - use super::*; - use sha2::Sha256; - use sha2::Sha512; use std::marker::PhantomData; + use sha2::{Sha256, Sha512}; + + use super::*; + #[test] fn test_expand_message() { // Test vectors are taken from: diff --git a/src/lib.rs b/src/lib.rs index f5caae2d4..35b2beca4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ mod arithmetic; +mod curve; pub mod ff_ext; pub mod fft; pub mod hash_to_curve; @@ -18,10 +19,10 @@ pub mod secq256k1; mod derive; // Re-export to simplify downstream dependencies. +pub use curve::{Coordinates, CurveAffine, CurveExt}; pub use ff; pub use group; pub use pairing; -pub use pasta_curves::arithmetic::{Coordinates, CurveAffine, CurveExt}; #[cfg(test)] pub mod tests; diff --git a/src/msm.rs b/src/msm.rs index 615bcb5f2..98ef865e3 100644 --- a/src/msm.rs +++ b/src/msm.rs @@ -1,20 +1,21 @@ use std::ops::Neg; -use crate::CurveAffine; -use ff::Field; -use ff::PrimeField; +use ff::{Field, PrimeField}; use group::Group; use rayon::iter::{ IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, }; +use crate::CurveAffine; + const BATCH_SIZE: usize = 64; fn get_booth_index(window_index: usize, window_size: usize, el: &[u8]) -> i32 { // Booth encoding: // * step by `window` size // * slice by size of `window + 1`` - // * each window overlap by 1 bit * append a zero bit to the least significant end + // * each window overlap by 1 bit * append a zero bit to the least significant + // end // Indexing rule for example window size 3 where we slice by 4 bits: // `[0, +1, +1, +2, +2, +3, +3, +4, -4, -3, -3 -2, -2, -1, -1, 0]`` // So we can reduce the bucket size without preprocessing scalars @@ -344,8 +345,8 @@ pub fn msm_serial(coeffs: &[C::Scalar], bases: &[C], acc: &mut C }; let field_byte_size = C::Scalar::NUM_BITS.div_ceil(8u32) as usize; - // OR all coefficients in order to make a mask to figure out the maximum number of bytes used - // among all coefficients. + // OR all coefficients in order to make a mask to figure out the maximum number + // of bytes used among all coefficients. let mut acc_or = vec![0; field_byte_size]; for coeff in &coeffs { for (acc_limb, limb) in acc_or.iter_mut().zip(coeff.as_ref().iter()) { @@ -536,13 +537,16 @@ pub fn msm_best(coeffs: &[C::Scalar], bases: &[C]) -> C::Curve { mod test { use std::ops::Neg; - use crate::bn256::{Fr, G1Affine, G1}; use ark_std::{end_timer, start_timer}; use ff::{Field, PrimeField}; use group::{Curve, Group}; - use pasta_curves::arithmetic::CurveAffine; use rand_core::OsRng; + use crate::{ + bn256::{Fr, G1Affine, G1}, + CurveAffine, + }; + #[test] fn test_booth_encoding() { fn mul(scalar: &Fr, point: &G1Affine, window: usize) -> G1Affine { diff --git a/src/pasta/curve.rs b/src/pasta/curve.rs new file mode 100644 index 000000000..8dd48b94b --- /dev/null +++ b/src/pasta/curve.rs @@ -0,0 +1,78 @@ +use std::convert::TryInto; + +use ff::{PrimeField, WithSmallOrderMulGroup}; + +use super::{fp::Fp, fq::Fq, Pallas, Vesta}; +use crate::{ + arithmetic::{mul_512, sbb, CurveEndo, EndoParameters}, + endo, +}; + +// Generated using https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/utils.go +// with `pasta_curves::Fp::ZETA` +// See https://github.com/demining/Endomorphism-Secp256k1/blob/main/README.md +// to have more details about the endomorphism. +const ENDO_PARAMS_EQ: EndoParameters = EndoParameters { + // round(b2/n) + gamma1: [0x32c49e4c00000003, 0x279a745902a2654e, 0x1, 0x0], + // round(-b1/n) + gamma2: [0x31f0256800000002, 0x4f34e8b2066389a4, 0x2, 0x0], + b1: [0x8cb1279300000001, 0x49e69d1640a89953, 0x0, 0x0], + b2: [0x0c7c095a00000001, 0x93cd3a2c8198e269, 0x0, 0x0], +}; + +// Generated using https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/utils.go +// with `pasta_curves::Fq::ZETA` +// See https://github.com/demining/Endomorphism-Secp256k1/blob/main/README.md +// to have more details about the endomorphism. +const ENDO_PARAMS_EP: EndoParameters = EndoParameters { + // round(b2/n) + gamma1: [0x32c49e4bffffffff, 0x279a745902a2654e, 0x1, 0x0], + // round(-b1/n) + gamma2: [0x31f0256800000002, 0x4f34e8b2066389a4, 0x2, 0x0], + b1: [0x8cb1279300000000, 0x49e69d1640a89953, 0x0, 0x0], + b2: [0x0c7c095a00000001, 0x93cd3a2c8198e269, 0x0, 0x0], +}; + +endo!(Vesta, Fp, ENDO_PARAMS_EQ); +endo!(Pallas, Fq, ENDO_PARAMS_EP); + +#[cfg(test)] +mod test { + use rand_core::OsRng; + + use super::*; + + #[test] + fn test_endo() { + use ff::Field; + + for _ in 0..100000 { + let k = Fp::random(OsRng); + let (k1, k1_neg, k2, k2_neg) = Vesta::decompose_scalar(&k); + if k1_neg & k2_neg { + assert_eq!(k, -Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2)) + } else if k1_neg { + assert_eq!(k, -Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2)) + } else if k2_neg { + assert_eq!(k, Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2)) + } else { + assert_eq!(k, Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2)) + } + } + + for _ in 0..100000 { + let k = Fp::random(OsRng); + let (k1, k1_neg, k2, k2_neg) = Vesta::decompose_scalar(&k); + if k1_neg & k2_neg { + assert_eq!(k, -Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2)) + } else if k1_neg { + assert_eq!(k, -Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2)) + } else if k2_neg { + assert_eq!(k, Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2)) + } else { + assert_eq!(k, Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2)) + } + } + } +} diff --git a/src/pasta/fp.rs b/src/pasta/fp.rs new file mode 100644 index 000000000..6735c32f5 --- /dev/null +++ b/src/pasta/fp.rs @@ -0,0 +1,30 @@ +use std::convert::TryInto; + +use halo2derive::impl_field; +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use crate::{ + extend_field_legendre, field_bits, impl_binops_additive, impl_binops_calls, + impl_binops_multiplicative, impl_from_bool, impl_from_u64, serialize_deserialize_primefield, +}; + +// Fp: Pasta base field and Vesta scalar field. +impl_field!( + pasta_base, + Fp, + modulus = "40000000000000000000000000000000224698fc094cf91b992d30ed00000001", + mul_gen = "5", + zeta = "12ccca834acdba712caad5dc57aab1b01d1f8bd237ad31491dad5ebdfdfe4ab9", + from_uniform = [48, 64], + endian = "little", +); + +extend_field_legendre!(Fp); +impl_binops_calls!(Fp); +impl_binops_additive!(Fp, Fp); +impl_binops_multiplicative!(Fp, Fp); +impl_from_u64!(Fp); +impl_from_bool!(Fp); +field_bits!(Fp); +serialize_deserialize_primefield!(Fp); diff --git a/src/pasta/fq.rs b/src/pasta/fq.rs new file mode 100644 index 000000000..a06e25923 --- /dev/null +++ b/src/pasta/fq.rs @@ -0,0 +1,30 @@ +use std::convert::TryInto; + +use halo2derive::impl_field; +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use crate::{ + extend_field_legendre, field_bits, impl_binops_additive, impl_binops_calls, + impl_binops_multiplicative, impl_from_bool, impl_from_u64, serialize_deserialize_primefield, +}; + +// Fq: Vesta base field and Pasta scalar field. +impl_field!( + vesta_base, + Fq, + modulus = "40000000000000000000000000000000224698fc0994a8dd8c46eb2100000001", + mul_gen = "5", + zeta = "06819a58283e528e511db4d81cf70f5a0fed467d47c033af2aa9d2e050aa0e4f", + from_uniform = [48, 64], + endian = "little", +); + +extend_field_legendre!(Fq); +impl_binops_calls!(Fq); +impl_binops_additive!(Fq, Fq); +impl_binops_multiplicative!(Fq, Fq); +impl_from_u64!(Fq); +impl_from_bool!(Fq); +field_bits!(Fq); +serialize_deserialize_primefield!(Fq); diff --git a/src/pasta/mod.rs b/src/pasta/mod.rs index 164697b5a..54a43573a 100644 --- a/src/pasta/mod.rs +++ b/src/pasta/mod.rs @@ -1,73 +1,10 @@ -use crate::arithmetic::mul_512; -use crate::arithmetic::sbb; -use crate::{ - arithmetic::{CurveEndo, EndoParameters}, - endo, -}; -use ff::PrimeField; -use ff::WithSmallOrderMulGroup; -pub use pasta_curves::{pallas, vesta, Ep, EpAffine, Eq, EqAffine, Fp, Fq}; -use std::convert::TryInto; - -// Generated using https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/utils.go -// with `pasta_curves::Fp::ZETA` -// See https://github.com/demining/Endomorphism-Secp256k1/blob/main/README.md -// to have more details about the endomorphism. -const ENDO_PARAMS_EQ: EndoParameters = EndoParameters { - // round(b2/n) - gamma1: [0x32c49e4c00000003, 0x279a745902a2654e, 0x1, 0x0], - // round(-b1/n) - gamma2: [0x31f0256800000002, 0x4f34e8b2066389a4, 0x2, 0x0], - b1: [0x8cb1279300000001, 0x49e69d1640a89953, 0x0, 0x0], - b2: [0x0c7c095a00000001, 0x93cd3a2c8198e269, 0x0, 0x0], -}; - -// Generated using https://github.com/ConsenSys/gnark-crypto/blob/master/ecc/utils.go -// with `pasta_curves::Fq::ZETA` -// See https://github.com/demining/Endomorphism-Secp256k1/blob/main/README.md -// to have more details about the endomorphism. -const ENDO_PARAMS_EP: EndoParameters = EndoParameters { - // round(b2/n) - gamma1: [0x32c49e4bffffffff, 0x279a745902a2654e, 0x1, 0x0], - // round(-b1/n) - gamma2: [0x31f0256800000002, 0x4f34e8b2066389a4, 0x2, 0x0], - b1: [0x8cb1279300000000, 0x49e69d1640a89953, 0x0, 0x0], - b2: [0x0c7c095a00000001, 0x93cd3a2c8198e269, 0x0, 0x0], -}; - -endo!(Eq, Fp, ENDO_PARAMS_EQ); -endo!(Ep, Fq, ENDO_PARAMS_EP); - -#[test] -fn test_endo() { - use ff::Field; - use rand_core::OsRng; - - for _ in 0..100000 { - let k = Fp::random(OsRng); - let (k1, k1_neg, k2, k2_neg) = Eq::decompose_scalar(&k); - if k1_neg & k2_neg { - assert_eq!(k, -Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2)) - } else if k1_neg { - assert_eq!(k, -Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2)) - } else if k2_neg { - assert_eq!(k, Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2)) - } else { - assert_eq!(k, Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2)) - } - } - - for _ in 0..100000 { - let k = Fp::random(OsRng); - let (k1, k1_neg, k2, k2_neg) = Eq::decompose_scalar(&k); - if k1_neg & k2_neg { - assert_eq!(k, -Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2)) - } else if k1_neg { - assert_eq!(k, -Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2)) - } else if k2_neg { - assert_eq!(k, Fp::from_u128(k1) + Fp::ZETA * Fp::from_u128(k2)) - } else { - assert_eq!(k, Fp::from_u128(k1) - Fp::ZETA * Fp::from_u128(k2)) - } - } -} +mod curve; +mod fp; +mod fq; +mod pallas; +mod vesta; + +pub use fp::*; +pub use fq::*; +pub use pallas::*; +pub use vesta::*; diff --git a/src/pasta/pallas.rs b/src/pasta/pallas.rs new file mode 100644 index 000000000..9332e7a41 --- /dev/null +++ b/src/pasta/pallas.rs @@ -0,0 +1,91 @@ +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; + +use ff::{Field, PrimeField, WithSmallOrderMulGroup}; +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use super::{fp::Fp, fq::Fq}; +use crate::{ + group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Curve, Group, GroupEncoding}, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, new_curve_impl, Coordinates, CurveAffine, CurveExt, +}; + +new_curve_impl!( + (pub), + Pallas, + PastaAffine, + Fp, + Fq, + (- Fp::ONE, Fp::from_raw([2,0,0,0])), + Fp::ZERO, + Fp::from_raw([5,0,0,0]), + "pasta", + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, Pallas::default_hash_to_curve_suite()), + crate::serde::CompressedFlagConfig::SingleSpare, + standard_sign +); + +impl CofactorGroup for Pallas { + type Subgroup = Pallas; + + fn clear_cofactor(&self) -> Self { + *self + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(self, 1.into()) + } + + fn is_torsion_free(&self) -> Choice { + 1.into() + } +} + +impl Pallas { + /// Z = -13 + pub const SVDW_Z: Fp = Fp::from_raw([ + 0x992d30ecfffffff4, + 0x224698fc094cf91b, + 0x0000000000000000, + 0x4000000000000000, + ]); + + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"pallas:SHA-256_SVDW_RO_", + Self::SVDW_Z, + crate::hash_to_curve::Method::SVDW, + ) + } +} + +#[cfg(test)] +mod test { + + use group::UncompressedEncoding; + use rand_core::OsRng; + + use super::*; + use crate::{curve_testing_suite, serde::SerdeObject}; + + curve_testing_suite!( + Pallas, + "constants", + Fp::MODULUS, + Fp::ZERO, + Fp::from_raw([5, 0, 0, 0]), + -Fp::ONE, + Fp::from_raw([2, 0, 0, 0]), + Fq::MODULUS + ); + + curve_testing_suite!(Pallas); + curve_testing_suite!(Pallas, "endo_consistency"); + curve_testing_suite!(Pallas, "ecdsa_example"); +} diff --git a/src/pasta/vesta.rs b/src/pasta/vesta.rs new file mode 100644 index 000000000..13603eacd --- /dev/null +++ b/src/pasta/vesta.rs @@ -0,0 +1,91 @@ +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; + +use ff::{Field, PrimeField, WithSmallOrderMulGroup}; +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + +use super::{fp::Fp, fq::Fq}; +use crate::{ + group::{cofactor::CofactorGroup, prime::PrimeCurveAffine, Curve, Group, GroupEncoding}, + impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, + impl_binops_multiplicative_mixed, new_curve_impl, Coordinates, CurveAffine, CurveExt, +}; + +new_curve_impl!( + (pub), + Vesta, + VestaAffine, + Fq, + Fp, + (- Fq::ONE, Fq::from_raw([2,0,0,0])), + Fq::ZERO,// Curve a parameter + Fq::from_raw([5,0,0,0]),// Curve b parameter + "vesta", + |domain_prefix| crate::hash_to_curve::hash_to_curve(domain_prefix, Vesta::default_hash_to_curve_suite()), + crate::serde::CompressedFlagConfig::SingleSpare, + standard_sign +); + +// NOTE: Temporary impl to satisfy macro requirements + +impl CofactorGroup for Vesta { + type Subgroup = Vesta; + + fn clear_cofactor(&self) -> Self { + *self + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(self, 1.into()) + } + + fn is_torsion_free(&self) -> Choice { + 1.into() + } +} + +impl Vesta { + /// Z = -13 + pub const SVDW_Z: Fq = Fq::from_raw([ + 0x8c46eb20fffffff4, + 0x224698fc0994a8dd, + 0x0000000000000000, + 0x4000000000000000, + ]); + fn default_hash_to_curve_suite() -> crate::hash_to_curve::Suite { + crate::hash_to_curve::Suite::::new( + b"vesta:SHA-256_SVDW_RO_", + Self::SVDW_Z, + crate::hash_to_curve::Method::SVDW, + ) + } +} + +#[cfg(test)] +mod test { + use group::UncompressedEncoding; + use rand_core::OsRng; + + use super::*; + use crate::{curve_testing_suite, serde::SerdeObject}; + + curve_testing_suite!( + Vesta, + "constants", + Fq::MODULUS, + Fq::ZERO, + Fq::from_raw([5, 0, 0, 0]), + -Fq::ONE, + Fq::from_raw([2, 0, 0, 0]), + Fp::MODULUS + ); + + curve_testing_suite!(Vesta); + curve_testing_suite!(Vesta, "endo_consistency"); + curve_testing_suite!(Vesta, "ecdsa_example"); +} diff --git a/src/pluto_eris/curve.rs b/src/pluto_eris/curve.rs index e0452a942..cbe3b7c03 100644 --- a/src/pluto_eris/curve.rs +++ b/src/pluto_eris/curve.rs @@ -1,19 +1,20 @@ -use super::{fp::Fp, fp2::Fp2, fq::Fq}; -use crate::ff::WithSmallOrderMulGroup; -use crate::ff::{Field, PrimeField}; -use crate::group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}; -use crate::{Coordinates, CurveAffine, CurveExt}; -use core::cmp; -use core::fmt::Debug; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; + use group::cofactor::CofactorGroup; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use super::{fp::Fp, fp2::Fp2, fq::Fq}; use crate::{ + ff::{Field, PrimeField, WithSmallOrderMulGroup}, + group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, - impl_binops_multiplicative_mixed, new_curve_impl, + impl_binops_multiplicative_mixed, new_curve_impl, Coordinates, CurveAffine, CurveExt, }; const G1_GENERATOR_X: Fp = Fp::from_raw([ @@ -271,8 +272,11 @@ new_curve_impl!( #[cfg(test)] mod test { - use super::*; use group::UncompressedEncoding; + use rand_core::OsRng; + + use super::*; + use crate::serde::SerdeObject; crate::curve_testing_suite!(G2, "clear_cofactor"); crate::curve_testing_suite!(G1, Eris, G2); diff --git a/src/pluto_eris/engine.rs b/src/pluto_eris/engine.rs index 4975c424b..5e78d1d87 100644 --- a/src/pluto_eris/engine.rs +++ b/src/pluto_eris/engine.rs @@ -1,25 +1,24 @@ #![allow(clippy::suspicious_arithmetic_impl)] -use crate::ff::PrimeField; -use crate::ff_ext::quadratic::QuadSparseMul; -use crate::ff_ext::ExtField; -use crate::group::cofactor::CofactorCurveAffine; -use crate::group::Group; -use crate::pluto_eris::curve::*; -use crate::pluto_eris::fp::*; -use crate::pluto_eris::fp12::*; -use crate::pluto_eris::fp2::*; -use crate::pluto_eris::fp6::FROBENIUS_COEFF_FP6_C1; -use crate::pluto_eris::fq::Fq; -use core::borrow::Borrow; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; +use core::{ + borrow::Borrow, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; +use std::ops::MulAssign; + use ff::Field; use pairing::{Engine, MillerLoopResult, MultiMillerLoop, PairingCurveAffine}; use rand_core::RngCore; -use std::ops::MulAssign; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq}; +use crate::{ + ff::PrimeField, + ff_ext::{quadratic::QuadSparseMul, ExtField}, + group::{cofactor::CofactorCurveAffine, Group}, + pluto_eris::{curve::*, fp::*, fp12::*, fp2::*, fp6::FROBENIUS_COEFF_FP6_C1, fq::Fq}, +}; + /// Adaptation of Algorithm 1, https://eprint.iacr.org/2013/722.pdf /// the parameter for the curve Pluto: u = -0x4000000000001000008780000000 const NEG_PLUTO_U: u128 = 0x4000000000001000008780000000; @@ -230,11 +229,14 @@ fn ell(f: &mut Fp12, coeffs: &(Fp2, Fp2, Fp2), p: &G1Affine) { #[cfg(test)] mod test { - use super::super::{Fq, Pluto, G1, G2}; - use super::{multi_miller_loop, Fp12, G1Affine, G2Affine, Gt}; use ff::Field; use group::{prime::PrimeCurveAffine, Curve, Group}; use pairing::{Engine, MillerLoopResult, PairingCurveAffine}; use rand_core::OsRng; + + use super::{ + super::{Fq, Pluto, G1, G2}, + multi_miller_loop, Fp12, G1Affine, G2Affine, Gt, + }; crate::test_pairing!(Pluto, G1, G1Affine, G2, G2Affine, Fp12, Gt, Fq); } diff --git a/src/pluto_eris/fp.rs b/src/pluto_eris/fp.rs index 7f85ef46f..b712e69de 100644 --- a/src/pluto_eris/fp.rs +++ b/src/pluto_eris/fp.rs @@ -1,9 +1,11 @@ -use crate::ff_ext::ExtField; use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use crate::ff_ext::ExtField; + impl_field!( pluto_eris_fp, Fp, diff --git a/src/pluto_eris/fp12.rs b/src/pluto_eris/fp12.rs index 31a7776fa..b792e31c7 100644 --- a/src/pluto_eris/fp12.rs +++ b/src/pluto_eris/fp12.rs @@ -1,11 +1,10 @@ -use super::fp::Fp; -use super::fp2::Fp2; -use super::fp6::Fp6; +use ff::Field; + +use super::{fp::Fp, fp2::Fp2, fp6::Fp6}; use crate::ff_ext::{ quadratic::{QuadExtField, QuadExtFieldArith, QuadSparseMul}, ExtField, }; -use ff::Field; /// -GAMMA is a quadratic non-residue in Fp6. Fp12 = Fp6[X]/(X^2 + GAMMA) /// We introduce the variable w such that w^2 = -GAMMA @@ -267,11 +266,12 @@ mod test { } }; } - use super::*; - use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; use ff::Field; use rand::RngCore; + use super::*; + use crate::{arith_test, frobenius_test, setup_f12_test_funcs, test}; + arith_test!(Fp12); // F12 specific diff --git a/src/pluto_eris/fp2.rs b/src/pluto_eris/fp2.rs index a3f64b4ad..d0a661f4d 100644 --- a/src/pluto_eris/fp2.rs +++ b/src/pluto_eris/fp2.rs @@ -1,12 +1,17 @@ -use super::fp::Fp; -use crate::ff::FromUniformBytes; -use crate::ff::{Field, PrimeField, WithSmallOrderMulGroup}; -use crate::ff_ext::quadratic::{QuadExtField, QuadExtFieldArith, SQRT}; -use crate::ff_ext::{ExtField, Legendre}; use core::convert::TryInto; use std::cmp::Ordering; + use subtle::{Choice, CtOption}; +use super::fp::Fp; +use crate::{ + ff::{Field, FromUniformBytes, PrimeField, WithSmallOrderMulGroup}, + ff_ext::{ + quadratic::{QuadExtField, QuadExtFieldArith, SQRT}, + ExtField, Legendre, + }, +}; + crate::impl_binops_additive!(Fp2, Fp2); crate::impl_binops_multiplicative!(Fp2, Fp2); crate::impl_binops_calls!(Fp2); @@ -79,9 +84,10 @@ impl ExtField for Fp2 { #[cfg(test)] mod test { + use rand_core::RngCore; + use super::*; use crate::{arith_test, constants_test, legendre_test, serde_test, test}; - use rand_core::RngCore; constants_test!(Fp2); diff --git a/src/pluto_eris/fp6.rs b/src/pluto_eris/fp6.rs index 9b8df7db2..1baaa2d7c 100644 --- a/src/pluto_eris/fp6.rs +++ b/src/pluto_eris/fp6.rs @@ -1,10 +1,10 @@ -use super::fp::Fp; -use super::fp2::Fp2; +use ff::Field; + +use super::{fp::Fp, fp2::Fp2}; use crate::ff_ext::{ cubic::{CubicExtField, CubicExtFieldArith, CubicSparseMul}, ExtField, }; -use ff::Field; // -BETA is a cubic non-residue in Fp2. Fp6 = Fp2[X]/(X^3 + BETA) // We introduce the variable v such that v^3 = -BETA @@ -42,7 +42,8 @@ impl ExtField for Fp6 { } } -/// Fp2 coefficients for the efficient computation of Frobenius Endomorphism in Fp6. +/// Fp2 coefficients for the efficient computation of Frobenius Endomorphism in +/// Fp6. pub(crate) const FROBENIUS_COEFF_FP6_C1: [Fp2; 6] = [ // Fp2(v^3)**(((p^0) - 1) / 3) Fp2::ONE, @@ -145,7 +146,8 @@ pub(crate) const FROBENIUS_COEFF_FP6_C1: [Fp2; 6] = [ }, ]; -/// Fp2 coefficients for the efficient computation of Frobenius Endomorphism in Fp6. +/// Fp2 coefficients for the efficient computation of Frobenius Endomorphism in +/// Fp6. pub(crate) const FROBENIUS_COEFF_FP6_C2: [Fp2; 6] = [ // Fp2(v^3)**(((2p^0) - 2) / 3) Fp2::ONE, @@ -250,9 +252,10 @@ pub(crate) const FROBENIUS_COEFF_FP6_C2: [Fp2; 6] = [ #[cfg(test)] mod test { + use rand_core::RngCore; + use super::*; use crate::{arith_test, frobenius_test, setup_f6_test_funcs, test}; - use rand_core::RngCore; macro_rules! test_fp6 { ($test:ident, $size: expr) => { diff --git a/src/pluto_eris/fq.rs b/src/pluto_eris/fq.rs index f17175768..cdddb24fc 100644 --- a/src/pluto_eris/fq.rs +++ b/src/pluto_eris/fq.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; diff --git a/src/pluto_eris/mod.rs b/src/pluto_eris/mod.rs index 0d0538ab6..b5bd0c278 100644 --- a/src/pluto_eris/mod.rs +++ b/src/pluto_eris/mod.rs @@ -1,6 +1,7 @@ //! # `Pluto\Eris half-pairing cycle` //! -//! Implementation of the Pluto / Eris half-pairing cycle of prime order elliptic curves. +//! Implementation of the Pluto / Eris half-pairing cycle of prime order +//! elliptic curves. //! //! Supporting evidence: https://github.com/daira/pluto-eris //! Field constant derivation: https://github.com/davidnevadoc/ec-constants/tree/main/pluto_eris diff --git a/src/secp256k1/curve.rs b/src/secp256k1/curve.rs index 6214cad83..806a5c275 100644 --- a/src/secp256k1/curve.rs +++ b/src/secp256k1/curve.rs @@ -1,19 +1,20 @@ -use crate::ff::WithSmallOrderMulGroup; -use crate::ff::{Field, PrimeField}; -use crate::group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}; -use crate::secp256k1::Fp; -use crate::secp256k1::Fq; -use crate::{Coordinates, CurveAffine, CurveExt}; -use core::cmp; -use core::fmt::Debug; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; + use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; use crate::{ + ff::{Field, PrimeField, WithSmallOrderMulGroup}, + group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, impl_binops_multiplicative_mixed, new_curve_impl, + secp256k1::{Fp, Fq}, + Coordinates, CurveAffine, CurveExt, }; impl group::cofactor::CofactorGroup for Secp256k1 { @@ -221,10 +222,12 @@ pub(crate) fn iso_map(x: Fp, y: Fp, z: Fp) -> Secp256k1 { #[cfg(test)] mod test { - use crate::tests::curve::TestH2C; + use group::UncompressedEncoding; + use rand_core::OsRng; use super::*; - use group::UncompressedEncoding; + use crate::{serde::SerdeObject, tests::curve::TestH2C}; + crate::curve_testing_suite!(Secp256k1); crate::curve_testing_suite!(Secp256k1, "endo_consistency"); crate::curve_testing_suite!(Secp256k1, "ecdsa_example"); diff --git a/src/secp256k1/fp.rs b/src/secp256k1/fp.rs index 8f036576b..7f621965e 100644 --- a/src/secp256k1/fp.rs +++ b/src/secp256k1/fp.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; diff --git a/src/secp256k1/fq.rs b/src/secp256k1/fq.rs index 037d51f00..09238482a 100644 --- a/src/secp256k1/fq.rs +++ b/src/secp256k1/fq.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; diff --git a/src/secp256r1/curve.rs b/src/secp256r1/curve.rs index 44486c1d3..e7e3f1a5f 100644 --- a/src/secp256r1/curve.rs +++ b/src/secp256r1/curve.rs @@ -1,16 +1,20 @@ -use crate::ff::WithSmallOrderMulGroup; -use crate::ff::{Field, PrimeField}; -use crate::group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}; -use crate::secp256r1::Fp; -use crate::secp256r1::Fq; -use crate::{Coordinates, CurveAffine, CurveExt}; -use core::cmp; -use core::fmt::Debug; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; + use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; +use crate::{ + ff::{Field, PrimeField, WithSmallOrderMulGroup}, + group::{prime::PrimeCurveAffine, Curve, Group as _, GroupEncoding}, + secp256r1::{Fp, Fq}, + Coordinates, CurveAffine, CurveExt, +}; + impl group::cofactor::CofactorGroup for Secp256r1 { type Subgroup = Secp256r1; @@ -105,10 +109,11 @@ pub(crate) fn hash_to_curve<'a>( #[cfg(test)] mod test { - use crate::tests::curve::TestH2C; + use group::UncompressedEncoding; + use rand_core::OsRng; use super::*; - use group::UncompressedEncoding; + use crate::{serde::SerdeObject, tests::curve::TestH2C}; crate::curve_testing_suite!(Secp256r1); crate::curve_testing_suite!(Secp256r1, "ecdsa_example"); crate::curve_testing_suite!( diff --git a/src/secp256r1/fp.rs b/src/secp256r1/fp.rs index ce423d5d6..6de4542a5 100644 --- a/src/secp256r1/fp.rs +++ b/src/secp256r1/fp.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; diff --git a/src/secp256r1/fq.rs b/src/secp256r1/fq.rs index 8e0c1071a..2cb9011a4 100644 --- a/src/secp256r1/fq.rs +++ b/src/secp256r1/fq.rs @@ -1,4 +1,5 @@ use core::convert::TryInto; + use halo2derive::impl_field; use rand::RngCore; use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; diff --git a/src/secq256k1/curve.rs b/src/secq256k1/curve.rs index f08b515d3..63f37c350 100644 --- a/src/secq256k1/curve.rs +++ b/src/secq256k1/curve.rs @@ -1,19 +1,21 @@ -use crate::ff::WithSmallOrderMulGroup; -use crate::ff::{Field, PrimeField}; -use crate::group::Curve; -use crate::group::{prime::PrimeCurveAffine, Group, GroupEncoding}; -use crate::secp256k1::{Fp, Fq}; +use core::{ + cmp, + fmt::Debug, + iter::Sum, + ops::{Add, Mul, Neg, Sub}, +}; + +use rand::RngCore; +use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; + use crate::{ + ff::{Field, PrimeField, WithSmallOrderMulGroup}, + group::{prime::PrimeCurveAffine, Curve, Group, GroupEncoding}, impl_binops_additive, impl_binops_additive_specify_output, impl_binops_multiplicative, impl_binops_multiplicative_mixed, new_curve_impl, + secp256k1::{Fp, Fq}, + Coordinates, CurveAffine, CurveExt, }; -use crate::{Coordinates, CurveAffine, CurveExt}; -use core::cmp; -use core::fmt::Debug; -use core::iter::Sum; -use core::ops::{Add, Mul, Neg, Sub}; -use rand::RngCore; -use subtle::{Choice, ConditionallySelectable, ConstantTimeEq, CtOption}; const SECQ_GENERATOR_X: Fq = Fq::from_raw([ 0xA24288E37702EDA6, @@ -77,8 +79,12 @@ impl Secq256k1 { #[cfg(test)] mod test { - use super::*; use group::UncompressedEncoding; + use rand_core::OsRng; + + use super::*; + use crate::serde::SerdeObject; + crate::curve_testing_suite!(Secq256k1); crate::curve_testing_suite!(Secq256k1, "endo_consistency"); crate::curve_testing_suite!( diff --git a/src/secq256k1/mod.rs b/src/secq256k1/mod.rs index b9a6127f3..cf6e3a91e 100644 --- a/src/secq256k1/mod.rs +++ b/src/secq256k1/mod.rs @@ -1,4 +1,5 @@ mod curve; -pub use crate::secp256k1::{Fp as Fq, Fq as Fp}; pub use curve::*; + +pub use crate::secp256k1::{Fp as Fq, Fq as Fp}; diff --git a/src/serde.rs b/src/serde.rs index 13779934c..107589997 100644 --- a/src/serde.rs +++ b/src/serde.rs @@ -92,23 +92,26 @@ impl std::ops::IndexMut> for Repr { } } -/// Trait for converting raw bytes to/from the internal representation of a type. -/// For example, field elements are represented in Montgomery form and serialized/deserialized without Montgomery reduction. +/// Trait for converting raw bytes to/from the internal representation of a +/// type. For example, field elements are represented in Montgomery form and +/// serialized/deserialized without Montgomery reduction. pub trait SerdeObject: Sized { - /// The purpose of unchecked functions is to read the internal memory representation - /// of a type from bytes as quickly as possible. No sanitization checks are performed - /// to ensure the bytes represent a valid object. As such this function should only be - /// used internally as an extension of machine memory. It should not be used to deserialize + /// The purpose of unchecked functions is to read the internal memory + /// representation of a type from bytes as quickly as possible. No + /// sanitization checks are performed to ensure the bytes represent a + /// valid object. As such this function should only be used internally + /// as an extension of machine memory. It should not be used to deserialize /// externally provided data. fn from_raw_bytes_unchecked(bytes: &[u8]) -> Self; fn from_raw_bytes(bytes: &[u8]) -> Option; fn to_raw_bytes(&self) -> Vec; - /// The purpose of unchecked functions is to read the internal memory representation - /// of a type from disk as quickly as possible. No sanitization checks are performed - /// to ensure the bytes represent a valid object. This function should only be used - /// internally when some machine state cannot be kept in memory (e.g., between runs) + /// The purpose of unchecked functions is to read the internal memory + /// representation of a type from disk as quickly as possible. No + /// sanitization checks are performed to ensure the bytes represent a + /// valid object. This function should only be used internally when some + /// machine state cannot be kept in memory (e.g., between runs) /// and needs to be reloaded as quickly as possible. fn read_raw_unchecked(reader: &mut R) -> Self; fn read_raw(reader: &mut R) -> io::Result; @@ -175,7 +178,7 @@ pub(crate) enum CompressedFlagConfig { Extra, // sign: 0 identity: 1 // Pasta curves should be encoded with - // SingleSpare, // sign: 0 + SingleSpare, // sign: 0 // BN254 curve should be encoded with TwoSpare, // sign: 0, identity: 1 @@ -237,6 +240,7 @@ where fn pos_sign() -> u8 { match Self::CONFIG { CompressedFlagConfig::Extra => 0, + CompressedFlagConfig::SingleSpare => 0, CompressedFlagConfig::TwoSpare => 0, CompressedFlagConfig::ThreeSpare => 2, } @@ -252,6 +256,7 @@ where fn pos_idetity() -> Option { match Self::CONFIG { CompressedFlagConfig::Extra => Some(1), + CompressedFlagConfig::SingleSpare => None, CompressedFlagConfig::TwoSpare => Some(1), CompressedFlagConfig::ThreeSpare => Some(1), } diff --git a/src/tests/curve.rs b/src/tests/curve.rs index a482c9c0e..9d897bf39 100644 --- a/src/tests/curve.rs +++ b/src/tests/curve.rs @@ -343,11 +343,6 @@ macro_rules! curve_testing_suite { } } - use $crate::ff::Field; - use $crate::group::prime::PrimeCurveAffine; - use $crate::{group::GroupEncoding, serde::SerdeObject}; - use $crate::{CurveAffine, CurveExt}; - use rand_core::OsRng; #[test] @@ -540,9 +535,10 @@ macro_rules! curve_testing_suite { }; } -use crate::{CurveAffine, CurveExt}; use group::Curve; +use crate::{CurveAffine, CurveExt}; + pub(crate) struct TestH2C { msg: &'static [u8], expect: C, diff --git a/src/tests/field.rs b/src/tests/field.rs index 280d41311..b67e66767 100644 --- a/src/tests/field.rs +++ b/src/tests/field.rs @@ -19,9 +19,10 @@ macro_rules! test { ($mod: ident, $field:ident, $test:ident, $size:expr) => { #[test] fn $test() { - use super::*; use rand::SeedableRng; use rand_xorshift::XorShiftRng; + + use super::*; let mut rng = XorShiftRng::from_seed($crate::tests::SEED); $crate::tests::field::$mod::$test::<$field>(&mut rng, $size); } diff --git a/src/tests/field/legendre.rs b/src/tests/field/legendre.rs index ad65e4778..7b60627d0 100644 --- a/src/tests/field/legendre.rs +++ b/src/tests/field/legendre.rs @@ -1,7 +1,8 @@ -use crate::ff_ext::Legendre; use ff::PrimeField; use rand::RngCore; +use crate::ff_ext::Legendre; + pub(crate) fn legendre_symbol_test(mut rng: impl RngCore, n: usize) { assert_eq!(F::ZERO.legendre(), 0); for _ in 0..n { diff --git a/src/tests/mod.rs b/src/tests/mod.rs index 9673e0a53..d365e17d3 100644 --- a/src/tests/mod.rs +++ b/src/tests/mod.rs @@ -1,6 +1,7 @@ use ff::PrimeField; use num_bigint::BigUint; -use pasta_curves::arithmetic::CurveAffine; + +use crate::CurveAffine; pub mod curve; #[macro_use]