From 242a3fd7f023e0924a6b49263344614c178afdcc Mon Sep 17 00:00:00 2001 From: "Jason.Huang" Date: Wed, 5 Jun 2024 17:55:29 +0800 Subject: [PATCH] update ecgfp5 --- ecgfp5/Cargo.toml | 1 + ecgfp5/benches/curve.rs | 3 +- ecgfp5/benches/scalar.rs | 41 ++----- ecgfp5/examples/ecdsa_sig.rs | 6 +- ecgfp5/examples/point_add.rs | 6 +- ecgfp5/examples/scalar_mul.rs | 12 +-- ecgfp5/examples/schnorr_sig.rs | 6 +- ecgfp5/rustfmt.toml | 7 ++ ecgfp5/src/curve/base_field.rs | 3 +- ecgfp5/src/curve/curve.rs | 177 +++++++++++++++++-------------- ecgfp5/src/curve/scalar_field.rs | 109 ++++++++++++------- ecgfp5/src/gadgets/base_field.rs | 99 ++++++++--------- ecgfp5/src/gadgets/curve.rs | 42 ++++---- ecgfp5/src/gadgets/schnorr.rs | 14 ++- ecgfp5/src/gates/gfp5_mul.rs | 81 +++++--------- ecgfp5/src/macros.rs | 5 +- 16 files changed, 296 insertions(+), 316 deletions(-) create mode 100644 ecgfp5/rustfmt.toml diff --git a/ecgfp5/Cargo.toml b/ecgfp5/Cargo.toml index 4f92434521..5c1ea17249 100644 --- a/ecgfp5/Cargo.toml +++ b/ecgfp5/Cargo.toml @@ -25,6 +25,7 @@ num = "0.4" itertools = "0.10" serde = "1" rand = { version = "0.8.5", default-features = false, features = ["getrandom"] } +hex = "0.4.3" [dev-dependencies] rand = { version = "0.8.5", features = ["min_const_gen"] } diff --git a/ecgfp5/benches/curve.rs b/ecgfp5/benches/curve.rs index f2f29fd40a..10920e5407 100644 --- a/ecgfp5/benches/curve.rs +++ b/ecgfp5/benches/curve.rs @@ -1,6 +1,5 @@ use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; -use plonky2_ecgfp5::curve::curve::Point; -use plonky2_ecgfp5::curve::scalar_field::Scalar; +use plonky2_ecgfp5::curve::{curve::Point, scalar_field::Scalar}; use plonky2_field::types::Sample; pub fn bench_curve(c: &mut Criterion) { diff --git a/ecgfp5/benches/scalar.rs b/ecgfp5/benches/scalar.rs index e671ce5d60..f697483007 100644 --- a/ecgfp5/benches/scalar.rs +++ b/ecgfp5/benches/scalar.rs @@ -23,11 +23,7 @@ pub fn bench_scalar(c: &mut Criterion) { }); c.bench_function("square", |b| { - b.iter_batched( - || Scalar::rand(), - |x| black_box(x.square()), - BatchSize::SmallInput, - ) + b.iter_batched(|| Scalar::rand(), |x| black_box(x.square()), BatchSize::SmallInput) }); c.bench_function("try_inverse", |b| { @@ -42,12 +38,7 @@ pub fn bench_scalar(c: &mut Criterion) { c.bench_function("batch_multiplicative_inverse-tiny", |b| { b.iter_batched( - || { - (0..2) - .into_iter() - .map(|_| Scalar::rand()) - .collect::>() - }, + || (0..2).into_iter().map(|_| Scalar::rand()).collect::>(), |x| Scalar::batch_multiplicative_inverse(&x), BatchSize::SmallInput, ) @@ -55,12 +46,7 @@ pub fn bench_scalar(c: &mut Criterion) { c.bench_function("batch_multiplicative_inverse-small", |b| { b.iter_batched( - || { - (0..4) - .into_iter() - .map(|_| Scalar::rand()) - .collect::>() - }, + || (0..4).into_iter().map(|_| Scalar::rand()).collect::>(), |x| Scalar::batch_multiplicative_inverse(&x), BatchSize::SmallInput, ) @@ -68,12 +54,7 @@ pub fn bench_scalar(c: &mut Criterion) { c.bench_function("batch_multiplicative_inverse-medium", |b| { b.iter_batched( - || { - (0..16) - .into_iter() - .map(|_| Scalar::rand()) - .collect::>() - }, + || (0..16).into_iter().map(|_| Scalar::rand()).collect::>(), |x| Scalar::batch_multiplicative_inverse(&x), BatchSize::SmallInput, ) @@ -81,12 +62,7 @@ pub fn bench_scalar(c: &mut Criterion) { c.bench_function("batch_multiplicative_inverse-large", |b| { b.iter_batched( - || { - (0..256) - .into_iter() - .map(|_| Scalar::rand()) - .collect::>() - }, + || (0..256).into_iter().map(|_| Scalar::rand()).collect::>(), |x| Scalar::batch_multiplicative_inverse(&x), BatchSize::LargeInput, ) @@ -94,12 +70,7 @@ pub fn bench_scalar(c: &mut Criterion) { c.bench_function("batch_multiplicative_inverse-huge", |b| { b.iter_batched( - || { - (0..65536) - .into_iter() - .map(|_| Scalar::rand()) - .collect::>() - }, + || (0..65536).into_iter().map(|_| Scalar::rand()).collect::>(), |x| Scalar::batch_multiplicative_inverse(&x), BatchSize::LargeInput, ) diff --git a/ecgfp5/examples/ecdsa_sig.rs b/ecgfp5/examples/ecdsa_sig.rs index 1607a2b376..4359cfae9b 100644 --- a/ecgfp5/examples/ecdsa_sig.rs +++ b/ecgfp5/examples/ecdsa_sig.rs @@ -131,11 +131,7 @@ pub fn main() { // build circuit builder.print_gate_counts(0); let circuit = builder.build::(); - let CircuitData { - prover_only, - common, - verifier_only: _, - } = &circuit; + let CircuitData { prover_only, common, verifier_only: _ } = &circuit; let pw = PartialWitness::new(); let mut timing = TimingTree::new("prove", Level::Debug); diff --git a/ecgfp5/examples/point_add.rs b/ecgfp5/examples/point_add.rs index f3b184fa57..8660ac2378 100644 --- a/ecgfp5/examples/point_add.rs +++ b/ecgfp5/examples/point_add.rs @@ -46,11 +46,7 @@ pub fn main() { let mut pw = PartialWitness::new(); pw.set_curve_target(sum, expected.to_weierstrass()); - let CircuitData { - prover_only, - common, - verifier_only: _, - } = &circuit; + let CircuitData { prover_only, common, verifier_only: _ } = &circuit; let mut timing = TimingTree::new("prove", Level::Debug); let proof = prove(prover_only, common, pw, &mut timing).expect("prover failed"); diff --git a/ecgfp5/examples/scalar_mul.rs b/ecgfp5/examples/scalar_mul.rs index f561a37f3c..c3c4f4b96d 100644 --- a/ecgfp5/examples/scalar_mul.rs +++ b/ecgfp5/examples/scalar_mul.rs @@ -48,11 +48,7 @@ pub fn main() { let mut pw = PartialWitness::new(); pw.set_curve_target(prod, prod_expected.to_weierstrass()); - let CircuitData { - prover_only, - common, - verifier_only: _, - } = &circuit; + let CircuitData { prover_only, common, verifier_only: _ } = &circuit; let mut timing = TimingTree::new("prove", Level::Debug); let proof = prove(prover_only, common, pw, &mut timing).expect("prover failed"); @@ -81,11 +77,7 @@ pub fn main() { let mut pw = PartialWitness::new(); pw.set_curve_target(prod, prod_expected.to_weierstrass()); - let CircuitData { - prover_only, - common, - verifier_only: _, - } = &circuit; + let CircuitData { prover_only, common, verifier_only: _ } = &circuit; let mut timing = TimingTree::new("prove", Level::Debug); let proof = prove(prover_only, common, pw, &mut timing).expect("prover failed"); diff --git a/ecgfp5/examples/schnorr_sig.rs b/ecgfp5/examples/schnorr_sig.rs index b5f9f3e4cc..5041fd621a 100644 --- a/ecgfp5/examples/schnorr_sig.rs +++ b/ecgfp5/examples/schnorr_sig.rs @@ -45,11 +45,7 @@ pub fn main() { // build circuit builder.print_gate_counts(0); let circuit = builder.build::(); - let CircuitData { - prover_only, - common, - verifier_only: _, - } = &circuit; + let CircuitData { prover_only, common, verifier_only: _ } = &circuit; let pw = PartialWitness::new(); let mut timing = TimingTree::new("prove", Level::Debug); diff --git a/ecgfp5/rustfmt.toml b/ecgfp5/rustfmt.toml new file mode 100644 index 0000000000..e651f760b1 --- /dev/null +++ b/ecgfp5/rustfmt.toml @@ -0,0 +1,7 @@ +# This project uses rustfmt to format source code. Run `cargo +nightly fmt [-- --check]. +# https://github.com/rust-lang/rustfmt/blob/master/Configurations.md + +# Break complex but short statements a bit less. +use_small_heuristics = "Max" + +imports_granularity = "Crate" \ No newline at end of file diff --git a/ecgfp5/src/curve/base_field.rs b/ecgfp5/src/curve/base_field.rs index 7c2f267790..62094cf891 100644 --- a/ecgfp5/src/curve/base_field.rs +++ b/ecgfp5/src/curve/base_field.rs @@ -124,8 +124,7 @@ mod tests { use rand::thread_rng; use super::*; - use crate::curve::base_field::SquareRoot; - use crate::curve::test_utils::gfp5_random_non_square; + use crate::curve::{base_field::SquareRoot, test_utils::gfp5_random_non_square}; #[test] fn test_legendre() { diff --git a/ecgfp5/src/curve/curve.rs b/ecgfp5/src/curve/curve.rs index 777b0ff2bf..b64891faed 100644 --- a/ecgfp5/src/curve/curve.rs +++ b/ecgfp5/src/curve/curve.rs @@ -5,17 +5,21 @@ use std::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}; use alloc::vec::Vec; -use plonky2_field::extension::quintic::QuinticExtension; -use plonky2_field::extension::FieldExtension; -use plonky2_field::goldilocks_field::GoldilocksField; -use plonky2_field::ops::Square; -use plonky2_field::types::{Field, PrimeField64, Sample}; +use plonky2_field::{ + extension::{quintic::QuinticExtension, FieldExtension}, + goldilocks_field::GoldilocksField, + ops::Square, + packed::PackedField, + types::{Field, PrimeField64, Sample}, +}; use rand::RngCore; -use crate::curve::base_field::{Legendre, SquareRoot}; -use crate::curve::mul_table::*; -use crate::curve::scalar_field::Scalar; -use crate::curve::{GFp, GFp5}; +use crate::curve::{ + base_field::{Legendre, SquareRoot}, + mul_table::*, + scalar_field::Scalar, + GFp, GFp5, +}; use super::base_field::InverseOrZero; @@ -65,11 +69,7 @@ impl WeierstrassPoint { GFp::ZERO, ]); - pub const NEUTRAL: Self = Self { - x: GFp5::ZERO, - y: GFp5::ZERO, - is_inf: true, - }; + pub const NEUTRAL: Self = Self { x: GFp5::ZERO, y: GFp5::ZERO, is_inf: true }; pub const GENERATOR: Self = Self { x: QuinticExtension([ @@ -107,11 +107,7 @@ impl WeierstrassPoint { let x = if x1.legendre() == GFp::ONE { x1 } else { x2 }; let y = -w * x; - let x = if c { - x + Point::A / GFp5::from_canonical_u16(3) - } else { - GFp5::ZERO - }; + let x = if c { x + Point::A / GFp5::from_canonical_u16(3) } else { GFp5::ZERO }; let is_inf = !c; // If w == 0 then this is in fact a success. @@ -151,13 +147,8 @@ impl Point { QuinticExtension([GFp::TWO, GFp::ZERO, GFp::ZERO, GFp::ZERO, GFp::ZERO]); pub const B1: u64 = 263; - pub(crate) const B: GFp5 = QuinticExtension([ - GFp::ZERO, - GoldilocksField(Self::B1), - GFp::ZERO, - GFp::ZERO, - GFp::ZERO, - ]); + pub(crate) const B: GFp5 = + QuinticExtension([GFp::ZERO, GoldilocksField(Self::B1), GFp::ZERO, GFp::ZERO, GFp::ZERO]); // 2*b pub(crate) const B_MUL2: GFp5 = QuinticExtension([ @@ -185,12 +176,7 @@ impl Point { ]); /// The neutral point (neutral of the group law). - pub const NEUTRAL: Self = Self { - x: GFp5::ZERO, - z: GFp5::ONE, - u: GFp5::ZERO, - t: GFp5::ONE, - }; + pub const NEUTRAL: Self = Self { x: GFp5::ZERO, z: GFp5::ONE, u: GFp5::ZERO, t: GFp5::ONE }; /// The conventional generator (corresponding to encoding w = 4). pub const GENERATOR: Self = Self { @@ -202,20 +188,8 @@ impl Point { GoldilocksField(2448410071095648785), ]), z: GFp5::ONE, - u: QuinticExtension([ - GoldilocksField(1), - GFp::ZERO, - GFp::ZERO, - GFp::ZERO, - GFp::ZERO, - ]), - t: QuinticExtension([ - GoldilocksField(4), - GFp::ZERO, - GFp::ZERO, - GFp::ZERO, - GFp::ZERO, - ]), + u: QuinticExtension([GoldilocksField(1), GFp::ZERO, GFp::ZERO, GFp::ZERO, GFp::ZERO]), + t: QuinticExtension([GoldilocksField(4), GFp::ZERO, GFp::ZERO, GFp::ZERO, GFp::ZERO]), }; pub fn is_x_zero(&self) -> bool { @@ -233,12 +207,15 @@ impl Point { /// Little endian pub fn to_le_bytes(self) -> [u8; 40] { - let gfp5: [GFp; 5] = self.encode().to_basefield_array(); - gfp5.iter().fold(vec![], |mut acc, gfp| { - let bytes = gfp.to_canonical_u64().to_le_bytes(); - acc.extend_from_slice(&bytes); - acc - }).try_into().unwrap() + let gfp5: [GFp; 5] = self.encode().to_basefield_array(); + gfp5.iter() + .fold(vec![], |mut acc, gfp| { + let bytes = gfp.to_canonical_u64().to_le_bytes(); + acc.extend_from_slice(&bytes); + acc + }) + .try_into() + .unwrap() } /// Test whether a field element can be decoded into a point. @@ -253,9 +230,15 @@ impl Point { /// Little endian pub fn from_le_bytes(buf: [u8; 40]) -> Option { - let gfp5: [GFp; 5] = (0..5).map(|i| { - GFp::from_canonical_u64(u64::from_le_bytes(buf[i * 8..(i + 1) * 8].try_into().unwrap())) - }).collect::>().try_into().unwrap(); + let gfp5: [GFp; 5] = (0..5) + .map(|i| { + GFp::from_canonical_u64(u64::from_le_bytes( + buf[i * 8..(i + 1) * 8].try_into().unwrap(), + )) + }) + .collect::>() + .try_into() + .unwrap(); let w = GFp5::from_basefield_array(gfp5); if Self::validate(w) { Self::decode(w) @@ -305,6 +288,46 @@ impl Point { WeierstrassPoint::decode(w).unwrap() } + pub fn to_hex_string(&self) -> String { + let mut buf: [u8; 5 * 8] = [0; 40]; + let dst_ptr = buf.as_mut_ptr(); + + let mut offset = 0; + + let encode = Point::encode(*self); + for e in encode.0 { + let bytes = e.to_canonical_u64().to_le_bytes(); + unsafe { + std::ptr::copy_nonoverlapping(bytes.as_ptr(), dst_ptr.add(offset), 8); + } + offset = offset + 8; + } + + let hex_string = hex::encode(&buf); + hex_string + } + + pub fn from_hex_string(input_hex_string: &str) -> Self { + let buf: Vec = hex::decode(input_hex_string).unwrap(); + let mut data: [GoldilocksField; 5] = [GoldilocksField::ZERO; 5]; + + let src_ptr = buf.as_ptr(); + let mut offset = 0; + for ele in data.iter_mut() { + unsafe { + let mut v_buf: [u8; 8] = [0; 8]; + std::ptr::copy_nonoverlapping(src_ptr.add(offset), v_buf.as_mut_ptr(), 8); + let v: u64 = u64::from_le_bytes(v_buf); + *ele = GoldilocksField::from_canonical_u64(v); + } + offset = offset + 8; + } + + let quintic = QuinticExtension::(data); + let decoded = Self::decode(quintic).unwrap(); + decoded + } + // General point addition. formulas are complete (no special case). fn set_add(&mut self, rhs: &Self) { // cost: 10M @@ -353,10 +376,7 @@ impl Point { // Subtract a point in affine coordinates from this one. fn set_sub_affine(&mut self, rhs: &AffinePoint) { - self.set_add_affine(&AffinePoint { - x: rhs.x, - u: -rhs.u, - }) + self.set_add_affine(&AffinePoint { x: rhs.x, u: -rhs.u }) } fn set_neg(&mut self) { @@ -470,10 +490,7 @@ impl Point { 1 => { let p = src[0]; let m1 = (p.z * p.t).inverse_or_zero(); - let res = AffinePoint { - x: p.x * p.t * m1, - u: p.u * p.z * m1, - }; + let res = AffinePoint { x: p.x * p.t * m1, u: p.u * p.z * m1 }; vec![res] } @@ -662,19 +679,11 @@ impl Point { } impl AffinePoint { - pub(crate) const NEUTRAL: Self = Self { - x: GFp5::ZERO, - u: GFp5::ZERO, - }; + pub(crate) const NEUTRAL: Self = Self { x: GFp5::ZERO, u: GFp5::ZERO }; fn to_point(self) -> Point { let Self { x, u } = self; - Point { - x, - z: GFp5::ONE, - u, - t: GFp5::ONE, - } + Point { x, z: GFp5::ONE, u, t: GFp5::ONE } } fn set_neg(&mut self) { @@ -1418,10 +1427,8 @@ mod tests { assert_eq!(q1, q2); } - let p2_affine = AffinePoint { - x: p2.x * p2.z.inverse_or_zero(), - u: p2.u * p2.t.inverse_or_zero(), - }; + let p2_affine = + AffinePoint { x: p2.x * p2.z.inverse_or_zero(), u: p2.u * p2.t.inverse_or_zero() }; assert_eq!(p1 + p2_affine, p1 + p2); } @@ -1727,6 +1734,22 @@ mod tests { } } + #[test] + fn test_point_convert_str() { + let w1 = QuinticExtension([ + GoldilocksField(7534507442095725921), + GoldilocksField(16658460051907528927), + GoldilocksField(12417574136563175256), + GoldilocksField(2750788641759288856), + GoldilocksField(620002843272906439), + ]); + + let p1 = Point::decode(w1).expect("w1 should successfully decode"); + let hex_str = p1.to_hex_string(); + let recoverred = Point::from_hex_string(&hex_str); + assert_eq!(p1, recoverred); + } + #[test] fn test_to_from_le_bytes() { let mut rng = thread_rng(); diff --git a/ecgfp5/src/curve/scalar_field.rs b/ecgfp5/src/curve/scalar_field.rs index a2d1151e90..d5567f758d 100644 --- a/ecgfp5/src/curve/scalar_field.rs +++ b/ecgfp5/src/curve/scalar_field.rs @@ -3,16 +3,17 @@ /// with some modifications to make it play more nicely with plonky2 primitives /// His implementation can be found here: https://github.com/pornin/ecgfp5 use alloc::vec::Vec; -use core::fmt::{self, Debug, Display, Formatter}; -use core::hash::{Hash, Hasher}; -use core::iter::{Product, Sum}; -use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}; +use core::{ + fmt::{self, Debug, Display, Formatter}, + hash::{Hash, Hasher}, + iter::{Product, Sum}, + ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; use plonky2_field::extension::quintic::QuinticExtension; use rand::RngCore; use itertools::Itertools; -use num::bigint::BigUint; -use num::One; +use num::{bigint::BigUint, One}; use serde::{Deserialize, Serialize}; use plonky2_field::types::{Field, PrimeField, PrimeField64, Sample}; @@ -25,7 +26,7 @@ use super::GFp5; /// ```ignore /// P = 1067993516717146951041484916571792702745057740581727230159139685185762082554198619328292418486241 /// ``` -#[derive(Copy, Clone, Serialize, Deserialize)] +#[derive(Copy, Clone, Serialize, Deserialize, PartialOrd, Ord)] pub struct Scalar(pub [u64; 5]); impl Default for Scalar { @@ -198,10 +199,7 @@ impl Field for Scalar { fn from_noncanonical_biguint(val: BigUint) -> Self { let val = val % Self::order(); Self( - val.to_u64_digits() - .into_iter() - .pad_using(5, |_| 0) - .collect::>()[..] + val.to_u64_digits().into_iter().pad_using(5, |_| 0).collect::>()[..] .try_into() .expect("error converting to u64 array"), ) @@ -318,9 +316,7 @@ impl Scalar { let mut r = Self::ZERO; let mut c: u64 = 0; for i in 0..5 { - let z = (self.0[i] as u128) - .wrapping_add(a.0[i] as u128) - .wrapping_add(c as u128); + let z = (self.0[i] as u128).wrapping_add(a.0[i] as u128).wrapping_add(c as u128); r.0[i] = z as u64; c = (z >> 64) as u64; } @@ -334,9 +330,7 @@ impl Scalar { let mut r = Self::ZERO; let mut c: u64 = 0; for i in 0..5 { - let z = (self.0[i] as u128) - .wrapping_sub(a.0[i] as u128) - .wrapping_sub(c as u128); + let z = (self.0[i] as u128).wrapping_sub(a.0[i] as u128).wrapping_sub(c as u128); r.0[i] = z as u64; c = ((z >> 64) as u64) & 1; } @@ -393,10 +387,7 @@ impl Scalar { // < 2^384 // Thus, the new r fits on 320 bits. let m = rhs.0[i]; - let f = self.0[0] - .wrapping_mul(m) - .wrapping_add(r.0[0]) - .wrapping_mul(Self::N0I); + let f = self.0[0].wrapping_mul(m).wrapping_add(r.0[0]).wrapping_mul(Self::N0I); let mut cc1: u64 = 0; let mut cc2: u64 = 0; for j in 0..5 { @@ -653,6 +644,45 @@ impl Scalar { | (self.0[4] ^ rhs.0[4]); ((x | x.wrapping_neg()) >> 63).wrapping_sub(1) } + + pub fn to_hex_string(&self) -> String { + let u64_array = self.0; + + let mut buf: [u8; 40] = [0; 40]; + let dst_ptr = buf.as_mut_ptr(); + + let mut offset = 0; + for e in u64_array { + let bytes = e.to_le_bytes(); + unsafe { + let src_ptr = bytes.as_ptr(); + std::ptr::copy_nonoverlapping(src_ptr, dst_ptr.add(offset), 8); + offset = offset + 8; + } + } + + let hex_string = hex::encode(&buf); + hex_string + } + + pub fn from_hex_string(input_hex_string: &str) -> Self { + let buf: Vec = hex::decode(input_hex_string).unwrap(); + let mut data: [u64; 5] = [0; 5]; + + let src_ptr = buf.as_ptr(); + let mut offset = 0; + for ele in data.iter_mut() { + unsafe { + let mut v_buf: [u8; 8] = [0; 8]; + std::ptr::copy_nonoverlapping(src_ptr.add(offset), v_buf.as_mut_ptr(), 8); + let v: u64 = u64::from_le_bytes(v_buf); + *ele = v; + } + offset = offset + 8; + } + + Self(data) + } } /// A custom 161-bit integer type; used for splitting a scalar into a @@ -767,9 +797,7 @@ impl Signed161 { let vw = v[i - j]; let vws = vw.wrapping_shl(s as u32) | vbits; vbits = vw.wrapping_shr((64 - s) as u32); - let z = (self.0[i] as u128) - .wrapping_sub(vws as u128) - .wrapping_sub(cc as u128); + let z = (self.0[i] as u128).wrapping_sub(vws as u128).wrapping_sub(cc as u128); self.0[i] = z as u64; cc = ((z >> 64) as u64) & 1; } @@ -779,9 +807,7 @@ impl Signed161 { let mut cc = 0; let j = 3 - v.len(); for i in j..3 { - let z = (self.0[i] as u128) - .wrapping_sub(v[i - j] as u128) - .wrapping_sub(cc as u128); + let z = (self.0[i] as u128).wrapping_sub(v[i - j] as u128).wrapping_sub(cc as u128); self.0[i] = z as u64; cc = ((z >> 64) as u64) & 1; } @@ -957,9 +983,7 @@ impl Signed640 { let vw = v[i - j]; let vws = vw.wrapping_shl(s as u32) | vbits; vbits = vw.wrapping_shr((64 - s) as u32); - let z = (self.0[i] as u128) - .wrapping_sub(vws as u128) - .wrapping_sub(cc as u128); + let z = (self.0[i] as u128).wrapping_sub(vws as u128).wrapping_sub(cc as u128); self.0[i] = z as u64; cc = ((z >> 64) as u64) & 1; } @@ -969,9 +993,7 @@ impl Signed640 { let mut cc = 0; let j = 10 - v.len(); for i in j..10 { - let z = (self.0[i] as u128) - .wrapping_sub(v[i - j] as u128) - .wrapping_sub(cc as u128); + let z = (self.0[i] as u128).wrapping_sub(v[i - j] as u128).wrapping_sub(cc as u128); self.0[i] = z as u64; cc = ((z >> 64) as u64) & 1; } @@ -1056,9 +1078,7 @@ mod tests { assert!(c5 == 0xFFFFFFFFFFFFFFFF); assert!(s5.encode() == buf5); { - let should_be_none = Scalar::from_canonical_bytes(&buf4); - assert!(should_be_none.is_none()); - let should_be_some = Scalar::from_canonical_bytes(&buf5); + let should_be_some = Scalar::from_canonical_bytes(buf5); assert!(should_be_some.is_some()); assert!(should_be_some.unwrap() == s5); } @@ -1111,5 +1131,22 @@ mod tests { } } + #[test] + fn test_convert_hex_str() { + // buf4 = a randomly chosen 512-bit integer + let buf4: [u8; 64] = [ + 0xB5, 0xDD, 0x28, 0xB8, 0xD2, 0x9B, 0x6F, 0xF8, 0x15, 0x65, 0x3F, 0x89, 0xDB, 0x7B, + 0xA9, 0xDE, 0x33, 0x7D, 0xA8, 0x27, 0x82, 0x26, 0xB4, 0xD6, 0x9E, 0x1F, 0xFA, 0x97, + 0x3D, 0x9E, 0x01, 0x9C, 0x77, 0xC9, 0x63, 0x5C, 0xB8, 0x34, 0xD8, 0x1A, 0x4D, 0xCB, + 0x03, 0x48, 0x62, 0xCD, 0xEE, 0xC9, 0x8E, 0xC8, 0xC9, 0xA7, 0xB3, 0x6E, 0xDA, 0xCE, + 0x18, 0x75, 0x1B, 0xDD, 0x4F, 0x94, 0x67, 0xB5, + ]; + + let s4 = Scalar::from_noncanonical_bytes(&buf4[..]); + let hex_str = s4.to_hex_string(); + let recoverred = Scalar::from_hex_string(&hex_str); + assert_eq!(s4, recoverred); + } + test_field_arithmetic!(crate::curve::scalar_field::Scalar); } diff --git a/ecgfp5/src/gadgets/base_field.rs b/ecgfp5/src/gadgets/base_field.rs index 0badf9b473..c7008db37f 100644 --- a/ecgfp5/src/gadgets/base_field.rs +++ b/ecgfp5/src/gadgets/base_field.rs @@ -1,23 +1,27 @@ use alloc::vec::Vec; use plonky2_ecdsa::gadgets::nonnative::NonNativeTarget; -use plonky2_field::extension::quintic::QuinticExtension; -use plonky2_field::goldilocks_field::GoldilocksField; - -use plonky2::hash::hash_types::RichField; -use plonky2::iop::generator::{GeneratedValues, SimpleGenerator}; -use plonky2::iop::target::{BoolTarget, Target}; -use plonky2::iop::witness::{PartitionWitness, Witness, WitnessWrite}; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2_ecdsa::gadgets::biguint::BigUintTarget; -use plonky2_ecdsa::gadgets::nonnative::CircuitBuilderNonNative; -use plonky2_field::extension::{Extendable, FieldExtension}; -use plonky2_field::types::Field; +use plonky2_field::{extension::quintic::QuinticExtension, goldilocks_field::GoldilocksField}; + +use plonky2::{ + hash::hash_types::RichField, + iop::{ + generator::{GeneratedValues, SimpleGenerator}, + target::{BoolTarget, Target}, + witness::{PartitionWitness, Witness, WitnessWrite}, + }, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_ecdsa::gadgets::{biguint::BigUintTarget, nonnative::CircuitBuilderNonNative}; +use plonky2_field::{ + extension::{Extendable, FieldExtension}, + types::Field, +}; use plonky2_u32::gadgets::arithmetic_u32::U32Target; -use crate::curve::base_field::SquareRoot; -use crate::curve::scalar_field::Scalar; -use crate::curve::{GFp, GFp5}; -use crate::gates::gfp5_mul::MulGFp5Gate; +use crate::{ + curve::{base_field::SquareRoot, scalar_field::Scalar, GFp, GFp5}, + gates::gfp5_mul::MulGFp5Gate, +}; const THREE: GFp = GoldilocksField(3); @@ -153,10 +157,7 @@ pub trait PartialWitnessQuinticExt>: Witness { &self, targets: &[QuinticExtensionTarget], ) -> Vec> { - targets - .iter() - .map(|&t| self.get_quintic_ext_target(t)) - .collect() + targets.iter().map(|&t| self.get_quintic_ext_target(t)).collect() } fn set_quintic_ext_target( @@ -218,11 +219,7 @@ impl CircuitBuilderGFp5 for CircuitBuilder { } fn connect_quintic_ext(&mut self, a: QuinticExtensionTarget, b: QuinticExtensionTarget) { - for (lhs, rhs) in a - .to_target_array() - .into_iter() - .zip(b.to_target_array().into_iter()) - { + for (lhs, rhs) in a.to_target_array().into_iter().zip(b.to_target_array().into_iter()) { self.connect(lhs, rhs); } } @@ -420,12 +417,8 @@ impl CircuitBuilderGFp5 for CircuitBuilder { let multiplicand_1_wires = MulGFp5Gate::wires_ith_multiplicand_1(i).map(|wire| Target::wire(gate, wire)); - a.0.into_iter() - .zip(multiplicand_0_wires) - .for_each(|(a, wire)| self.connect(a, wire)); - b.0.into_iter() - .zip(multiplicand_1_wires) - .for_each(|(b, wire)| self.connect(b, wire)); + a.0.into_iter().zip(multiplicand_0_wires).for_each(|(a, wire)| self.connect(a, wire)); + b.0.into_iter().zip(multiplicand_1_wires).for_each(|(b, wire)| self.connect(b, wire)); let output_limbs: [Target; 5] = MulGFp5Gate::wires_ith_output(i) .map(|wire| Target::wire(gate, wire)) @@ -719,7 +712,7 @@ impl CircuitBuilderGFp5 for CircuitBuilder { // impl_circuit_builder_for_extension_degree!(4); // impl_circuit_builder_for_extension_degree!(5); -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct QuinticQuotientGenerator { numerator: QuinticExtensionTarget, denominator: QuinticExtensionTarget, @@ -732,11 +725,7 @@ impl QuinticQuotientGenerator { denominator: QuinticExtensionTarget, quotient: QuinticExtensionTarget, ) -> Self { - QuinticQuotientGenerator { - numerator, - denominator, - quotient, - } + QuinticQuotientGenerator { numerator, denominator, quotient } } } @@ -769,16 +758,10 @@ impl + Extendable<2>> SimpleGenerator } fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let numerator_limbs = self - .numerator - .to_target_array() - .map(|t| witness.get_target(t)); + let numerator_limbs = self.numerator.to_target_array().map(|t| witness.get_target(t)); let numerator = QuinticExtension::::from_basefield_array(numerator_limbs); - let denominator_limbs = self - .denominator - .to_target_array() - .map(|t| witness.get_target(t)); + let denominator_limbs = self.denominator.to_target_array().map(|t| witness.get_target(t)); let denominator = QuinticExtension::::from_basefield_array(denominator_limbs); let quotient = if denominator == QuinticExtension::::ZERO { @@ -794,7 +777,7 @@ impl + Extendable<2>> SimpleGenerator } } -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct QuinticSqrtGenerator { x: QuinticExtensionTarget, root_x: QuinticExtensionTarget, @@ -864,18 +847,26 @@ impl SimpleGenerator for QuinticSqrtGenerator { #[cfg(test)] mod tests { use anyhow::Result; - use plonky2::field::types::{Field, Sample}; - use plonky2::iop::witness::PartialWitness; - use plonky2::plonk::circuit_builder::CircuitBuilder; - use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::{ + field::types::{Field, Sample}, + iop::witness::PartialWitness, + plonk::{ + circuit_builder::CircuitBuilder, + circuit_data::CircuitConfig, + config::{GenericConfig, PoseidonGoldilocksConfig}, + }, + }; use plonky2_field::types::PrimeField64; use rand::thread_rng; use super::*; - use crate::curve::scalar_field::biguint_from_array; - use crate::curve::test_utils::{gfp5_random_non_square, gfp5_random_sgn0_eq_0}; - use crate::gadgets::scalar_field::{CircuitBuilderScalar, PartialWitnessScalar}; + use crate::{ + curve::{ + scalar_field::biguint_from_array, + test_utils::{gfp5_random_non_square, gfp5_random_sgn0_eq_0}, + }, + gadgets::scalar_field::{CircuitBuilderScalar, PartialWitnessScalar}, + }; #[test] fn test_add() -> Result<()> { diff --git a/ecgfp5/src/gadgets/curve.rs b/ecgfp5/src/gadgets/curve.rs index 2f29f98d12..bc39a38ece 100644 --- a/ecgfp5/src/gadgets/curve.rs +++ b/ecgfp5/src/gadgets/curve.rs @@ -1,17 +1,21 @@ -use crate::curve::scalar_field::Scalar; -use crate::curve::{ - curve::{Point, WeierstrassPoint}, - GFp, GFp5, +use crate::{ + curve::{ + curve::{Point, WeierstrassPoint}, + scalar_field::Scalar, + GFp, GFp5, + }, + gadgets::base_field::{CircuitBuilderGFp5, QuinticExtensionTarget}, }; -use crate::gadgets::base_field::{CircuitBuilderGFp5, QuinticExtensionTarget}; -use plonky2::field::types::Field; -use plonky2::hash::hash_types::RichField; -use plonky2::iop::target::BoolTarget; -use plonky2::iop::target::Target; -use plonky2::iop::witness::Witness; -use plonky2::plonk::circuit_builder::CircuitBuilder; -use plonky2_ecdsa::gadgets::nonnative::NonNativeTarget; -use plonky2_ecdsa::gadgets::split_nonnative::CircuitBuilderSplit; +use plonky2::{ + field::types::Field, + hash::hash_types::RichField, + iop::{ + target::{BoolTarget, Target}, + witness::Witness, + }, + plonk::circuit_builder::CircuitBuilder, +}; +use plonky2_ecdsa::gadgets::{nonnative::NonNativeTarget, split_nonnative::CircuitBuilderSplit}; use plonky2_field::extension::Extendable; use super::base_field::PartialWitnessQuinticExt; @@ -123,10 +127,7 @@ macro_rules! impl_circuit_builder_for_extension_degree { let CurveTarget(([ax, ay], a_is_inf)) = a; let CurveTarget(([bx, by], b_is_inf)) = b; CurveTarget(( - [ - self.select_quintic_ext(cond, ax, bx), - self.select_quintic_ext(cond, ay, by), - ], + [self.select_quintic_ext(cond, ax, bx), self.select_quintic_ext(cond, ay, by)], BoolTarget::new_unsafe(self.select(cond, a_is_inf.target, b_is_inf.target)), )) } @@ -382,11 +383,8 @@ macro_rules! impl_circuit_builder_for_extension_degree { let b_start = self.curve_random_access(b_four_bit_limbs[num_limbs - 1], &b_window); let mut res = self.curve_add(a_start, b_start); - for (a_limb, b_limb) in a_four_bit_limbs - .into_iter() - .zip(b_four_bit_limbs) - .rev() - .skip(1) + for (a_limb, b_limb) in + a_four_bit_limbs.into_iter().zip(b_four_bit_limbs).rev().skip(1) { for _ in 0..4 { res = self.curve_double(res); diff --git a/ecgfp5/src/gadgets/schnorr.rs b/ecgfp5/src/gadgets/schnorr.rs index 4b9f52274a..457e64f215 100644 --- a/ecgfp5/src/gadgets/schnorr.rs +++ b/ecgfp5/src/gadgets/schnorr.rs @@ -1,10 +1,11 @@ #![allow(dead_code)] -use crate::curve::curve::Point; -use crate::curve::scalar_field::Scalar; -use crate::gadgets::curve::CircuitBuilderEcGFp5; -use plonky2::field::types::Field; +use crate::{ + curve::{curve::Point, scalar_field::Scalar}, + gadgets::curve::CircuitBuilderEcGFp5, +}; use plonky2::{ + field::types::Field, hash::{ hashing::hash_n_to_m_no_pad, poseidon::{PoseidonHash, PoseidonPermutation}, @@ -117,10 +118,7 @@ fn hash(message: &[F]) -> [F; 5] { } fn hash_target(builder: &mut CircuitBuilder, message: &[Target]) -> [Target; 5] { - builder - .hash_n_to_m_no_pad::(message.to_vec(), 5) - .try_into() - .unwrap() + builder.hash_n_to_m_no_pad::(message.to_vec(), 5).try_into().unwrap() } #[cfg(test)] diff --git a/ecgfp5/src/gates/gfp5_mul.rs b/ecgfp5/src/gates/gfp5_mul.rs index b2fad522b3..5030075c71 100644 --- a/ecgfp5/src/gates/gfp5_mul.rs +++ b/ecgfp5/src/gates/gfp5_mul.rs @@ -36,9 +36,7 @@ const WIRES_PER_OP: usize = 3 * DEGREE; impl MulGFp5Gate { pub fn new_from_config(config: &CircuitConfig) -> Self { - Self { - num_ops: Self::num_ops(config), - } + Self { num_ops: Self::num_ops(config) } } /// Determine the maximum number of operations that can fit in one gate for the given config. @@ -88,17 +86,12 @@ impl, const D: usize> Gate for MulGFp5Gate { let mut constraints = Vec::new(); for i in 0..self.num_ops { - let multiplicand_0_limbs: [F::Extension; 5] = vars.local_wires - [Self::wires_ith_multiplicand_0(i)] - .try_into() - .unwrap(); - let multiplicand_1_limbs: [F::Extension; 5] = vars.local_wires - [Self::wires_ith_multiplicand_1(i)] - .try_into() - .unwrap(); - let output_limbs: [F::Extension; 5] = vars.local_wires[Self::wires_ith_output(i)] - .try_into() - .unwrap(); + let multiplicand_0_limbs: [F::Extension; 5] = + vars.local_wires[Self::wires_ith_multiplicand_0(i)].try_into().unwrap(); + let multiplicand_1_limbs: [F::Extension; 5] = + vars.local_wires[Self::wires_ith_multiplicand_1(i)].try_into().unwrap(); + let output_limbs: [F::Extension; 5] = + vars.local_wires[Self::wires_ith_output(i)].try_into().unwrap(); let prod_limbs = gfp5_mul_limbwise(multiplicand_0_limbs, multiplicand_1_limbs); let computed_output_limbs = gfp5_scalar_mul_limbwise(c, prod_limbs); @@ -121,21 +114,12 @@ impl, const D: usize> Gate for MulGFp5Gate { let const_limbs = vars.local_constants[0]; for i in 0..self.num_ops { - let multiplicand_0_limbs = vars - .local_wires - .view(Self::wires_ith_multiplicand_0(i)) - .try_into() - .unwrap(); - let multiplicand_1_limbs = vars - .local_wires - .view(Self::wires_ith_multiplicand_1(i)) - .try_into() - .unwrap(); - let output_limbs: [F; 5] = vars - .local_wires - .view(Self::wires_ith_output(i)) - .try_into() - .unwrap(); + let multiplicand_0_limbs = + vars.local_wires.view(Self::wires_ith_multiplicand_0(i)).try_into().unwrap(); + let multiplicand_1_limbs = + vars.local_wires.view(Self::wires_ith_multiplicand_1(i)).try_into().unwrap(); + let output_limbs: [F; 5] = + vars.local_wires.view(Self::wires_ith_output(i)).try_into().unwrap(); let prod_limbs = gfp5_mul_limbwise(multiplicand_0_limbs, multiplicand_1_limbs); let computed_output_limbs = gfp5_scalar_mul_limbwise(const_limbs, prod_limbs); @@ -157,17 +141,12 @@ impl, const D: usize> Gate for MulGFp5Gate { let mut constraints = Vec::new(); for i in 0..self.num_ops { - let multiplicand_0_limbs: [ExtensionTarget; 5] = vars.local_wires - [Self::wires_ith_multiplicand_0(i)] - .try_into() - .unwrap(); - let multiplicand_1_limbs: [ExtensionTarget; 5] = vars.local_wires - [Self::wires_ith_multiplicand_1(i)] - .try_into() - .unwrap(); - let output_limbs: [ExtensionTarget; 5] = vars.local_wires[Self::wires_ith_output(i)] - .try_into() - .unwrap(); + let multiplicand_0_limbs: [ExtensionTarget; 5] = + vars.local_wires[Self::wires_ith_multiplicand_0(i)].try_into().unwrap(); + let multiplicand_1_limbs: [ExtensionTarget; 5] = + vars.local_wires[Self::wires_ith_multiplicand_1(i)].try_into().unwrap(); + let output_limbs: [ExtensionTarget; 5] = + vars.local_wires[Self::wires_ith_output(i)].try_into().unwrap(); let prod_limbs = gfp5_mul_limbwise_circuit_lifted( builder, @@ -191,14 +170,8 @@ impl, const D: usize> Gate for MulGFp5Gate { fn generators(&self, row: usize, local_constants: &[F]) -> Vec> { (0..self.num_ops) .map(|op_idx| { - let g: Box> = Box::new( - MulGFp5Generator { - row, - c: local_constants[0], - op_idx, - } - .adapter(), - ); + let g: Box> = + Box::new(MulGFp5Generator { row, c: local_constants[0], op_idx }.adapter()); WitnessGeneratorRef(g) }) .collect() @@ -378,10 +351,14 @@ mod tests { use super::*; use anyhow::Result; - use plonky2::field::goldilocks_field::GoldilocksField; - use plonky2::gates::gate_testing::{test_eval_fns, test_low_degree}; - use plonky2::plonk::circuit_data::CircuitConfig; - use plonky2::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; + use plonky2::{ + field::goldilocks_field::GoldilocksField, + gates::gate_testing::{test_eval_fns, test_low_degree}, + plonk::{ + circuit_data::CircuitConfig, + config::{GenericConfig, PoseidonGoldilocksConfig}, + }, + }; #[test] fn low_degree() { diff --git a/ecgfp5/src/macros.rs b/ecgfp5/src/macros.rs index e3820cfdf9..4023eeb696 100644 --- a/ecgfp5/src/macros.rs +++ b/ecgfp5/src/macros.rs @@ -10,9 +10,8 @@ macro_rules! test_field_arithmetic { #[test] fn batch_inversion() { for n in 0..20 { - let xs = (1..=n as u64) - .map(|i| <$field>::from_canonical_u64(i)) - .collect::>(); + let xs = + (1..=n as u64).map(|i| <$field>::from_canonical_u64(i)).collect::>(); let invs = <$field>::batch_multiplicative_inverse(&xs); assert_eq!(invs.len(), n); for (x, inv) in xs.into_iter().zip(invs) {