diff --git a/Cargo.toml b/Cargo.toml index cc070d96..00a4b28f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["field", "insertion", "plonky2", "starky", "system_zero", "util", "waksman"] +members = ["field", "insertion", "plonky2", "starky", "system_zero", "util", "waksman", "ecdsa"] [profile.release] opt-level = 3 diff --git a/ecdsa/src/gadgets/mod.rs b/ecdsa/src/gadgets/mod.rs new file mode 100644 index 00000000..35b10100 --- /dev/null +++ b/ecdsa/src/gadgets/mod.rs @@ -0,0 +1,9 @@ +pub mod biguint; +pub mod curve; +pub mod curve_fixed_base; +pub mod curve_msm; +pub mod curve_windowed_mul; +pub mod ecdsa; +pub mod glv; +pub mod nonnative; +pub mod split_nonnative; diff --git a/plonky2/src/curve/curve_adds.rs b/plonky2/src/curve/curve_adds.rs deleted file mode 100644 index 98dbc697..00000000 --- a/plonky2/src/curve/curve_adds.rs +++ /dev/null @@ -1,158 +0,0 @@ -use std::ops::Add; - -use plonky2_field::field_types::Field; -use plonky2_field::ops::Square; - -use crate::curve::curve_types::{AffinePoint, Curve, ProjectivePoint}; - -impl Add> for ProjectivePoint { - type Output = ProjectivePoint; - - fn add(self, rhs: ProjectivePoint) -> Self::Output { - let ProjectivePoint { - x: x1, - y: y1, - z: z1, - } = self; - let ProjectivePoint { - x: x2, - y: y2, - z: z2, - } = rhs; - - if z1 == C::BaseField::ZERO { - return rhs; - } - if z2 == C::BaseField::ZERO { - return self; - } - - let x1z2 = x1 * z2; - let y1z2 = y1 * z2; - let x2z1 = x2 * z1; - let y2z1 = y2 * z1; - - // Check if we're doubling or adding inverses. - if x1z2 == x2z1 { - if y1z2 == y2z1 { - // TODO: inline to avoid redundant muls. - return self.double(); - } - if y1z2 == -y2z1 { - return ProjectivePoint::ZERO; - } - } - - // From https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/addition/add-1998-cmo-2 - let z1z2 = z1 * z2; - let u = y2z1 - y1z2; - let uu = u.square(); - let v = x2z1 - x1z2; - let vv = v.square(); - let vvv = v * vv; - let r = vv * x1z2; - let a = uu * z1z2 - vvv - r.double(); - let x3 = v * a; - let y3 = u * (r - a) - vvv * y1z2; - let z3 = vvv * z1z2; - ProjectivePoint::nonzero(x3, y3, z3) - } -} - -impl Add> for ProjectivePoint { - type Output = ProjectivePoint; - - fn add(self, rhs: AffinePoint) -> Self::Output { - let ProjectivePoint { - x: x1, - y: y1, - z: z1, - } = self; - let AffinePoint { - x: x2, - y: y2, - zero: zero2, - } = rhs; - - if z1 == C::BaseField::ZERO { - return rhs.to_projective(); - } - if zero2 { - return self; - } - - let x2z1 = x2 * z1; - let y2z1 = y2 * z1; - - // Check if we're doubling or adding inverses. - if x1 == x2z1 { - if y1 == y2z1 { - // TODO: inline to avoid redundant muls. - return self.double(); - } - if y1 == -y2z1 { - return ProjectivePoint::ZERO; - } - } - - // From https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/addition/madd-1998-cmo - let u = y2z1 - y1; - let uu = u.square(); - let v = x2z1 - x1; - let vv = v.square(); - let vvv = v * vv; - let r = vv * x1; - let a = uu * z1 - vvv - r.double(); - let x3 = v * a; - let y3 = u * (r - a) - vvv * y1; - let z3 = vvv * z1; - ProjectivePoint::nonzero(x3, y3, z3) - } -} - -impl Add> for AffinePoint { - type Output = ProjectivePoint; - - fn add(self, rhs: AffinePoint) -> Self::Output { - let AffinePoint { - x: x1, - y: y1, - zero: zero1, - } = self; - let AffinePoint { - x: x2, - y: y2, - zero: zero2, - } = rhs; - - if zero1 { - return rhs.to_projective(); - } - if zero2 { - return self.to_projective(); - } - - // Check if we're doubling or adding inverses. - if x1 == x2 { - if y1 == y2 { - return self.to_projective().double(); - } - if y1 == -y2 { - return ProjectivePoint::ZERO; - } - } - - // From https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/addition/mmadd-1998-cmo - let u = y2 - y1; - let uu = u.square(); - let v = x2 - x1; - let vv = v.square(); - let vvv = v * vv; - let r = vv * x1; - let a = uu - vvv - r.double(); - let x3 = v * a; - let y3 = u * (r - a) - vvv * y1; - let z3 = vvv; - ProjectivePoint::nonzero(x3, y3, z3) - } -} diff --git a/plonky2/src/curve/curve_msm.rs b/plonky2/src/curve/curve_msm.rs deleted file mode 100644 index 4c274c1c..00000000 --- a/plonky2/src/curve/curve_msm.rs +++ /dev/null @@ -1,265 +0,0 @@ -use itertools::Itertools; -use plonky2_field::field_types::Field; -use plonky2_field::field_types::PrimeField; -use rayon::prelude::*; - -use crate::curve::curve_summation::affine_multisummation_best; -use crate::curve::curve_types::{AffinePoint, Curve, ProjectivePoint}; - -/// In Yao's method, we compute an affine summation for each digit. In a parallel setting, it would -/// be easiest to assign individual summations to threads, but this would be sub-optimal because -/// multi-summations can be more efficient than repeating individual summations (see -/// `affine_multisummation_best`). Thus we divide digits into large chunks, and assign chunks of -/// digits to threads. Note that there is a delicate balance here, as large chunks can result in -/// uneven distributions of work among threads. -const DIGITS_PER_CHUNK: usize = 80; - -#[derive(Clone, Debug)] -pub struct MsmPrecomputation { - /// For each generator (in the order they were passed to `msm_precompute`), contains a vector - /// of powers, i.e. [(2^w)^i] for i < DIGITS. - // TODO: Use compressed coordinates here. - powers_per_generator: Vec>>, - - /// The window size. - w: usize, -} - -pub fn msm_precompute( - generators: &[ProjectivePoint], - w: usize, -) -> MsmPrecomputation { - MsmPrecomputation { - powers_per_generator: generators - .into_par_iter() - .map(|&g| precompute_single_generator(g, w)) - .collect(), - w, - } -} - -fn precompute_single_generator(g: ProjectivePoint, w: usize) -> Vec> { - let digits = (C::ScalarField::BITS + w - 1) / w; - let mut powers: Vec> = Vec::with_capacity(digits); - powers.push(g); - for i in 1..digits { - let mut power_i_proj = powers[i - 1]; - for _j in 0..w { - power_i_proj = power_i_proj.double(); - } - powers.push(power_i_proj); - } - ProjectivePoint::batch_to_affine(&powers) -} - -pub fn msm_parallel( - scalars: &[C::ScalarField], - generators: &[ProjectivePoint], - w: usize, -) -> ProjectivePoint { - let precomputation = msm_precompute(generators, w); - msm_execute_parallel(&precomputation, scalars) -} - -pub fn msm_execute( - precomputation: &MsmPrecomputation, - scalars: &[C::ScalarField], -) -> ProjectivePoint { - assert_eq!(precomputation.powers_per_generator.len(), scalars.len()); - let w = precomputation.w; - let digits = (C::ScalarField::BITS + w - 1) / w; - let base = 1 << w; - - // This is a variant of Yao's method, adapted to the multi-scalar setting. Because we use - // extremely large windows, the repeated scans in Yao's method could be more expensive than the - // actual group operations. To avoid this, we store a multimap from each possible digit to the - // positions in which that digit occurs in the scalars. These positions have the form (i, j), - // where i is the index of the generator and j is an index into the digits of the scalar - // associated with that generator. - let mut digit_occurrences: Vec> = Vec::with_capacity(digits); - for _i in 0..base { - digit_occurrences.push(Vec::new()); - } - for (i, scalar) in scalars.iter().enumerate() { - let digits = to_digits::(scalar, w); - for (j, &digit) in digits.iter().enumerate() { - digit_occurrences[digit].push((i, j)); - } - } - - let mut y = ProjectivePoint::ZERO; - let mut u = ProjectivePoint::ZERO; - - for digit in (1..base).rev() { - for &(i, j) in &digit_occurrences[digit] { - u = u + precomputation.powers_per_generator[i][j]; - } - y = y + u; - } - - y -} - -pub fn msm_execute_parallel( - precomputation: &MsmPrecomputation, - scalars: &[C::ScalarField], -) -> ProjectivePoint { - assert_eq!(precomputation.powers_per_generator.len(), scalars.len()); - let w = precomputation.w; - let digits = (C::ScalarField::BITS + w - 1) / w; - let base = 1 << w; - - // This is a variant of Yao's method, adapted to the multi-scalar setting. Because we use - // extremely large windows, the repeated scans in Yao's method could be more expensive than the - // actual group operations. To avoid this, we store a multimap from each possible digit to the - // positions in which that digit occurs in the scalars. These positions have the form (i, j), - // where i is the index of the generator and j is an index into the digits of the scalar - // associated with that generator. - let mut digit_occurrences: Vec> = Vec::with_capacity(digits); - for _i in 0..base { - digit_occurrences.push(Vec::new()); - } - for (i, scalar) in scalars.iter().enumerate() { - let digits = to_digits::(scalar, w); - for (j, &digit) in digits.iter().enumerate() { - digit_occurrences[digit].push((i, j)); - } - } - - // For each digit, we add up the powers associated with all occurrences that digit. - let digits: Vec = (0..base).collect(); - let digit_acc: Vec> = digits - .par_chunks(DIGITS_PER_CHUNK) - .flat_map(|chunk| { - let summations: Vec>> = chunk - .iter() - .map(|&digit| { - digit_occurrences[digit] - .iter() - .map(|&(i, j)| precomputation.powers_per_generator[i][j]) - .collect() - }) - .collect(); - affine_multisummation_best(summations) - }) - .collect(); - // println!("Computing the per-digit summations (in parallel) took {}s", start.elapsed().as_secs_f64()); - - let mut y = ProjectivePoint::ZERO; - let mut u = ProjectivePoint::ZERO; - for digit in (1..base).rev() { - u = u + digit_acc[digit]; - y = y + u; - } - // println!("Final summation (sequential) {}s", start.elapsed().as_secs_f64()); - y -} - -pub(crate) fn to_digits(x: &C::ScalarField, w: usize) -> Vec { - let scalar_bits = C::ScalarField::BITS; - let num_digits = (scalar_bits + w - 1) / w; - - // Convert x to a bool array. - let x_canonical: Vec<_> = x - .to_canonical_biguint() - .to_u64_digits() - .iter() - .cloned() - .pad_using(scalar_bits / 64, |_| 0) - .collect(); - let mut x_bits = Vec::with_capacity(scalar_bits); - for i in 0..scalar_bits { - x_bits.push((x_canonical[i / 64] >> (i as u64 % 64) & 1) != 0); - } - - let mut digits = Vec::with_capacity(num_digits); - for i in 0..num_digits { - let mut digit = 0; - for j in ((i * w)..((i + 1) * w).min(scalar_bits)).rev() { - digit <<= 1; - digit |= x_bits[j] as usize; - } - digits.push(digit); - } - digits -} - -#[cfg(test)] -mod tests { - use num::BigUint; - use plonky2_field::field_types::Field; - use plonky2_field::field_types::PrimeField; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - - use crate::curve::curve_msm::{msm_execute, msm_precompute, to_digits}; - use crate::curve::curve_types::Curve; - use crate::curve::secp256k1::Secp256K1; - - #[test] - fn test_to_digits() { - let x_canonical = [ - 0b10101010101010101010101010101010, - 0b10101010101010101010101010101010, - 0b11001100110011001100110011001100, - 0b11001100110011001100110011001100, - 0b11110000111100001111000011110000, - 0b11110000111100001111000011110000, - 0b00001111111111111111111111111111, - 0b11111111111111111111111111111111, - ]; - let x = Secp256K1Scalar::from_biguint(BigUint::from_slice(&x_canonical)); - assert_eq!(x.to_canonical_biguint().to_u32_digits(), x_canonical); - assert_eq!( - to_digits::(&x, 17), - vec![ - 0b01010101010101010, - 0b10101010101010101, - 0b01010101010101010, - 0b11001010101010101, - 0b01100110011001100, - 0b00110011001100110, - 0b10011001100110011, - 0b11110000110011001, - 0b01111000011110000, - 0b00111100001111000, - 0b00011110000111100, - 0b11111111111111110, - 0b01111111111111111, - 0b11111111111111000, - 0b11111111111111111, - 0b1, - ] - ); - } - - #[test] - fn test_msm() { - let w = 5; - - let generator_1 = Secp256K1::GENERATOR_PROJECTIVE; - let generator_2 = generator_1 + generator_1; - let generator_3 = generator_1 + generator_2; - - let scalar_1 = Secp256K1Scalar::from_biguint(BigUint::from_slice(&[ - 11111111, 22222222, 33333333, 44444444, - ])); - let scalar_2 = Secp256K1Scalar::from_biguint(BigUint::from_slice(&[ - 22222222, 22222222, 33333333, 44444444, - ])); - let scalar_3 = Secp256K1Scalar::from_biguint(BigUint::from_slice(&[ - 33333333, 22222222, 33333333, 44444444, - ])); - - let generators = vec![generator_1, generator_2, generator_3]; - let scalars = vec![scalar_1, scalar_2, scalar_3]; - - let precomputation = msm_precompute(&generators, w); - let result_msm = msm_execute(&precomputation, &scalars); - - let result_naive = Secp256K1::convert(scalar_1) * generator_1 - + Secp256K1::convert(scalar_2) * generator_2 - + Secp256K1::convert(scalar_3) * generator_3; - - assert_eq!(result_msm, result_naive); - } -} diff --git a/plonky2/src/curve/curve_multiplication.rs b/plonky2/src/curve/curve_multiplication.rs deleted file mode 100644 index c6fbbd83..00000000 --- a/plonky2/src/curve/curve_multiplication.rs +++ /dev/null @@ -1,99 +0,0 @@ -use std::ops::Mul; - -use plonky2_field::field_types::Field; -use plonky2_field::field_types::PrimeField; - -use crate::curve::curve_types::{Curve, CurveScalar, ProjectivePoint}; - -const WINDOW_BITS: usize = 4; -const BASE: usize = 1 << WINDOW_BITS; - -fn digits_per_scalar() -> usize { - (C::ScalarField::BITS + WINDOW_BITS - 1) / WINDOW_BITS -} - -/// Precomputed state used for scalar x ProjectivePoint multiplications, -/// specific to a particular generator. -#[derive(Clone)] -pub struct MultiplicationPrecomputation { - /// [(2^w)^i] g for each i < digits_per_scalar. - powers: Vec>, -} - -impl ProjectivePoint { - pub fn mul_precompute(&self) -> MultiplicationPrecomputation { - let num_digits = digits_per_scalar::(); - let mut powers = Vec::with_capacity(num_digits); - powers.push(*self); - for i in 1..num_digits { - let mut power_i = powers[i - 1]; - for _j in 0..WINDOW_BITS { - power_i = power_i.double(); - } - powers.push(power_i); - } - - MultiplicationPrecomputation { powers } - } - - pub fn mul_with_precomputation( - &self, - scalar: C::ScalarField, - precomputation: MultiplicationPrecomputation, - ) -> Self { - // Yao's method; see https://koclab.cs.ucsb.edu/teaching/ecc/eccPapers/Doche-ch09.pdf - let precomputed_powers = precomputation.powers; - - let digits = to_digits::(&scalar); - - let mut y = ProjectivePoint::ZERO; - let mut u = ProjectivePoint::ZERO; - let mut all_summands = Vec::new(); - for j in (1..BASE).rev() { - let mut u_summands = Vec::new(); - for (i, &digit) in digits.iter().enumerate() { - if digit == j as u64 { - u_summands.push(precomputed_powers[i]); - } - } - all_summands.push(u_summands); - } - - let all_sums: Vec> = all_summands - .iter() - .cloned() - .map(|vec| vec.iter().fold(ProjectivePoint::ZERO, |a, &b| a + b)) - .collect(); - for i in 0..all_sums.len() { - u = u + all_sums[i]; - y = y + u; - } - y - } -} - -impl Mul> for CurveScalar { - type Output = ProjectivePoint; - - fn mul(self, rhs: ProjectivePoint) -> Self::Output { - let precomputation = rhs.mul_precompute(); - rhs.mul_with_precomputation(self.0, precomputation) - } -} - -#[allow(clippy::assertions_on_constants)] -fn to_digits(x: &C::ScalarField) -> Vec { - debug_assert!( - 64 % WINDOW_BITS == 0, - "For simplicity, only power-of-two window sizes are handled for now" - ); - let digits_per_u64 = 64 / WINDOW_BITS; - let mut digits = Vec::with_capacity(digits_per_scalar::()); - for limb in x.to_canonical_biguint().to_u64_digits() { - for j in 0..digits_per_u64 { - digits.push((limb >> (j * WINDOW_BITS) as u64) % BASE as u64); - } - } - - digits -} diff --git a/plonky2/src/curve/curve_summation.rs b/plonky2/src/curve/curve_summation.rs deleted file mode 100644 index 7ea01524..00000000 --- a/plonky2/src/curve/curve_summation.rs +++ /dev/null @@ -1,239 +0,0 @@ -use std::iter::Sum; - -use plonky2_field::field_types::Field; -use plonky2_field::ops::Square; - -use crate::curve::curve_types::{AffinePoint, Curve, ProjectivePoint}; - -impl Sum> for ProjectivePoint { - fn sum>>(iter: I) -> ProjectivePoint { - let points: Vec<_> = iter.collect(); - affine_summation_best(points) - } -} - -impl Sum for ProjectivePoint { - fn sum>>(iter: I) -> ProjectivePoint { - iter.fold(ProjectivePoint::ZERO, |acc, x| acc + x) - } -} - -pub fn affine_summation_best(summation: Vec>) -> ProjectivePoint { - let result = affine_multisummation_best(vec![summation]); - debug_assert_eq!(result.len(), 1); - result[0] -} - -pub fn affine_multisummation_best( - summations: Vec>>, -) -> Vec> { - let pairwise_sums: usize = summations.iter().map(|summation| summation.len() / 2).sum(); - - // This threshold is chosen based on data from the summation benchmarks. - if pairwise_sums < 70 { - affine_multisummation_pairwise(summations) - } else { - affine_multisummation_batch_inversion(summations) - } -} - -/// Adds each pair of points using an affine + affine = projective formula, then adds up the -/// intermediate sums using a projective formula. -pub fn affine_multisummation_pairwise( - summations: Vec>>, -) -> Vec> { - summations - .into_iter() - .map(affine_summation_pairwise) - .collect() -} - -/// Adds each pair of points using an affine + affine = projective formula, then adds up the -/// intermediate sums using a projective formula. -pub fn affine_summation_pairwise(points: Vec>) -> ProjectivePoint { - let mut reduced_points: Vec> = Vec::new(); - for chunk in points.chunks(2) { - match chunk.len() { - 1 => reduced_points.push(chunk[0].to_projective()), - 2 => reduced_points.push(chunk[0] + chunk[1]), - _ => panic!(), - } - } - // TODO: Avoid copying (deref) - reduced_points - .iter() - .fold(ProjectivePoint::ZERO, |sum, x| sum + *x) -} - -/// Computes several summations of affine points by applying an affine group law, except that the -/// divisions are batched via Montgomery's trick. -pub fn affine_summation_batch_inversion( - summation: Vec>, -) -> ProjectivePoint { - let result = affine_multisummation_batch_inversion(vec![summation]); - debug_assert_eq!(result.len(), 1); - result[0] -} - -/// Computes several summations of affine points by applying an affine group law, except that the -/// divisions are batched via Montgomery's trick. -pub fn affine_multisummation_batch_inversion( - summations: Vec>>, -) -> Vec> { - let mut elements_to_invert = Vec::new(); - - // For each pair of points, (x1, y1) and (x2, y2), that we're going to add later, we want to - // invert either y (if the points are equal) or x1 - x2 (otherwise). We will use these later. - for summation in &summations { - let n = summation.len(); - // The special case for n=0 is to avoid underflow. - let range_end = if n == 0 { 0 } else { n - 1 }; - - for i in (0..range_end).step_by(2) { - let p1 = summation[i]; - let p2 = summation[i + 1]; - let AffinePoint { - x: x1, - y: y1, - zero: zero1, - } = p1; - let AffinePoint { - x: x2, - y: _y2, - zero: zero2, - } = p2; - - if zero1 || zero2 || p1 == -p2 { - // These are trivial cases where we won't need any inverse. - } else if p1 == p2 { - elements_to_invert.push(y1.double()); - } else { - elements_to_invert.push(x1 - x2); - } - } - } - - let inverses: Vec = - C::BaseField::batch_multiplicative_inverse(&elements_to_invert); - - let mut all_reduced_points = Vec::with_capacity(summations.len()); - let mut inverse_index = 0; - for summation in summations { - let n = summation.len(); - let mut reduced_points = Vec::with_capacity((n + 1) / 2); - - // The special case for n=0 is to avoid underflow. - let range_end = if n == 0 { 0 } else { n - 1 }; - - for i in (0..range_end).step_by(2) { - let p1 = summation[i]; - let p2 = summation[i + 1]; - let AffinePoint { - x: x1, - y: y1, - zero: zero1, - } = p1; - let AffinePoint { - x: x2, - y: y2, - zero: zero2, - } = p2; - - let sum = if zero1 { - p2 - } else if zero2 { - p1 - } else if p1 == -p2 { - AffinePoint::ZERO - } else { - // It's a non-trivial case where we need one of the inverses we computed earlier. - let inverse = inverses[inverse_index]; - inverse_index += 1; - - if p1 == p2 { - // This is the doubling case. - let mut numerator = x1.square().triple(); - if C::A.is_nonzero() { - numerator += C::A; - } - let quotient = numerator * inverse; - let x3 = quotient.square() - x1.double(); - let y3 = quotient * (x1 - x3) - y1; - AffinePoint::nonzero(x3, y3) - } else { - // This is the general case. We use the incomplete addition formulas 4.3 and 4.4. - let quotient = (y1 - y2) * inverse; - let x3 = quotient.square() - x1 - x2; - let y3 = quotient * (x1 - x3) - y1; - AffinePoint::nonzero(x3, y3) - } - }; - reduced_points.push(sum); - } - - // If n is odd, the last point was not part of a pair. - if n % 2 == 1 { - reduced_points.push(summation[n - 1]); - } - - all_reduced_points.push(reduced_points); - } - - // We should have consumed all of the inverses from the batch computation. - debug_assert_eq!(inverse_index, inverses.len()); - - // Recurse with our smaller set of points. - affine_multisummation_best(all_reduced_points) -} - -#[cfg(test)] -mod tests { - use crate::curve::curve_summation::{ - affine_summation_batch_inversion, affine_summation_pairwise, - }; - use crate::curve::curve_types::{Curve, ProjectivePoint}; - use crate::curve::secp256k1::Secp256K1; - - #[test] - fn test_pairwise_affine_summation() { - let g_affine = Secp256K1::GENERATOR_AFFINE; - let g2_affine = (g_affine + g_affine).to_affine(); - let g3_affine = (g_affine + g_affine + g_affine).to_affine(); - let g2_proj = g2_affine.to_projective(); - let g3_proj = g3_affine.to_projective(); - assert_eq!( - affine_summation_pairwise::(vec![g_affine, g_affine]), - g2_proj - ); - assert_eq!( - affine_summation_pairwise::(vec![g_affine, g2_affine]), - g3_proj - ); - assert_eq!( - affine_summation_pairwise::(vec![g_affine, g_affine, g_affine]), - g3_proj - ); - assert_eq!( - affine_summation_pairwise::(vec![]), - ProjectivePoint::ZERO - ); - } - - #[test] - fn test_pairwise_affine_summation_batch_inversion() { - let g = Secp256K1::GENERATOR_AFFINE; - let g_proj = g.to_projective(); - assert_eq!( - affine_summation_batch_inversion::(vec![g, g]), - g_proj + g_proj - ); - assert_eq!( - affine_summation_batch_inversion::(vec![g, g, g]), - g_proj + g_proj + g_proj - ); - assert_eq!( - affine_summation_batch_inversion::(vec![]), - ProjectivePoint::ZERO - ); - } -} diff --git a/plonky2/src/curve/curve_types.rs b/plonky2/src/curve/curve_types.rs deleted file mode 100644 index 264120c7..00000000 --- a/plonky2/src/curve/curve_types.rs +++ /dev/null @@ -1,282 +0,0 @@ -use std::fmt::Debug; -use std::hash::Hash; -use std::ops::Neg; - -use plonky2_field::field_types::{Field, PrimeField}; -use plonky2_field::ops::Square; -use serde::{Deserialize, Serialize}; - -// To avoid implementation conflicts from associated types, -// see https://github.com/rust-lang/rust/issues/20400 -pub struct CurveScalar(pub ::ScalarField); - -/// A short Weierstrass curve. -pub trait Curve: 'static + Sync + Sized + Copy + Debug { - type BaseField: PrimeField; - type ScalarField: PrimeField; - - const A: Self::BaseField; - const B: Self::BaseField; - - const GENERATOR_AFFINE: AffinePoint; - - const GENERATOR_PROJECTIVE: ProjectivePoint = ProjectivePoint { - x: Self::GENERATOR_AFFINE.x, - y: Self::GENERATOR_AFFINE.y, - z: Self::BaseField::ONE, - }; - - fn convert(x: Self::ScalarField) -> CurveScalar { - CurveScalar(x) - } - - fn is_safe_curve() -> bool { - // Added additional check to prevent using vulnerabilties in case a discriminant is equal to 0. - (Self::A.cube().double().double() + Self::B.square().triple().triple().triple()) - .is_nonzero() - } -} - -/// A point on a short Weierstrass curve, represented in affine coordinates. -#[derive(Copy, Clone, Debug, Deserialize, Serialize)] -pub struct AffinePoint { - pub x: C::BaseField, - pub y: C::BaseField, - pub zero: bool, -} - -impl AffinePoint { - pub const ZERO: Self = Self { - x: C::BaseField::ZERO, - y: C::BaseField::ZERO, - zero: true, - }; - - pub fn nonzero(x: C::BaseField, y: C::BaseField) -> Self { - let point = Self { x, y, zero: false }; - debug_assert!(point.is_valid()); - point - } - - pub fn is_valid(&self) -> bool { - let Self { x, y, zero } = *self; - zero || y.square() == x.cube() + C::A * x + C::B - } - - pub fn to_projective(&self) -> ProjectivePoint { - let Self { x, y, zero } = *self; - let z = if zero { - C::BaseField::ZERO - } else { - C::BaseField::ONE - }; - - ProjectivePoint { x, y, z } - } - - pub fn batch_to_projective(affine_points: &[Self]) -> Vec> { - affine_points.iter().map(Self::to_projective).collect() - } - - pub fn double(&self) -> Self { - let AffinePoint { x: x1, y: y1, zero } = *self; - - if zero { - return AffinePoint::ZERO; - } - - let double_y = y1.double(); - let inv_double_y = double_y.inverse(); // (2y)^(-1) - let triple_xx = x1.square().triple(); // 3x^2 - let lambda = (triple_xx + C::A) * inv_double_y; - let x3 = lambda.square() - self.x.double(); - let y3 = lambda * (x1 - x3) - y1; - - Self { - x: x3, - y: y3, - zero: false, - } - } -} - -impl PartialEq for AffinePoint { - fn eq(&self, other: &Self) -> bool { - let AffinePoint { - x: x1, - y: y1, - zero: zero1, - } = *self; - let AffinePoint { - x: x2, - y: y2, - zero: zero2, - } = *other; - if zero1 || zero2 { - return zero1 == zero2; - } - x1 == x2 && y1 == y2 - } -} - -impl Eq for AffinePoint {} - -impl Hash for AffinePoint { - fn hash(&self, state: &mut H) { - if self.zero { - self.zero.hash(state); - } else { - self.x.hash(state); - self.y.hash(state); - } - } -} - -/// A point on a short Weierstrass curve, represented in projective coordinates. -#[derive(Copy, Clone, Debug)] -pub struct ProjectivePoint { - pub x: C::BaseField, - pub y: C::BaseField, - pub z: C::BaseField, -} - -impl ProjectivePoint { - pub const ZERO: Self = Self { - x: C::BaseField::ZERO, - y: C::BaseField::ONE, - z: C::BaseField::ZERO, - }; - - pub fn nonzero(x: C::BaseField, y: C::BaseField, z: C::BaseField) -> Self { - let point = Self { x, y, z }; - debug_assert!(point.is_valid()); - point - } - - pub fn is_valid(&self) -> bool { - let Self { x, y, z } = *self; - z.is_zero() || y.square() * z == x.cube() + C::A * x * z.square() + C::B * z.cube() - } - - pub fn to_affine(&self) -> AffinePoint { - let Self { x, y, z } = *self; - if z == C::BaseField::ZERO { - AffinePoint::ZERO - } else { - let z_inv = z.inverse(); - AffinePoint::nonzero(x * z_inv, y * z_inv) - } - } - - pub fn batch_to_affine(proj_points: &[Self]) -> Vec> { - let n = proj_points.len(); - let zs: Vec = proj_points.iter().map(|pp| pp.z).collect(); - let z_invs = C::BaseField::batch_multiplicative_inverse(&zs); - - let mut result = Vec::with_capacity(n); - for i in 0..n { - let Self { x, y, z } = proj_points[i]; - result.push(if z == C::BaseField::ZERO { - AffinePoint::ZERO - } else { - let z_inv = z_invs[i]; - AffinePoint::nonzero(x * z_inv, y * z_inv) - }); - } - result - } - - // From https://www.hyperelliptic.org/EFD/g1p/data/shortw/projective/doubling/dbl-2007-bl - pub fn double(&self) -> Self { - let Self { x, y, z } = *self; - if z == C::BaseField::ZERO { - return ProjectivePoint::ZERO; - } - - let xx = x.square(); - let zz = z.square(); - let mut w = xx.triple(); - if C::A.is_nonzero() { - w += C::A * zz; - } - let s = y.double() * z; - let r = y * s; - let rr = r.square(); - let b = (x + r).square() - (xx + rr); - let h = w.square() - b.double(); - let x3 = h * s; - let y3 = w * (b - h) - rr.double(); - let z3 = s.cube(); - Self { - x: x3, - y: y3, - z: z3, - } - } - - pub fn add_slices(a: &[Self], b: &[Self]) -> Vec { - assert_eq!(a.len(), b.len()); - a.iter() - .zip(b.iter()) - .map(|(&a_i, &b_i)| a_i + b_i) - .collect() - } - - pub fn neg(&self) -> Self { - Self { - x: self.x, - y: -self.y, - z: self.z, - } - } -} - -impl PartialEq for ProjectivePoint { - fn eq(&self, other: &Self) -> bool { - let ProjectivePoint { - x: x1, - y: y1, - z: z1, - } = *self; - let ProjectivePoint { - x: x2, - y: y2, - z: z2, - } = *other; - if z1 == C::BaseField::ZERO || z2 == C::BaseField::ZERO { - return z1 == z2; - } - - // We want to compare (x1/z1, y1/z1) == (x2/z2, y2/z2). - // But to avoid field division, it is better to compare (x1*z2, y1*z2) == (x2*z1, y2*z1). - x1 * z2 == x2 * z1 && y1 * z2 == y2 * z1 - } -} - -impl Eq for ProjectivePoint {} - -impl Neg for AffinePoint { - type Output = AffinePoint; - - fn neg(self) -> Self::Output { - let AffinePoint { x, y, zero } = self; - AffinePoint { x, y: -y, zero } - } -} - -impl Neg for ProjectivePoint { - type Output = ProjectivePoint; - - fn neg(self) -> Self::Output { - let ProjectivePoint { x, y, z } = self; - ProjectivePoint { x, y: -y, z } - } -} - -pub fn base_to_scalar(x: C::BaseField) -> C::ScalarField { - C::ScalarField::from_biguint(x.to_canonical_biguint()) -} - -pub fn scalar_to_base(x: C::ScalarField) -> C::BaseField { - C::BaseField::from_biguint(x.to_canonical_biguint()) -} diff --git a/plonky2/src/curve/ecdsa.rs b/plonky2/src/curve/ecdsa.rs deleted file mode 100644 index cabe038a..00000000 --- a/plonky2/src/curve/ecdsa.rs +++ /dev/null @@ -1,78 +0,0 @@ -use serde::{Deserialize, Serialize}; - -use crate::curve::curve_msm::msm_parallel; -use crate::curve::curve_types::{base_to_scalar, AffinePoint, Curve, CurveScalar}; -use crate::field::field_types::Field; - -#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct ECDSASignature { - pub r: C::ScalarField, - pub s: C::ScalarField, -} - -#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct ECDSASecretKey(pub C::ScalarField); - -#[derive(Copy, Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct ECDSAPublicKey(pub AffinePoint); - -pub fn sign_message(msg: C::ScalarField, sk: ECDSASecretKey) -> ECDSASignature { - let (k, rr) = { - let mut k = C::ScalarField::rand(); - let mut rr = (CurveScalar(k) * C::GENERATOR_PROJECTIVE).to_affine(); - while rr.x == C::BaseField::ZERO { - k = C::ScalarField::rand(); - rr = (CurveScalar(k) * C::GENERATOR_PROJECTIVE).to_affine(); - } - (k, rr) - }; - let r = base_to_scalar::(rr.x); - - let s = k.inverse() * (msg + r * sk.0); - - ECDSASignature { r, s } -} - -pub fn verify_message( - msg: C::ScalarField, - sig: ECDSASignature, - pk: ECDSAPublicKey, -) -> bool { - let ECDSASignature { r, s } = sig; - - assert!(pk.0.is_valid()); - - let c = s.inverse(); - let u1 = msg * c; - let u2 = r * c; - - let g = C::GENERATOR_PROJECTIVE; - let w = 5; // Experimentally fastest - let point_proj = msm_parallel(&[u1, u2], &[g, pk.0.to_projective()], w); - let point = point_proj.to_affine(); - - let x = base_to_scalar::(point.x); - r == x -} - -#[cfg(test)] -mod tests { - use crate::curve::curve_types::{Curve, CurveScalar}; - use crate::curve::ecdsa::{sign_message, verify_message, ECDSAPublicKey, ECDSASecretKey}; - use crate::curve::secp256k1::Secp256K1; - use crate::field::field_types::Field; - use crate::field::secp256k1_scalar::Secp256K1Scalar; - - #[test] - fn test_ecdsa_native() { - type C = Secp256K1; - - let msg = Secp256K1Scalar::rand(); - let sk = ECDSASecretKey(Secp256K1Scalar::rand()); - let pk = ECDSAPublicKey((CurveScalar(sk.0) * C::GENERATOR_PROJECTIVE).to_affine()); - - let sig = sign_message(msg, sk); - let result = verify_message(msg, sig, pk); - assert!(result); - } -} diff --git a/plonky2/src/curve/glv.rs b/plonky2/src/curve/glv.rs deleted file mode 100644 index aeeb463e..00000000 --- a/plonky2/src/curve/glv.rs +++ /dev/null @@ -1,136 +0,0 @@ -use num::rational::Ratio; -use num::BigUint; -use plonky2_field::field_types::{Field, PrimeField}; -use plonky2_field::secp256k1_base::Secp256K1Base; -use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - -use crate::curve::curve_msm::msm_parallel; -use crate::curve::curve_types::{AffinePoint, ProjectivePoint}; -use crate::curve::secp256k1::Secp256K1; - -pub const GLV_BETA: Secp256K1Base = Secp256K1Base([ - 13923278643952681454, - 11308619431505398165, - 7954561588662645993, - 8856726876819556112, -]); - -pub const GLV_S: Secp256K1Scalar = Secp256K1Scalar([ - 16069571880186789234, - 1310022930574435960, - 11900229862571533402, - 6008836872998760672, -]); - -const A1: Secp256K1Scalar = Secp256K1Scalar([16747920425669159701, 3496713202691238861, 0, 0]); - -const MINUS_B1: Secp256K1Scalar = - Secp256K1Scalar([8022177200260244675, 16448129721693014056, 0, 0]); - -const A2: Secp256K1Scalar = Secp256K1Scalar([6323353552219852760, 1498098850674701302, 1, 0]); - -const B2: Secp256K1Scalar = Secp256K1Scalar([16747920425669159701, 3496713202691238861, 0, 0]); - -pub fn decompose_secp256k1_scalar( - k: Secp256K1Scalar, -) -> (Secp256K1Scalar, Secp256K1Scalar, bool, bool) { - let p = Secp256K1Scalar::order(); - let c1_biguint = Ratio::new( - B2.to_canonical_biguint() * k.to_canonical_biguint(), - p.clone(), - ) - .round() - .to_integer(); - let c1 = Secp256K1Scalar::from_biguint(c1_biguint); - let c2_biguint = Ratio::new( - MINUS_B1.to_canonical_biguint() * k.to_canonical_biguint(), - p.clone(), - ) - .round() - .to_integer(); - let c2 = Secp256K1Scalar::from_biguint(c2_biguint); - - let k1_raw = k - c1 * A1 - c2 * A2; - let k2_raw = c1 * MINUS_B1 - c2 * B2; - debug_assert!(k1_raw + GLV_S * k2_raw == k); - - let two = BigUint::from_slice(&[2]); - let k1_neg = k1_raw.to_canonical_biguint() > p.clone() / two.clone(); - let k1 = if k1_neg { - Secp256K1Scalar::from_biguint(p.clone() - k1_raw.to_canonical_biguint()) - } else { - k1_raw - }; - let k2_neg = k2_raw.to_canonical_biguint() > p.clone() / two; - let k2 = if k2_neg { - Secp256K1Scalar::from_biguint(p - k2_raw.to_canonical_biguint()) - } else { - k2_raw - }; - - (k1, k2, k1_neg, k2_neg) -} - -pub fn glv_mul(p: ProjectivePoint, k: Secp256K1Scalar) -> ProjectivePoint { - let (k1, k2, k1_neg, k2_neg) = decompose_secp256k1_scalar(k); - /*let one = Secp256K1Scalar::ONE; - let m1 = if k1_neg { -one } else { one }; - let m2 = if k2_neg { -one } else { one }; - assert!(k1 * m1 + S * k2 * m2 == k);*/ - - let p_affine = p.to_affine(); - let sp = AffinePoint:: { - x: p_affine.x * GLV_BETA, - y: p_affine.y, - zero: p_affine.zero, - }; - - let first = if k1_neg { p.neg() } else { p }; - let second = if k2_neg { - sp.to_projective().neg() - } else { - sp.to_projective() - }; - - msm_parallel(&[k1, k2], &[first, second], 5) -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use plonky2_field::field_types::Field; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - - use crate::curve::curve_types::{Curve, CurveScalar}; - use crate::curve::glv::{decompose_secp256k1_scalar, glv_mul, GLV_S}; - use crate::curve::secp256k1::Secp256K1; - - #[test] - fn test_glv_decompose() -> Result<()> { - let k = Secp256K1Scalar::rand(); - let (k1, k2, k1_neg, k2_neg) = decompose_secp256k1_scalar(k); - let one = Secp256K1Scalar::ONE; - let m1 = if k1_neg { -one } else { one }; - let m2 = if k2_neg { -one } else { one }; - - assert!(k1 * m1 + GLV_S * k2 * m2 == k); - - Ok(()) - } - - #[test] - fn test_glv_mul() -> Result<()> { - for _ in 0..20 { - let k = Secp256K1Scalar::rand(); - - let p = CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE; - - let kp = CurveScalar(k) * p; - let glv = glv_mul(p, k); - - assert!(kp == glv); - } - - Ok(()) - } -} diff --git a/plonky2/src/curve/mod.rs b/plonky2/src/curve/mod.rs deleted file mode 100644 index 1984b0c6..00000000 --- a/plonky2/src/curve/mod.rs +++ /dev/null @@ -1,8 +0,0 @@ -pub mod curve_adds; -pub mod curve_msm; -pub mod curve_multiplication; -pub mod curve_summation; -pub mod curve_types; -pub mod ecdsa; -pub mod glv; -pub mod secp256k1; diff --git a/plonky2/src/curve/secp256k1.rs b/plonky2/src/curve/secp256k1.rs deleted file mode 100644 index 18040dae..00000000 --- a/plonky2/src/curve/secp256k1.rs +++ /dev/null @@ -1,101 +0,0 @@ -use plonky2_field::field_types::Field; -use plonky2_field::secp256k1_base::Secp256K1Base; -use plonky2_field::secp256k1_scalar::Secp256K1Scalar; -use serde::{Deserialize, Serialize}; - -use crate::curve::curve_types::{AffinePoint, Curve}; - -#[derive(Debug, Copy, Clone, Deserialize, Eq, Hash, PartialEq, Serialize)] -pub struct Secp256K1; - -impl Curve for Secp256K1 { - type BaseField = Secp256K1Base; - type ScalarField = Secp256K1Scalar; - - const A: Secp256K1Base = Secp256K1Base::ZERO; - const B: Secp256K1Base = Secp256K1Base([7, 0, 0, 0]); - const GENERATOR_AFFINE: AffinePoint = AffinePoint { - x: SECP256K1_GENERATOR_X, - y: SECP256K1_GENERATOR_Y, - zero: false, - }; -} - -// 55066263022277343669578718895168534326250603453777594175500187360389116729240 -const SECP256K1_GENERATOR_X: Secp256K1Base = Secp256K1Base([ - 0x59F2815B16F81798, - 0x029BFCDB2DCE28D9, - 0x55A06295CE870B07, - 0x79BE667EF9DCBBAC, -]); - -/// 32670510020758816978083085130507043184471273380659243275938904335757337482424 -const SECP256K1_GENERATOR_Y: Secp256K1Base = Secp256K1Base([ - 0x9C47D08FFB10D4B8, - 0xFD17B448A6855419, - 0x5DA4FBFC0E1108A8, - 0x483ADA7726A3C465, -]); - -#[cfg(test)] -mod tests { - use num::BigUint; - use plonky2_field::field_types::Field; - use plonky2_field::field_types::PrimeField; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - - use crate::curve::curve_types::{AffinePoint, Curve, ProjectivePoint}; - use crate::curve::secp256k1::Secp256K1; - - #[test] - fn test_generator() { - let g = Secp256K1::GENERATOR_AFFINE; - assert!(g.is_valid()); - - let neg_g = AffinePoint:: { - x: g.x, - y: -g.y, - zero: g.zero, - }; - assert!(neg_g.is_valid()); - } - - #[test] - fn test_naive_multiplication() { - let g = Secp256K1::GENERATOR_PROJECTIVE; - let ten = Secp256K1Scalar::from_canonical_u64(10); - let product = mul_naive(ten, g); - let sum = g + g + g + g + g + g + g + g + g + g; - assert_eq!(product, sum); - } - - #[test] - fn test_g1_multiplication() { - let lhs = Secp256K1Scalar::from_biguint(BigUint::from_slice(&[ - 1111, 2222, 3333, 4444, 5555, 6666, 7777, 8888, - ])); - assert_eq!( - Secp256K1::convert(lhs) * Secp256K1::GENERATOR_PROJECTIVE, - mul_naive(lhs, Secp256K1::GENERATOR_PROJECTIVE) - ); - } - - /// A simple, somewhat inefficient implementation of multiplication which is used as a reference - /// for correctness. - fn mul_naive( - lhs: Secp256K1Scalar, - rhs: ProjectivePoint, - ) -> ProjectivePoint { - let mut g = rhs; - let mut sum = ProjectivePoint::ZERO; - for limb in lhs.to_canonical_biguint().to_u64_digits().iter() { - for j in 0..64 { - if (limb >> j & 1u64) != 0u64 { - sum = sum + g; - } - g = g.double(); - } - } - sum - } -} diff --git a/plonky2/src/gadgets/biguint.rs b/plonky2/src/gadgets/biguint.rs deleted file mode 100644 index c9ad7280..00000000 --- a/plonky2/src/gadgets/biguint.rs +++ /dev/null @@ -1,418 +0,0 @@ -use std::marker::PhantomData; - -use num::{BigUint, Integer, Zero}; -use plonky2_field::extension_field::Extendable; - -use crate::gadgets::arithmetic_u32::U32Target; -use crate::hash::hash_types::RichField; -use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::{BoolTarget, Target}; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; - -#[derive(Clone, Debug)] -pub struct BigUintTarget { - pub limbs: Vec, -} - -impl BigUintTarget { - pub fn num_limbs(&self) -> usize { - self.limbs.len() - } - - pub fn get_limb(&self, i: usize) -> U32Target { - self.limbs[i] - } -} - -impl, const D: usize> CircuitBuilder { - pub fn constant_biguint(&mut self, value: &BigUint) -> BigUintTarget { - let limb_values = value.to_u32_digits(); - let limbs = limb_values.iter().map(|&l| self.constant_u32(l)).collect(); - - BigUintTarget { limbs } - } - - pub fn zero_biguint(&mut self) -> BigUintTarget { - self.constant_biguint(&BigUint::zero()) - } - - pub fn connect_biguint(&mut self, lhs: &BigUintTarget, rhs: &BigUintTarget) { - let min_limbs = lhs.num_limbs().min(rhs.num_limbs()); - for i in 0..min_limbs { - self.connect_u32(lhs.get_limb(i), rhs.get_limb(i)); - } - - for i in min_limbs..lhs.num_limbs() { - self.assert_zero_u32(lhs.get_limb(i)); - } - for i in min_limbs..rhs.num_limbs() { - self.assert_zero_u32(rhs.get_limb(i)); - } - } - - pub fn pad_biguints( - &mut self, - a: &BigUintTarget, - b: &BigUintTarget, - ) -> (BigUintTarget, BigUintTarget) { - if a.num_limbs() > b.num_limbs() { - let mut padded_b = b.clone(); - for _ in b.num_limbs()..a.num_limbs() { - padded_b.limbs.push(self.zero_u32()); - } - - (a.clone(), padded_b) - } else { - let mut padded_a = a.clone(); - for _ in a.num_limbs()..b.num_limbs() { - padded_a.limbs.push(self.zero_u32()); - } - - (padded_a, b.clone()) - } - } - - pub fn cmp_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BoolTarget { - let (a, b) = self.pad_biguints(a, b); - - self.list_le_u32(a.limbs, b.limbs) - } - - pub fn add_virtual_biguint_target(&mut self, num_limbs: usize) -> BigUintTarget { - let limbs = self.add_virtual_u32_targets(num_limbs); - - BigUintTarget { limbs } - } - - // Add two `BigUintTarget`s. - pub fn add_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { - let num_limbs = a.num_limbs().max(b.num_limbs()); - - let mut combined_limbs = vec![]; - let mut carry = self.zero_u32(); - for i in 0..num_limbs { - let a_limb = (i < a.num_limbs()) - .then(|| a.limbs[i]) - .unwrap_or_else(|| self.zero_u32()); - let b_limb = (i < b.num_limbs()) - .then(|| b.limbs[i]) - .unwrap_or_else(|| self.zero_u32()); - - let (new_limb, new_carry) = self.add_many_u32(&[carry, a_limb, b_limb]); - carry = new_carry; - combined_limbs.push(new_limb); - } - combined_limbs.push(carry); - - BigUintTarget { - limbs: combined_limbs, - } - } - - // Subtract two `BigUintTarget`s. We assume that the first is larger than the second. - pub fn sub_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { - let (a, b) = self.pad_biguints(a, b); - let num_limbs = a.limbs.len(); - - let mut result_limbs = vec![]; - - let mut borrow = self.zero_u32(); - for i in 0..num_limbs { - let (result, new_borrow) = self.sub_u32(a.limbs[i], b.limbs[i], borrow); - result_limbs.push(result); - borrow = new_borrow; - } - // Borrow should be zero here. - - BigUintTarget { - limbs: result_limbs, - } - } - - pub fn mul_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { - let total_limbs = a.limbs.len() + b.limbs.len(); - - let mut to_add = vec![vec![]; total_limbs]; - for i in 0..a.limbs.len() { - for j in 0..b.limbs.len() { - let (product, carry) = self.mul_u32(a.limbs[i], b.limbs[j]); - to_add[i + j].push(product); - to_add[i + j + 1].push(carry); - } - } - - let mut combined_limbs = vec![]; - let mut carry = self.zero_u32(); - for summands in &mut to_add { - let (new_result, new_carry) = self.add_u32s_with_carry(summands, carry); - combined_limbs.push(new_result); - carry = new_carry; - } - combined_limbs.push(carry); - - BigUintTarget { - limbs: combined_limbs, - } - } - - pub fn mul_biguint_by_bool(&mut self, a: &BigUintTarget, b: BoolTarget) -> BigUintTarget { - let t = b.target; - - BigUintTarget { - limbs: a - .limbs - .iter() - .map(|&l| U32Target(self.mul(l.0, t))) - .collect(), - } - } - - // Returns x * y + z. This is no more efficient than mul-then-add; it's purely for convenience (only need to call one CircuitBuilder function). - pub fn mul_add_biguint( - &mut self, - x: &BigUintTarget, - y: &BigUintTarget, - z: &BigUintTarget, - ) -> BigUintTarget { - let prod = self.mul_biguint(x, y); - self.add_biguint(&prod, z) - } - - pub fn div_rem_biguint( - &mut self, - a: &BigUintTarget, - b: &BigUintTarget, - ) -> (BigUintTarget, BigUintTarget) { - let a_len = a.limbs.len(); - let b_len = b.limbs.len(); - let div_num_limbs = if b_len > a_len + 1 { - 0 - } else { - a_len - b_len + 1 - }; - let div = self.add_virtual_biguint_target(div_num_limbs); - let rem = self.add_virtual_biguint_target(b_len); - - self.add_simple_generator(BigUintDivRemGenerator:: { - a: a.clone(), - b: b.clone(), - div: div.clone(), - rem: rem.clone(), - _phantom: PhantomData, - }); - - let div_b = self.mul_biguint(&div, b); - let div_b_plus_rem = self.add_biguint(&div_b, &rem); - self.connect_biguint(a, &div_b_plus_rem); - - let cmp_rem_b = self.cmp_biguint(&rem, b); - self.assert_one(cmp_rem_b.target); - - (div, rem) - } - - pub fn div_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { - let (div, _rem) = self.div_rem_biguint(a, b); - div - } - - pub fn rem_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { - let (_div, rem) = self.div_rem_biguint(a, b); - rem - } -} - -#[derive(Debug)] -struct BigUintDivRemGenerator, const D: usize> { - a: BigUintTarget, - b: BigUintTarget, - div: BigUintTarget, - rem: BigUintTarget, - _phantom: PhantomData, -} - -impl, const D: usize> SimpleGenerator - for BigUintDivRemGenerator -{ - fn dependencies(&self) -> Vec { - self.a - .limbs - .iter() - .chain(&self.b.limbs) - .map(|&l| l.0) - .collect() - } - - fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let a = witness.get_biguint_target(self.a.clone()); - let b = witness.get_biguint_target(self.b.clone()); - let (div, rem) = a.div_rem(&b); - - out_buffer.set_biguint_target(self.div.clone(), div); - out_buffer.set_biguint_target(self.rem.clone(), rem); - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use num::{BigUint, FromPrimitive, Integer}; - use rand::Rng; - - use crate::iop::witness::Witness; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::{ - iop::witness::PartialWitness, - plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, verifier::verify}, - }; - - #[test] - fn test_biguint_add() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let mut rng = rand::thread_rng(); - - let x_value = BigUint::from_u128(rng.gen()).unwrap(); - let y_value = BigUint::from_u128(rng.gen()).unwrap(); - let expected_z_value = &x_value + &y_value; - - let config = CircuitConfig::standard_recursion_config(); - let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.add_virtual_biguint_target(x_value.to_u32_digits().len()); - let y = builder.add_virtual_biguint_target(y_value.to_u32_digits().len()); - let z = builder.add_biguint(&x, &y); - let expected_z = builder.add_virtual_biguint_target(expected_z_value.to_u32_digits().len()); - builder.connect_biguint(&z, &expected_z); - - pw.set_biguint_target(&x, &x_value); - pw.set_biguint_target(&y, &y_value); - pw.set_biguint_target(&expected_z, &expected_z_value); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_biguint_sub() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let mut rng = rand::thread_rng(); - - let mut x_value = BigUint::from_u128(rng.gen()).unwrap(); - let mut y_value = BigUint::from_u128(rng.gen()).unwrap(); - if y_value > x_value { - (x_value, y_value) = (y_value, x_value); - } - let expected_z_value = &x_value - &y_value; - - let config = CircuitConfig::standard_recursion_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.constant_biguint(&x_value); - let y = builder.constant_biguint(&y_value); - let z = builder.sub_biguint(&x, &y); - let expected_z = builder.constant_biguint(&expected_z_value); - - builder.connect_biguint(&z, &expected_z); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_biguint_mul() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let mut rng = rand::thread_rng(); - - let x_value = BigUint::from_u128(rng.gen()).unwrap(); - let y_value = BigUint::from_u128(rng.gen()).unwrap(); - let expected_z_value = &x_value * &y_value; - - let config = CircuitConfig::standard_recursion_config(); - let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.add_virtual_biguint_target(x_value.to_u32_digits().len()); - let y = builder.add_virtual_biguint_target(y_value.to_u32_digits().len()); - let z = builder.mul_biguint(&x, &y); - let expected_z = builder.add_virtual_biguint_target(expected_z_value.to_u32_digits().len()); - builder.connect_biguint(&z, &expected_z); - - pw.set_biguint_target(&x, &x_value); - pw.set_biguint_target(&y, &y_value); - pw.set_biguint_target(&expected_z, &expected_z_value); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_biguint_cmp() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let mut rng = rand::thread_rng(); - - let x_value = BigUint::from_u128(rng.gen()).unwrap(); - let y_value = BigUint::from_u128(rng.gen()).unwrap(); - - let config = CircuitConfig::standard_recursion_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.constant_biguint(&x_value); - let y = builder.constant_biguint(&y_value); - let cmp = builder.cmp_biguint(&x, &y); - let expected_cmp = builder.constant_bool(x_value <= y_value); - - builder.connect(cmp.target, expected_cmp.target); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_biguint_div_rem() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let mut rng = rand::thread_rng(); - - let mut x_value = BigUint::from_u128(rng.gen()).unwrap(); - let mut y_value = BigUint::from_u128(rng.gen()).unwrap(); - if y_value > x_value { - (x_value, y_value) = (y_value, x_value); - } - let (expected_div_value, expected_rem_value) = x_value.div_rem(&y_value); - - let config = CircuitConfig::standard_recursion_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.constant_biguint(&x_value); - let y = builder.constant_biguint(&y_value); - let (div, rem) = builder.div_rem_biguint(&x, &y); - - let expected_div = builder.constant_biguint(&expected_div_value); - let expected_rem = builder.constant_biguint(&expected_rem_value); - - builder.connect_biguint(&div, &expected_div); - builder.connect_biguint(&rem, &expected_rem); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } -} diff --git a/plonky2/src/gadgets/curve.rs b/plonky2/src/gadgets/curve.rs deleted file mode 100644 index e4e66a4e..00000000 --- a/plonky2/src/gadgets/curve.rs +++ /dev/null @@ -1,434 +0,0 @@ -use plonky2_field::extension_field::Extendable; -use plonky2_field::field_types::Field; - -use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::iop::target::BoolTarget; -use crate::plonk::circuit_builder::CircuitBuilder; - -/// A Target representing an affine point on the curve `C`. We use incomplete arithmetic for efficiency, -/// so we assume these points are not zero. -#[derive(Clone, Debug)] -pub struct AffinePointTarget { - pub x: NonNativeTarget, - pub y: NonNativeTarget, -} - -impl AffinePointTarget { - pub fn to_vec(&self) -> Vec> { - vec![self.x.clone(), self.y.clone()] - } -} - -impl, const D: usize> CircuitBuilder { - pub fn constant_affine_point( - &mut self, - point: AffinePoint, - ) -> AffinePointTarget { - debug_assert!(!point.zero); - AffinePointTarget { - x: self.constant_nonnative(point.x), - y: self.constant_nonnative(point.y), - } - } - - pub fn connect_affine_point( - &mut self, - lhs: &AffinePointTarget, - rhs: &AffinePointTarget, - ) { - self.connect_nonnative(&lhs.x, &rhs.x); - self.connect_nonnative(&lhs.y, &rhs.y); - } - - pub fn add_virtual_affine_point_target(&mut self) -> AffinePointTarget { - let x = self.add_virtual_nonnative_target(); - let y = self.add_virtual_nonnative_target(); - - AffinePointTarget { x, y } - } - - pub fn curve_assert_valid(&mut self, p: &AffinePointTarget) { - let a = self.constant_nonnative(C::A); - let b = self.constant_nonnative(C::B); - - let y_squared = self.mul_nonnative(&p.y, &p.y); - let x_squared = self.mul_nonnative(&p.x, &p.x); - let x_cubed = self.mul_nonnative(&x_squared, &p.x); - let a_x = self.mul_nonnative(&a, &p.x); - let a_x_plus_b = self.add_nonnative(&a_x, &b); - let rhs = self.add_nonnative(&x_cubed, &a_x_plus_b); - - self.connect_nonnative(&y_squared, &rhs); - } - - pub fn curve_neg(&mut self, p: &AffinePointTarget) -> AffinePointTarget { - let neg_y = self.neg_nonnative(&p.y); - AffinePointTarget { - x: p.x.clone(), - y: neg_y, - } - } - - pub fn curve_conditional_neg( - &mut self, - p: &AffinePointTarget, - b: BoolTarget, - ) -> AffinePointTarget { - AffinePointTarget { - x: p.x.clone(), - y: self.nonnative_conditional_neg(&p.y, b), - } - } - - pub fn curve_double(&mut self, p: &AffinePointTarget) -> AffinePointTarget { - let AffinePointTarget { x, y } = p; - let double_y = self.add_nonnative(y, y); - let inv_double_y = self.inv_nonnative(&double_y); - let x_squared = self.mul_nonnative(x, x); - let double_x_squared = self.add_nonnative(&x_squared, &x_squared); - let triple_x_squared = self.add_nonnative(&double_x_squared, &x_squared); - - let a = self.constant_nonnative(C::A); - let triple_xx_a = self.add_nonnative(&triple_x_squared, &a); - let lambda = self.mul_nonnative(&triple_xx_a, &inv_double_y); - let lambda_squared = self.mul_nonnative(&lambda, &lambda); - let x_double = self.add_nonnative(x, x); - - let x3 = self.sub_nonnative(&lambda_squared, &x_double); - - let x_diff = self.sub_nonnative(x, &x3); - let lambda_x_diff = self.mul_nonnative(&lambda, &x_diff); - - let y3 = self.sub_nonnative(&lambda_x_diff, y); - - AffinePointTarget { x: x3, y: y3 } - } - - pub fn curve_repeated_double( - &mut self, - p: &AffinePointTarget, - n: usize, - ) -> AffinePointTarget { - let mut result = p.clone(); - - for _ in 0..n { - result = self.curve_double(&result); - } - - result - } - - // Add two points, which are assumed to be non-equal. - pub fn curve_add( - &mut self, - p1: &AffinePointTarget, - p2: &AffinePointTarget, - ) -> AffinePointTarget { - let AffinePointTarget { x: x1, y: y1 } = p1; - let AffinePointTarget { x: x2, y: y2 } = p2; - - let u = self.sub_nonnative(y2, y1); - let v = self.sub_nonnative(x2, x1); - let v_inv = self.inv_nonnative(&v); - let s = self.mul_nonnative(&u, &v_inv); - let s_squared = self.mul_nonnative(&s, &s); - let x_sum = self.add_nonnative(x2, x1); - let x3 = self.sub_nonnative(&s_squared, &x_sum); - let x_diff = self.sub_nonnative(x1, &x3); - let prod = self.mul_nonnative(&s, &x_diff); - let y3 = self.sub_nonnative(&prod, y1); - - AffinePointTarget { x: x3, y: y3 } - } - - pub fn curve_conditional_add( - &mut self, - p1: &AffinePointTarget, - p2: &AffinePointTarget, - b: BoolTarget, - ) -> AffinePointTarget { - let not_b = self.not(b); - let sum = self.curve_add(p1, p2); - let x_if_true = self.mul_nonnative_by_bool(&sum.x, b); - let y_if_true = self.mul_nonnative_by_bool(&sum.y, b); - let x_if_false = self.mul_nonnative_by_bool(&p1.x, not_b); - let y_if_false = self.mul_nonnative_by_bool(&p1.y, not_b); - - let x = self.add_nonnative(&x_if_true, &x_if_false); - let y = self.add_nonnative(&y_if_true, &y_if_false); - - AffinePointTarget { x, y } - } - - pub fn curve_scalar_mul( - &mut self, - p: &AffinePointTarget, - n: &NonNativeTarget, - ) -> AffinePointTarget { - let bits = self.split_nonnative_to_bits(n); - - let rando = (CurveScalar(C::ScalarField::rand()) * C::GENERATOR_PROJECTIVE).to_affine(); - let randot = self.constant_affine_point(rando); - // Result starts at `rando`, which is later subtracted, because we don't support arithmetic with the zero point. - let mut result = self.add_virtual_affine_point_target(); - self.connect_affine_point(&randot, &result); - - let mut two_i_times_p = self.add_virtual_affine_point_target(); - self.connect_affine_point(p, &two_i_times_p); - - for &bit in bits.iter() { - let not_bit = self.not(bit); - - let result_plus_2_i_p = self.curve_add(&result, &two_i_times_p); - - let new_x_if_bit = self.mul_nonnative_by_bool(&result_plus_2_i_p.x, bit); - let new_x_if_not_bit = self.mul_nonnative_by_bool(&result.x, not_bit); - let new_y_if_bit = self.mul_nonnative_by_bool(&result_plus_2_i_p.y, bit); - let new_y_if_not_bit = self.mul_nonnative_by_bool(&result.y, not_bit); - - let new_x = self.add_nonnative(&new_x_if_bit, &new_x_if_not_bit); - let new_y = self.add_nonnative(&new_y_if_bit, &new_y_if_not_bit); - - result = AffinePointTarget { x: new_x, y: new_y }; - - two_i_times_p = self.curve_double(&two_i_times_p); - } - - // Subtract off result's intial value of `rando`. - let neg_r = self.curve_neg(&randot); - result = self.curve_add(&result, &neg_r); - - result - } -} - -#[cfg(test)] -mod tests { - use std::ops::Neg; - - use anyhow::Result; - use plonky2_field::field_types::Field; - use plonky2_field::secp256k1_base::Secp256K1Base; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - - use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; - use crate::curve::secp256k1::Secp256K1; - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - #[test] - fn test_curve_point_is_valid() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let g = Secp256K1::GENERATOR_AFFINE; - let g_target = builder.constant_affine_point(g); - let neg_g_target = builder.curve_neg(&g_target); - - builder.curve_assert_valid(&g_target); - builder.curve_assert_valid(&neg_g_target); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - #[should_panic] - fn test_curve_point_is_not_valid() { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let g = Secp256K1::GENERATOR_AFFINE; - let not_g = AffinePoint:: { - x: g.x, - y: g.y + Secp256K1Base::ONE, - zero: g.zero, - }; - let not_g_target = builder.constant_affine_point(not_g); - - builder.curve_assert_valid(¬_g_target); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common).unwrap(); - } - - #[test] - fn test_curve_double() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let g = Secp256K1::GENERATOR_AFFINE; - let g_target = builder.constant_affine_point(g); - let neg_g_target = builder.curve_neg(&g_target); - - let double_g = g.double(); - let double_g_expected = builder.constant_affine_point(double_g); - builder.curve_assert_valid(&double_g_expected); - - let double_neg_g = (-g).double(); - let double_neg_g_expected = builder.constant_affine_point(double_neg_g); - builder.curve_assert_valid(&double_neg_g_expected); - - let double_g_actual = builder.curve_double(&g_target); - let double_neg_g_actual = builder.curve_double(&neg_g_target); - builder.curve_assert_valid(&double_g_actual); - builder.curve_assert_valid(&double_neg_g_actual); - - builder.connect_affine_point(&double_g_expected, &double_g_actual); - builder.connect_affine_point(&double_neg_g_expected, &double_neg_g_actual); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_curve_add() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let g = Secp256K1::GENERATOR_AFFINE; - let double_g = g.double(); - let g_plus_2g = (g + double_g).to_affine(); - let g_plus_2g_expected = builder.constant_affine_point(g_plus_2g); - builder.curve_assert_valid(&g_plus_2g_expected); - - let g_target = builder.constant_affine_point(g); - let double_g_target = builder.curve_double(&g_target); - let g_plus_2g_actual = builder.curve_add(&g_target, &double_g_target); - builder.curve_assert_valid(&g_plus_2g_actual); - - builder.connect_affine_point(&g_plus_2g_expected, &g_plus_2g_actual); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_curve_conditional_add() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let g = Secp256K1::GENERATOR_AFFINE; - let double_g = g.double(); - let g_plus_2g = (g + double_g).to_affine(); - let g_plus_2g_expected = builder.constant_affine_point(g_plus_2g); - - let g_expected = builder.constant_affine_point(g); - let double_g_target = builder.curve_double(&g_expected); - let t = builder._true(); - let f = builder._false(); - let g_plus_2g_actual = builder.curve_conditional_add(&g_expected, &double_g_target, t); - let g_actual = builder.curve_conditional_add(&g_expected, &double_g_target, f); - - builder.connect_affine_point(&g_plus_2g_expected, &g_plus_2g_actual); - builder.connect_affine_point(&g_expected, &g_actual); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - #[ignore] - fn test_curve_mul() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let g = Secp256K1::GENERATOR_PROJECTIVE.to_affine(); - let five = Secp256K1Scalar::from_canonical_usize(5); - let neg_five = five.neg(); - let neg_five_scalar = CurveScalar::(neg_five); - let neg_five_g = (neg_five_scalar * g.to_projective()).to_affine(); - let neg_five_g_expected = builder.constant_affine_point(neg_five_g); - builder.curve_assert_valid(&neg_five_g_expected); - - let g_target = builder.constant_affine_point(g); - let neg_five_target = builder.constant_nonnative(neg_five); - let neg_five_g_actual = builder.curve_scalar_mul(&g_target, &neg_five_target); - builder.curve_assert_valid(&neg_five_g_actual); - - builder.connect_affine_point(&neg_five_g_expected, &neg_five_g_actual); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - #[ignore] - fn test_curve_random() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let rando = - (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); - let randot = builder.constant_affine_point(rando); - - let two_target = builder.constant_nonnative(Secp256K1Scalar::TWO); - let randot_doubled = builder.curve_double(&randot); - let randot_times_two = builder.curve_scalar_mul(&randot, &two_target); - builder.connect_affine_point(&randot_doubled, &randot_times_two); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } -} diff --git a/plonky2/src/gadgets/curve_fixed_base.rs b/plonky2/src/gadgets/curve_fixed_base.rs deleted file mode 100644 index f28e45d1..00000000 --- a/plonky2/src/gadgets/curve_fixed_base.rs +++ /dev/null @@ -1,110 +0,0 @@ -use num::BigUint; -use plonky2_field::extension_field::Extendable; - -use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar}; -use crate::field::field_types::Field; -use crate::gadgets::curve::AffinePointTarget; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::hash::keccak::KeccakHash; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::config::{GenericHashOut, Hasher}; - -impl, const D: usize> CircuitBuilder { - /// Compute windowed fixed-base scalar multiplication, using a 4-bit window. - pub fn fixed_base_curve_mul( - &mut self, - base: AffinePoint, - scalar: &NonNativeTarget, - ) -> AffinePointTarget { - // Holds `(16^i) * base` for `i=0..scalar.value.limbs.len() * 8`. - let scaled_base = (0..scalar.value.limbs.len() * 8).scan(base, |acc, _| { - let tmp = *acc; - for _ in 0..4 { - *acc = acc.double(); - } - Some(tmp) - }); - - let limbs = self.split_nonnative_to_4_bit_limbs(scalar); - - let hash_0 = KeccakHash::<32>::hash_no_pad(&[F::ZERO]); - let hash_0_scalar = C::ScalarField::from_biguint(BigUint::from_bytes_le( - &GenericHashOut::::to_bytes(&hash_0), - )); - let rando = (CurveScalar(hash_0_scalar) * C::GENERATOR_PROJECTIVE).to_affine(); - - let zero = self.zero(); - let mut result = self.constant_affine_point(rando); - // `s * P = sum s_i * P_i` with `P_i = (16^i) * P` and `s = sum s_i * (16^i)`. - for (limb, point) in limbs.into_iter().zip(scaled_base) { - // `muls_point[t] = t * P_i` for `t=0..16`. - let muls_point = (0..16) - .scan(AffinePoint::ZERO, |acc, _| { - let tmp = *acc; - *acc = (point + *acc).to_affine(); - Some(tmp) - }) - .map(|p| self.constant_affine_point(p)) - .collect::>(); - let is_zero = self.is_equal(limb, zero); - let should_add = self.not(is_zero); - // `r = s_i * P_i` - let r = self.random_access_curve_points(limb, muls_point); - result = self.curve_conditional_add(&result, &r, should_add); - } - - let to_add = self.constant_affine_point(-rando); - self.curve_add(&result, &to_add) - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use plonky2_field::field_types::PrimeField; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - - use crate::curve::curve_types::{Curve, CurveScalar}; - use crate::curve::secp256k1::Secp256K1; - use crate::field::field_types::Field; - use crate::iop::witness::{PartialWitness, Witness}; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - #[test] - #[ignore] - fn test_fixed_base() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let mut pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let g = Secp256K1::GENERATOR_AFFINE; - let n = Secp256K1Scalar::rand(); - - let res = (CurveScalar(n) * g.to_projective()).to_affine(); - let res_expected = builder.constant_affine_point(res); - builder.curve_assert_valid(&res_expected); - - let n_target = builder.add_virtual_nonnative_target::(); - pw.set_biguint_target(&n_target.value, &n.to_canonical_biguint()); - - let res_target = builder.fixed_base_curve_mul(g, &n_target); - builder.curve_assert_valid(&res_target); - - builder.connect_affine_point(&res_target, &res_expected); - - dbg!(builder.num_gates()); - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } -} diff --git a/plonky2/src/gadgets/curve_msm.rs b/plonky2/src/gadgets/curve_msm.rs deleted file mode 100644 index fba7c229..00000000 --- a/plonky2/src/gadgets/curve_msm.rs +++ /dev/null @@ -1,133 +0,0 @@ -use num::BigUint; -use plonky2_field::extension_field::Extendable; - -use crate::curve::curve_types::{Curve, CurveScalar}; -use crate::field::field_types::Field; -use crate::gadgets::curve::AffinePointTarget; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::hash::keccak::KeccakHash; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::config::{GenericHashOut, Hasher}; - -impl, const D: usize> CircuitBuilder { - /// Computes `n*p + m*q` using windowed MSM, with a 2-bit window. - /// See Algorithm 9.23 in Handbook of Elliptic and Hyperelliptic Curve Cryptography for a - /// description. - /// Note: Doesn't work if `p == q`. - pub fn curve_msm( - &mut self, - p: &AffinePointTarget, - q: &AffinePointTarget, - n: &NonNativeTarget, - m: &NonNativeTarget, - ) -> AffinePointTarget { - let limbs_n = self.split_nonnative_to_2_bit_limbs(n); - let limbs_m = self.split_nonnative_to_2_bit_limbs(m); - assert_eq!(limbs_n.len(), limbs_m.len()); - let num_limbs = limbs_n.len(); - - let hash_0 = KeccakHash::<32>::hash_no_pad(&[F::ZERO]); - let hash_0_scalar = C::ScalarField::from_biguint(BigUint::from_bytes_le( - &GenericHashOut::::to_bytes(&hash_0), - )); - let rando = (CurveScalar(hash_0_scalar) * C::GENERATOR_PROJECTIVE).to_affine(); - let rando_t = self.constant_affine_point(rando); - let neg_rando = self.constant_affine_point(-rando); - - // Precomputes `precomputation[i + 4*j] = i*p + j*q` for `i,j=0..4`. - let mut precomputation = vec![p.clone(); 16]; - let mut cur_p = rando_t.clone(); - let mut cur_q = rando_t.clone(); - for i in 0..4 { - precomputation[i] = cur_p.clone(); - precomputation[4 * i] = cur_q.clone(); - cur_p = self.curve_add(&cur_p, p); - cur_q = self.curve_add(&cur_q, q); - } - for i in 1..4 { - precomputation[i] = self.curve_add(&precomputation[i], &neg_rando); - precomputation[4 * i] = self.curve_add(&precomputation[4 * i], &neg_rando); - } - for i in 1..4 { - for j in 1..4 { - precomputation[i + 4 * j] = - self.curve_add(&precomputation[i], &precomputation[4 * j]); - } - } - - let four = self.constant(F::from_canonical_usize(4)); - - let zero = self.zero(); - let mut result = rando_t; - for (limb_n, limb_m) in limbs_n.into_iter().zip(limbs_m).rev() { - result = self.curve_repeated_double(&result, 2); - let index = self.mul_add(four, limb_m, limb_n); - let r = self.random_access_curve_points(index, precomputation.clone()); - let is_zero = self.is_equal(index, zero); - let should_add = self.not(is_zero); - result = self.curve_conditional_add(&result, &r, should_add); - } - let starting_point_multiplied = (0..2 * num_limbs).fold(rando, |acc, _| acc.double()); - let to_add = self.constant_affine_point(-starting_point_multiplied); - result = self.curve_add(&result, &to_add); - - result - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - - use crate::curve::curve_types::{Curve, CurveScalar}; - use crate::curve::secp256k1::Secp256K1; - use crate::field::field_types::Field; - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - #[test] - #[ignore] - fn test_curve_msm() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let p = - (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); - let q = - (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); - let n = Secp256K1Scalar::rand(); - let m = Secp256K1Scalar::rand(); - - let res = - (CurveScalar(n) * p.to_projective() + CurveScalar(m) * q.to_projective()).to_affine(); - let res_expected = builder.constant_affine_point(res); - builder.curve_assert_valid(&res_expected); - - let p_target = builder.constant_affine_point(p); - let q_target = builder.constant_affine_point(q); - let n_target = builder.constant_nonnative(n); - let m_target = builder.constant_nonnative(m); - - let res_target = builder.curve_msm(&p_target, &q_target, &n_target, &m_target); - builder.curve_assert_valid(&res_target); - - builder.connect_affine_point(&res_target, &res_expected); - - dbg!(builder.num_gates()); - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } -} diff --git a/plonky2/src/gadgets/curve_windowed_mul.rs b/plonky2/src/gadgets/curve_windowed_mul.rs deleted file mode 100644 index 46c663a0..00000000 --- a/plonky2/src/gadgets/curve_windowed_mul.rs +++ /dev/null @@ -1,224 +0,0 @@ -use std::marker::PhantomData; - -use num::BigUint; -use plonky2_field::extension_field::Extendable; -use plonky2_field::field_types::Field; - -use crate::curve::curve_types::{Curve, CurveScalar}; -use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; -use crate::gadgets::curve::AffinePointTarget; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::hash::keccak::KeccakHash; -use crate::iop::target::{BoolTarget, Target}; -use crate::plonk::circuit_builder::CircuitBuilder; -use crate::plonk::config::{GenericHashOut, Hasher}; - -const WINDOW_SIZE: usize = 4; - -impl, const D: usize> CircuitBuilder { - pub fn precompute_window( - &mut self, - p: &AffinePointTarget, - ) -> Vec> { - let g = (CurveScalar(C::ScalarField::rand()) * C::GENERATOR_PROJECTIVE).to_affine(); - let neg = { - let mut neg = g; - neg.y = -neg.y; - self.constant_affine_point(neg) - }; - - let mut multiples = vec![self.constant_affine_point(g)]; - for i in 1..1 << WINDOW_SIZE { - multiples.push(self.curve_add(p, &multiples[i - 1])); - } - for i in 1..1 << WINDOW_SIZE { - multiples[i] = self.curve_add(&neg, &multiples[i]); - } - multiples - } - - pub fn random_access_curve_points( - &mut self, - access_index: Target, - v: Vec>, - ) -> AffinePointTarget { - let num_limbs = C::BaseField::BITS / 32; - let zero = self.zero_u32(); - let x_limbs: Vec> = (0..num_limbs) - .map(|i| { - v.iter() - .map(|p| p.x.value.limbs.get(i).unwrap_or(&zero).0) - .collect() - }) - .collect(); - let y_limbs: Vec> = (0..num_limbs) - .map(|i| { - v.iter() - .map(|p| p.y.value.limbs.get(i).unwrap_or(&zero).0) - .collect() - }) - .collect(); - - let selected_x_limbs: Vec<_> = x_limbs - .iter() - .map(|limbs| U32Target(self.random_access(access_index, limbs.clone()))) - .collect(); - let selected_y_limbs: Vec<_> = y_limbs - .iter() - .map(|limbs| U32Target(self.random_access(access_index, limbs.clone()))) - .collect(); - - let x = NonNativeTarget { - value: BigUintTarget { - limbs: selected_x_limbs, - }, - _phantom: PhantomData, - }; - let y = NonNativeTarget { - value: BigUintTarget { - limbs: selected_y_limbs, - }, - _phantom: PhantomData, - }; - AffinePointTarget { x, y } - } - - pub fn if_affine_point( - &mut self, - b: BoolTarget, - p1: &AffinePointTarget, - p2: &AffinePointTarget, - ) -> AffinePointTarget { - let new_x = self.if_nonnative(b, &p1.x, &p2.x); - let new_y = self.if_nonnative(b, &p1.y, &p2.y); - AffinePointTarget { x: new_x, y: new_y } - } - - pub fn curve_scalar_mul_windowed( - &mut self, - p: &AffinePointTarget, - n: &NonNativeTarget, - ) -> AffinePointTarget { - let hash_0 = KeccakHash::<25>::hash_no_pad(&[F::ZERO]); - let hash_0_scalar = C::ScalarField::from_biguint(BigUint::from_bytes_le( - &GenericHashOut::::to_bytes(&hash_0), - )); - let starting_point = CurveScalar(hash_0_scalar) * C::GENERATOR_PROJECTIVE; - let starting_point_multiplied = { - let mut cur = starting_point; - for _ in 0..C::ScalarField::BITS { - cur = cur.double(); - } - cur - }; - - let mut result = self.constant_affine_point(starting_point.to_affine()); - - let precomputation = self.precompute_window(p); - let zero = self.zero(); - - let windows = self.split_nonnative_to_4_bit_limbs(n); - for i in (0..windows.len()).rev() { - result = self.curve_repeated_double(&result, WINDOW_SIZE); - let window = windows[i]; - - let to_add = self.random_access_curve_points(window, precomputation.clone()); - let is_zero = self.is_equal(window, zero); - let should_add = self.not(is_zero); - result = self.curve_conditional_add(&result, &to_add, should_add); - } - - let to_subtract = self.constant_affine_point(starting_point_multiplied.to_affine()); - let to_add = self.curve_neg(&to_subtract); - result = self.curve_add(&result, &to_add); - - result - } -} - -#[cfg(test)] -mod tests { - use std::ops::Neg; - - use anyhow::Result; - use plonky2_field::field_types::Field; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - use rand::Rng; - - use crate::curve::curve_types::{Curve, CurveScalar}; - use crate::curve::secp256k1::Secp256K1; - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - #[test] - fn test_random_access_curve_points() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let num_points = 16; - let points: Vec<_> = (0..num_points) - .map(|_| { - let g = (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE) - .to_affine(); - builder.constant_affine_point(g) - }) - .collect(); - - let mut rng = rand::thread_rng(); - let access_index = rng.gen::() % num_points; - - let access_index_target = builder.constant(F::from_canonical_usize(access_index)); - let selected = builder.random_access_curve_points(access_index_target, points.clone()); - let expected = points[access_index].clone(); - builder.connect_affine_point(&selected, &expected); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_curve_windowed_mul() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let g = - (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); - let five = Secp256K1Scalar::from_canonical_usize(5); - let neg_five = five.neg(); - let neg_five_scalar = CurveScalar::(neg_five); - let neg_five_g = (neg_five_scalar * g.to_projective()).to_affine(); - let neg_five_g_expected = builder.constant_affine_point(neg_five_g); - builder.curve_assert_valid(&neg_five_g_expected); - - let g_target = builder.constant_affine_point(g); - let neg_five_target = builder.constant_nonnative(neg_five); - let neg_five_g_actual = builder.curve_scalar_mul_windowed(&g_target, &neg_five_target); - builder.curve_assert_valid(&neg_five_g_actual); - - builder.connect_affine_point(&neg_five_g_expected, &neg_five_g_actual); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } -} diff --git a/plonky2/src/gadgets/ecdsa.rs b/plonky2/src/gadgets/ecdsa.rs deleted file mode 100644 index a376e56a..00000000 --- a/plonky2/src/gadgets/ecdsa.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::marker::PhantomData; - -use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - -use crate::curve::curve_types::Curve; -use crate::curve::secp256k1::Secp256K1; -use crate::field::extension_field::Extendable; -use crate::gadgets::curve::AffinePointTarget; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::plonk::circuit_builder::CircuitBuilder; - -#[derive(Clone, Debug)] -pub struct ECDSASecretKeyTarget(NonNativeTarget); - -#[derive(Clone, Debug)] -pub struct ECDSAPublicKeyTarget(AffinePointTarget); - -#[derive(Clone, Debug)] -pub struct ECDSASignatureTarget { - pub r: NonNativeTarget, - pub s: NonNativeTarget, -} - -impl, const D: usize> CircuitBuilder { - pub fn verify_message( - &mut self, - msg: NonNativeTarget, - sig: ECDSASignatureTarget, - pk: ECDSAPublicKeyTarget, - ) { - let ECDSASignatureTarget { r, s } = sig; - - self.curve_assert_valid(&pk.0); - - let c = self.inv_nonnative(&s); - let u1 = self.mul_nonnative(&msg, &c); - let u2 = self.mul_nonnative(&r, &c); - - let point1 = self.fixed_base_curve_mul(Secp256K1::GENERATOR_AFFINE, &u1); - let point2 = self.glv_mul(&pk.0, &u2); - let point = self.curve_add(&point1, &point2); - - let x = NonNativeTarget:: { - value: point.x.value, - _phantom: PhantomData, - }; - self.connect_nonnative(&r, &x); - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - - use crate::curve::curve_types::{Curve, CurveScalar}; - use crate::curve::ecdsa::{sign_message, ECDSAPublicKey, ECDSASecretKey, ECDSASignature}; - use crate::curve::secp256k1::Secp256K1; - use crate::field::field_types::Field; - use crate::field::secp256k1_scalar::Secp256K1Scalar; - use crate::gadgets::ecdsa::{ECDSAPublicKeyTarget, ECDSASignatureTarget}; - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - fn test_ecdsa_circuit_with_config(config: CircuitConfig) -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - type Curve = Secp256K1; - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let msg = Secp256K1Scalar::rand(); - let msg_target = builder.constant_nonnative(msg); - - let sk = ECDSASecretKey::(Secp256K1Scalar::rand()); - let pk = ECDSAPublicKey((CurveScalar(sk.0) * Curve::GENERATOR_PROJECTIVE).to_affine()); - - let pk_target = ECDSAPublicKeyTarget(builder.constant_affine_point(pk.0)); - - let sig = sign_message(msg, sk); - - let ECDSASignature { r, s } = sig; - let r_target = builder.constant_nonnative(r); - let s_target = builder.constant_nonnative(s); - let sig_target = ECDSASignatureTarget { - r: r_target, - s: s_target, - }; - - builder.verify_message(msg_target, sig_target, pk_target); - - dbg!(builder.num_gates()); - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - #[ignore] - fn test_ecdsa_circuit_narrow() -> Result<()> { - test_ecdsa_circuit_with_config(CircuitConfig::standard_ecc_config()) - } - - #[test] - #[ignore] - fn test_ecdsa_circuit_wide() -> Result<()> { - test_ecdsa_circuit_with_config(CircuitConfig::wide_ecc_config()) - } -} diff --git a/plonky2/src/gadgets/glv.rs b/plonky2/src/gadgets/glv.rs deleted file mode 100644 index 8a0179ec..00000000 --- a/plonky2/src/gadgets/glv.rs +++ /dev/null @@ -1,148 +0,0 @@ -use std::marker::PhantomData; - -use plonky2_field::extension_field::Extendable; -use plonky2_field::secp256k1_base::Secp256K1Base; -use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - -use crate::curve::glv::{decompose_secp256k1_scalar, GLV_BETA, GLV_S}; -use crate::curve::secp256k1::Secp256K1; -use crate::gadgets::curve::AffinePointTarget; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::{BoolTarget, Target}; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; - -impl, const D: usize> CircuitBuilder { - pub fn secp256k1_glv_beta(&mut self) -> NonNativeTarget { - self.constant_nonnative(GLV_BETA) - } - - pub fn decompose_secp256k1_scalar( - &mut self, - k: &NonNativeTarget, - ) -> ( - NonNativeTarget, - NonNativeTarget, - BoolTarget, - BoolTarget, - ) { - let k1 = self.add_virtual_nonnative_target_sized::(4); - let k2 = self.add_virtual_nonnative_target_sized::(4); - let k1_neg = self.add_virtual_bool_target(); - let k2_neg = self.add_virtual_bool_target(); - - self.add_simple_generator(GLVDecompositionGenerator:: { - k: k.clone(), - k1: k1.clone(), - k2: k2.clone(), - k1_neg, - k2_neg, - _phantom: PhantomData, - }); - - // Check that `k1_raw + GLV_S * k2_raw == k`. - let k1_raw = self.nonnative_conditional_neg(&k1, k1_neg); - let k2_raw = self.nonnative_conditional_neg(&k2, k2_neg); - let s = self.constant_nonnative(GLV_S); - let mut should_be_k = self.mul_nonnative(&s, &k2_raw); - should_be_k = self.add_nonnative(&should_be_k, &k1_raw); - self.connect_nonnative(&should_be_k, k); - - (k1, k2, k1_neg, k2_neg) - } - - pub fn glv_mul( - &mut self, - p: &AffinePointTarget, - k: &NonNativeTarget, - ) -> AffinePointTarget { - let (k1, k2, k1_neg, k2_neg) = self.decompose_secp256k1_scalar(k); - - let beta = self.secp256k1_glv_beta(); - let beta_px = self.mul_nonnative(&beta, &p.x); - let sp = AffinePointTarget:: { - x: beta_px, - y: p.y.clone(), - }; - - let p_neg = self.curve_conditional_neg(p, k1_neg); - let sp_neg = self.curve_conditional_neg(&sp, k2_neg); - self.curve_msm(&p_neg, &sp_neg, &k1, &k2) - } -} - -#[derive(Debug)] -struct GLVDecompositionGenerator, const D: usize> { - k: NonNativeTarget, - k1: NonNativeTarget, - k2: NonNativeTarget, - k1_neg: BoolTarget, - k2_neg: BoolTarget, - _phantom: PhantomData, -} - -impl, const D: usize> SimpleGenerator - for GLVDecompositionGenerator -{ - fn dependencies(&self) -> Vec { - self.k.value.limbs.iter().map(|l| l.0).collect() - } - - fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let k = witness.get_nonnative_target(self.k.clone()); - let (k1, k2, k1_neg, k2_neg) = decompose_secp256k1_scalar(k); - - out_buffer.set_nonnative_target(self.k1.clone(), k1); - out_buffer.set_nonnative_target(self.k2.clone(), k2); - out_buffer.set_bool_target(self.k1_neg, k1_neg); - out_buffer.set_bool_target(self.k2_neg, k2_neg); - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use plonky2_field::field_types::Field; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - - use crate::curve::curve_types::{Curve, CurveScalar}; - use crate::curve::glv::glv_mul; - use crate::curve::secp256k1::Secp256K1; - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - #[test] - fn test_glv_gadget() -> Result<()> { - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let rando = - (CurveScalar(Secp256K1Scalar::rand()) * Secp256K1::GENERATOR_PROJECTIVE).to_affine(); - let randot = builder.constant_affine_point(rando); - - let scalar = Secp256K1Scalar::rand(); - let scalar_target = builder.constant_nonnative(scalar); - - let rando_glv_scalar = glv_mul(rando.to_projective(), scalar); - let expected = builder.constant_affine_point(rando_glv_scalar.to_affine()); - let actual = builder.glv_mul(&randot, &scalar_target); - builder.connect_affine_point(&expected, &actual); - - dbg!(builder.num_gates()); - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - - verify(proof, &data.verifier_only, &data.common) - } -} diff --git a/plonky2/src/gadgets/mod.rs b/plonky2/src/gadgets/mod.rs index 50fc0437..d8613337 100644 --- a/plonky2/src/gadgets/mod.rs +++ b/plonky2/src/gadgets/mod.rs @@ -1,21 +1,12 @@ pub mod arithmetic; pub mod arithmetic_extension; pub mod arithmetic_u32; -pub mod biguint; -pub mod curve; -pub mod curve_fixed_base; -pub mod curve_msm; -pub mod curve_windowed_mul; -pub mod ecdsa; -pub mod glv; pub mod hash; pub mod interpolation; pub mod multiple_comparison; -pub mod nonnative; pub mod polynomial; pub mod random_access; pub mod range_check; pub mod select; pub mod split_base; pub(crate) mod split_join; -pub mod split_nonnative; diff --git a/plonky2/src/gadgets/nonnative.rs b/plonky2/src/gadgets/nonnative.rs deleted file mode 100644 index 6c483a86..00000000 --- a/plonky2/src/gadgets/nonnative.rs +++ /dev/null @@ -1,732 +0,0 @@ -use std::marker::PhantomData; - -use num::{BigUint, Integer, One, Zero}; -use plonky2_field::field_types::PrimeField; -use plonky2_field::{extension_field::Extendable, field_types::Field}; -use plonky2_util::ceil_div_usize; - -use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; -use crate::hash::hash_types::RichField; -use crate::iop::generator::{GeneratedValues, SimpleGenerator}; -use crate::iop::target::{BoolTarget, Target}; -use crate::iop::witness::{PartitionWitness, Witness}; -use crate::plonk::circuit_builder::CircuitBuilder; - -#[derive(Clone, Debug)] -pub struct NonNativeTarget { - pub(crate) value: BigUintTarget, - pub(crate) _phantom: PhantomData, -} - -impl, const D: usize> CircuitBuilder { - fn num_nonnative_limbs() -> usize { - ceil_div_usize(FF::BITS, 32) - } - - pub fn biguint_to_nonnative(&mut self, x: &BigUintTarget) -> NonNativeTarget { - NonNativeTarget { - value: x.clone(), - _phantom: PhantomData, - } - } - - pub fn nonnative_to_canonical_biguint( - &mut self, - x: &NonNativeTarget, - ) -> BigUintTarget { - x.value.clone() - } - - pub fn constant_nonnative(&mut self, x: FF) -> NonNativeTarget { - let x_biguint = self.constant_biguint(&x.to_canonical_biguint()); - self.biguint_to_nonnative(&x_biguint) - } - - pub fn zero_nonnative(&mut self) -> NonNativeTarget { - self.constant_nonnative(FF::ZERO) - } - - // Assert that two NonNativeTarget's, both assumed to be in reduced form, are equal. - pub fn connect_nonnative( - &mut self, - lhs: &NonNativeTarget, - rhs: &NonNativeTarget, - ) { - self.connect_biguint(&lhs.value, &rhs.value); - } - - pub fn add_virtual_nonnative_target(&mut self) -> NonNativeTarget { - let num_limbs = Self::num_nonnative_limbs::(); - let value = self.add_virtual_biguint_target(num_limbs); - - NonNativeTarget { - value, - _phantom: PhantomData, - } - } - - pub fn add_virtual_nonnative_target_sized( - &mut self, - num_limbs: usize, - ) -> NonNativeTarget { - let value = self.add_virtual_biguint_target(num_limbs); - - NonNativeTarget { - value, - _phantom: PhantomData, - } - } - - pub fn add_nonnative( - &mut self, - a: &NonNativeTarget, - b: &NonNativeTarget, - ) -> NonNativeTarget { - let sum = self.add_virtual_nonnative_target::(); - let overflow = self.add_virtual_bool_target(); - - self.add_simple_generator(NonNativeAdditionGenerator:: { - a: a.clone(), - b: b.clone(), - sum: sum.clone(), - overflow, - _phantom: PhantomData, - }); - - let sum_expected = self.add_biguint(&a.value, &b.value); - - let modulus = self.constant_biguint(&FF::order()); - let mod_times_overflow = self.mul_biguint_by_bool(&modulus, overflow); - let sum_actual = self.add_biguint(&sum.value, &mod_times_overflow); - self.connect_biguint(&sum_expected, &sum_actual); - - // Range-check result. - // TODO: can potentially leave unreduced until necessary (e.g. when connecting values). - let cmp = self.cmp_biguint(&sum.value, &modulus); - let one = self.one(); - self.connect(cmp.target, one); - - sum - } - - pub fn mul_nonnative_by_bool( - &mut self, - a: &NonNativeTarget, - b: BoolTarget, - ) -> NonNativeTarget { - NonNativeTarget { - value: self.mul_biguint_by_bool(&a.value, b), - _phantom: PhantomData, - } - } - - pub fn if_nonnative( - &mut self, - b: BoolTarget, - x: &NonNativeTarget, - y: &NonNativeTarget, - ) -> NonNativeTarget { - let not_b = self.not(b); - let maybe_x = self.mul_nonnative_by_bool(x, b); - let maybe_y = self.mul_nonnative_by_bool(y, not_b); - self.add_nonnative(&maybe_x, &maybe_y) - } - - pub fn add_many_nonnative( - &mut self, - to_add: &[NonNativeTarget], - ) -> NonNativeTarget { - if to_add.len() == 1 { - return to_add[0].clone(); - } - - let sum = self.add_virtual_nonnative_target::(); - let overflow = self.add_virtual_u32_target(); - let summands = to_add.to_vec(); - - self.add_simple_generator(NonNativeMultipleAddsGenerator:: { - summands: summands.clone(), - sum: sum.clone(), - overflow, - _phantom: PhantomData, - }); - - self.range_check_u32(sum.value.limbs.clone()); - self.range_check_u32(vec![overflow]); - - let sum_expected = summands - .iter() - .fold(self.zero_biguint(), |a, b| self.add_biguint(&a, &b.value)); - - let modulus = self.constant_biguint(&FF::order()); - let overflow_biguint = BigUintTarget { - limbs: vec![overflow], - }; - let mod_times_overflow = self.mul_biguint(&modulus, &overflow_biguint); - let sum_actual = self.add_biguint(&sum.value, &mod_times_overflow); - self.connect_biguint(&sum_expected, &sum_actual); - - // Range-check result. - // TODO: can potentially leave unreduced until necessary (e.g. when connecting values). - let cmp = self.cmp_biguint(&sum.value, &modulus); - let one = self.one(); - self.connect(cmp.target, one); - - sum - } - - // Subtract two `NonNativeTarget`s. - pub fn sub_nonnative( - &mut self, - a: &NonNativeTarget, - b: &NonNativeTarget, - ) -> NonNativeTarget { - let diff = self.add_virtual_nonnative_target::(); - let overflow = self.add_virtual_bool_target(); - - self.add_simple_generator(NonNativeSubtractionGenerator:: { - a: a.clone(), - b: b.clone(), - diff: diff.clone(), - overflow, - _phantom: PhantomData, - }); - - self.range_check_u32(diff.value.limbs.clone()); - self.assert_bool(overflow); - - let diff_plus_b = self.add_biguint(&diff.value, &b.value); - let modulus = self.constant_biguint(&FF::order()); - let mod_times_overflow = self.mul_biguint_by_bool(&modulus, overflow); - let diff_plus_b_reduced = self.sub_biguint(&diff_plus_b, &mod_times_overflow); - self.connect_biguint(&a.value, &diff_plus_b_reduced); - - diff - } - - pub fn mul_nonnative( - &mut self, - a: &NonNativeTarget, - b: &NonNativeTarget, - ) -> NonNativeTarget { - let prod = self.add_virtual_nonnative_target::(); - let modulus = self.constant_biguint(&FF::order()); - let overflow = self.add_virtual_biguint_target( - a.value.num_limbs() + b.value.num_limbs() - modulus.num_limbs(), - ); - - self.add_simple_generator(NonNativeMultiplicationGenerator:: { - a: a.clone(), - b: b.clone(), - prod: prod.clone(), - overflow: overflow.clone(), - _phantom: PhantomData, - }); - - self.range_check_u32(prod.value.limbs.clone()); - self.range_check_u32(overflow.limbs.clone()); - - let prod_expected = self.mul_biguint(&a.value, &b.value); - - let mod_times_overflow = self.mul_biguint(&modulus, &overflow); - let prod_actual = self.add_biguint(&prod.value, &mod_times_overflow); - self.connect_biguint(&prod_expected, &prod_actual); - - prod - } - - pub fn mul_many_nonnative( - &mut self, - to_mul: &[NonNativeTarget], - ) -> NonNativeTarget { - if to_mul.len() == 1 { - return to_mul[0].clone(); - } - - let mut accumulator = self.mul_nonnative(&to_mul[0], &to_mul[1]); - for i in 2..to_mul.len() { - accumulator = self.mul_nonnative(&accumulator, &to_mul[i]); - } - accumulator - } - - pub fn neg_nonnative( - &mut self, - x: &NonNativeTarget, - ) -> NonNativeTarget { - let zero_target = self.constant_biguint(&BigUint::zero()); - let zero_ff = self.biguint_to_nonnative(&zero_target); - - self.sub_nonnative(&zero_ff, x) - } - - pub fn inv_nonnative( - &mut self, - x: &NonNativeTarget, - ) -> NonNativeTarget { - let num_limbs = x.value.num_limbs(); - let inv_biguint = self.add_virtual_biguint_target(num_limbs); - let div = self.add_virtual_biguint_target(num_limbs); - - self.add_simple_generator(NonNativeInverseGenerator:: { - x: x.clone(), - inv: inv_biguint.clone(), - div: div.clone(), - _phantom: PhantomData, - }); - - let product = self.mul_biguint(&x.value, &inv_biguint); - - let modulus = self.constant_biguint(&FF::order()); - let mod_times_div = self.mul_biguint(&modulus, &div); - let one = self.constant_biguint(&BigUint::one()); - let expected_product = self.add_biguint(&mod_times_div, &one); - self.connect_biguint(&product, &expected_product); - - NonNativeTarget:: { - value: inv_biguint, - _phantom: PhantomData, - } - } - - /// Returns `x % |FF|` as a `NonNativeTarget`. - fn reduce(&mut self, x: &BigUintTarget) -> NonNativeTarget { - let modulus = FF::order(); - let order_target = self.constant_biguint(&modulus); - let value = self.rem_biguint(x, &order_target); - - NonNativeTarget { - value, - _phantom: PhantomData, - } - } - - pub fn reduce_nonnative(&mut self, x: &NonNativeTarget) -> NonNativeTarget { - let x_biguint = self.nonnative_to_canonical_biguint(x); - self.reduce(&x_biguint) - } - - pub fn bool_to_nonnative(&mut self, b: &BoolTarget) -> NonNativeTarget { - let limbs = vec![U32Target(b.target)]; - let value = BigUintTarget { limbs }; - - NonNativeTarget { - value, - _phantom: PhantomData, - } - } - - // Split a nonnative field element to bits. - pub fn split_nonnative_to_bits( - &mut self, - x: &NonNativeTarget, - ) -> Vec { - let num_limbs = x.value.num_limbs(); - let mut result = Vec::with_capacity(num_limbs * 32); - - for i in 0..num_limbs { - let limb = x.value.get_limb(i); - let bit_targets = self.split_le_base::<2>(limb.0, 32); - let mut bits: Vec<_> = bit_targets - .iter() - .map(|&t| BoolTarget::new_unsafe(t)) - .collect(); - - result.append(&mut bits); - } - - result - } - - pub fn nonnative_conditional_neg( - &mut self, - x: &NonNativeTarget, - b: BoolTarget, - ) -> NonNativeTarget { - let not_b = self.not(b); - let neg = self.neg_nonnative(x); - let x_if_true = self.mul_nonnative_by_bool(&neg, b); - let x_if_false = self.mul_nonnative_by_bool(x, not_b); - - self.add_nonnative(&x_if_true, &x_if_false) - } -} - -#[derive(Debug)] -struct NonNativeAdditionGenerator, const D: usize, FF: PrimeField> { - a: NonNativeTarget, - b: NonNativeTarget, - sum: NonNativeTarget, - overflow: BoolTarget, - _phantom: PhantomData, -} - -impl, const D: usize, FF: PrimeField> SimpleGenerator - for NonNativeAdditionGenerator -{ - fn dependencies(&self) -> Vec { - self.a - .value - .limbs - .iter() - .cloned() - .chain(self.b.value.limbs.clone()) - .map(|l| l.0) - .collect() - } - - fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let a = witness.get_nonnative_target(self.a.clone()); - let b = witness.get_nonnative_target(self.b.clone()); - let a_biguint = a.to_canonical_biguint(); - let b_biguint = b.to_canonical_biguint(); - let sum_biguint = a_biguint + b_biguint; - let modulus = FF::order(); - let (overflow, sum_reduced) = if sum_biguint > modulus { - (true, sum_biguint - modulus) - } else { - (false, sum_biguint) - }; - - out_buffer.set_biguint_target(self.sum.value.clone(), sum_reduced); - out_buffer.set_bool_target(self.overflow, overflow); - } -} - -#[derive(Debug)] -struct NonNativeMultipleAddsGenerator, const D: usize, FF: PrimeField> -{ - summands: Vec>, - sum: NonNativeTarget, - overflow: U32Target, - _phantom: PhantomData, -} - -impl, const D: usize, FF: PrimeField> SimpleGenerator - for NonNativeMultipleAddsGenerator -{ - fn dependencies(&self) -> Vec { - self.summands - .iter() - .flat_map(|summand| summand.value.limbs.iter().map(|limb| limb.0)) - .collect() - } - - fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let summands: Vec<_> = self - .summands - .iter() - .map(|summand| witness.get_nonnative_target(summand.clone())) - .collect(); - let summand_biguints: Vec<_> = summands - .iter() - .map(|summand| summand.to_canonical_biguint()) - .collect(); - - let sum_biguint = summand_biguints - .iter() - .fold(BigUint::zero(), |a, b| a + b.clone()); - - let modulus = FF::order(); - let (overflow_biguint, sum_reduced) = sum_biguint.div_rem(&modulus); - let overflow = overflow_biguint.to_u64_digits()[0] as u32; - - out_buffer.set_biguint_target(self.sum.value.clone(), sum_reduced); - out_buffer.set_u32_target(self.overflow, overflow); - } -} - -#[derive(Debug)] -struct NonNativeSubtractionGenerator, const D: usize, FF: Field> { - a: NonNativeTarget, - b: NonNativeTarget, - diff: NonNativeTarget, - overflow: BoolTarget, - _phantom: PhantomData, -} - -impl, const D: usize, FF: PrimeField> SimpleGenerator - for NonNativeSubtractionGenerator -{ - fn dependencies(&self) -> Vec { - self.a - .value - .limbs - .iter() - .cloned() - .chain(self.b.value.limbs.clone()) - .map(|l| l.0) - .collect() - } - - fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let a = witness.get_nonnative_target(self.a.clone()); - let b = witness.get_nonnative_target(self.b.clone()); - let a_biguint = a.to_canonical_biguint(); - let b_biguint = b.to_canonical_biguint(); - - let modulus = FF::order(); - let (diff_biguint, overflow) = if a_biguint >= b_biguint { - (a_biguint - b_biguint, false) - } else { - (modulus + a_biguint - b_biguint, true) - }; - - out_buffer.set_biguint_target(self.diff.value.clone(), diff_biguint); - out_buffer.set_bool_target(self.overflow, overflow); - } -} - -#[derive(Debug)] -struct NonNativeMultiplicationGenerator, const D: usize, FF: Field> { - a: NonNativeTarget, - b: NonNativeTarget, - prod: NonNativeTarget, - overflow: BigUintTarget, - _phantom: PhantomData, -} - -impl, const D: usize, FF: PrimeField> SimpleGenerator - for NonNativeMultiplicationGenerator -{ - fn dependencies(&self) -> Vec { - self.a - .value - .limbs - .iter() - .cloned() - .chain(self.b.value.limbs.clone()) - .map(|l| l.0) - .collect() - } - - fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let a = witness.get_nonnative_target(self.a.clone()); - let b = witness.get_nonnative_target(self.b.clone()); - let a_biguint = a.to_canonical_biguint(); - let b_biguint = b.to_canonical_biguint(); - - let prod_biguint = a_biguint * b_biguint; - - let modulus = FF::order(); - let (overflow_biguint, prod_reduced) = prod_biguint.div_rem(&modulus); - - out_buffer.set_biguint_target(self.prod.value.clone(), prod_reduced); - out_buffer.set_biguint_target(self.overflow.clone(), overflow_biguint); - } -} - -#[derive(Debug)] -struct NonNativeInverseGenerator, const D: usize, FF: PrimeField> { - x: NonNativeTarget, - inv: BigUintTarget, - div: BigUintTarget, - _phantom: PhantomData, -} - -impl, const D: usize, FF: PrimeField> SimpleGenerator - for NonNativeInverseGenerator -{ - fn dependencies(&self) -> Vec { - self.x.value.limbs.iter().map(|&l| l.0).collect() - } - - fn run_once(&self, witness: &PartitionWitness, out_buffer: &mut GeneratedValues) { - let x = witness.get_nonnative_target(self.x.clone()); - let inv = x.inverse(); - - let x_biguint = x.to_canonical_biguint(); - let inv_biguint = inv.to_canonical_biguint(); - let prod = x_biguint * &inv_biguint; - let modulus = FF::order(); - let (div, _rem) = prod.div_rem(&modulus); - - out_buffer.set_biguint_target(self.div.clone(), div); - out_buffer.set_biguint_target(self.inv.clone(), inv_biguint); - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use plonky2_field::field_types::{Field, PrimeField}; - use plonky2_field::secp256k1_base::Secp256K1Base; - - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - #[test] - fn test_nonnative_add() -> Result<()> { - type FF = Secp256K1Base; - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let x_ff = FF::rand(); - let y_ff = FF::rand(); - let sum_ff = x_ff + y_ff; - - let config = CircuitConfig::standard_ecc_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.constant_nonnative(x_ff); - let y = builder.constant_nonnative(y_ff); - let sum = builder.add_nonnative(&x, &y); - - let sum_expected = builder.constant_nonnative(sum_ff); - builder.connect_nonnative(&sum, &sum_expected); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_nonnative_many_adds() -> Result<()> { - type FF = Secp256K1Base; - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let a_ff = FF::rand(); - let b_ff = FF::rand(); - let c_ff = FF::rand(); - let d_ff = FF::rand(); - let e_ff = FF::rand(); - let f_ff = FF::rand(); - let g_ff = FF::rand(); - let h_ff = FF::rand(); - let sum_ff = a_ff + b_ff + c_ff + d_ff + e_ff + f_ff + g_ff + h_ff; - - let config = CircuitConfig::standard_ecc_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let a = builder.constant_nonnative(a_ff); - let b = builder.constant_nonnative(b_ff); - let c = builder.constant_nonnative(c_ff); - let d = builder.constant_nonnative(d_ff); - let e = builder.constant_nonnative(e_ff); - let f = builder.constant_nonnative(f_ff); - let g = builder.constant_nonnative(g_ff); - let h = builder.constant_nonnative(h_ff); - let all = [a, b, c, d, e, f, g, h]; - let sum = builder.add_many_nonnative(&all); - - let sum_expected = builder.constant_nonnative(sum_ff); - builder.connect_nonnative(&sum, &sum_expected); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_nonnative_sub() -> Result<()> { - type FF = Secp256K1Base; - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let x_ff = FF::rand(); - let mut y_ff = FF::rand(); - while y_ff.to_canonical_biguint() > x_ff.to_canonical_biguint() { - y_ff = FF::rand(); - } - let diff_ff = x_ff - y_ff; - - let config = CircuitConfig::standard_ecc_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.constant_nonnative(x_ff); - let y = builder.constant_nonnative(y_ff); - let diff = builder.sub_nonnative(&x, &y); - - let diff_expected = builder.constant_nonnative(diff_ff); - builder.connect_nonnative(&diff, &diff_expected); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_nonnative_mul() -> Result<()> { - type FF = Secp256K1Base; - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let x_ff = FF::rand(); - let y_ff = FF::rand(); - let product_ff = x_ff * y_ff; - - let config = CircuitConfig::standard_ecc_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.constant_nonnative(x_ff); - let y = builder.constant_nonnative(y_ff); - let product = builder.mul_nonnative(&x, &y); - - let product_expected = builder.constant_nonnative(product_ff); - builder.connect_nonnative(&product, &product_expected); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_nonnative_neg() -> Result<()> { - type FF = Secp256K1Base; - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let x_ff = FF::rand(); - let neg_x_ff = -x_ff; - - let config = CircuitConfig::standard_ecc_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.constant_nonnative(x_ff); - let neg_x = builder.neg_nonnative(&x); - - let neg_x_expected = builder.constant_nonnative(neg_x_ff); - builder.connect_nonnative(&neg_x, &neg_x_expected); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } - - #[test] - fn test_nonnative_inv() -> Result<()> { - type FF = Secp256K1Base; - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - let x_ff = FF::rand(); - let inv_x_ff = x_ff.inverse(); - - let config = CircuitConfig::standard_ecc_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = builder.constant_nonnative(x_ff); - let inv_x = builder.inv_nonnative(&x); - - let inv_x_expected = builder.constant_nonnative(inv_x_ff); - builder.connect_nonnative(&inv_x, &inv_x_expected); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } -} diff --git a/plonky2/src/gadgets/split_nonnative.rs b/plonky2/src/gadgets/split_nonnative.rs deleted file mode 100644 index 18fc0264..00000000 --- a/plonky2/src/gadgets/split_nonnative.rs +++ /dev/null @@ -1,109 +0,0 @@ -use std::marker::PhantomData; - -use itertools::Itertools; -use plonky2_field::extension_field::Extendable; -use plonky2_field::field_types::Field; - -use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; -use crate::gadgets::nonnative::NonNativeTarget; -use crate::hash::hash_types::RichField; -use crate::iop::target::Target; -use crate::plonk::circuit_builder::CircuitBuilder; - -impl, const D: usize> CircuitBuilder { - pub fn split_u32_to_4_bit_limbs(&mut self, val: U32Target) -> Vec { - let two_bit_limbs = self.split_le_base::<4>(val.0, 16); - let four = self.constant(F::from_canonical_usize(4)); - let combined_limbs = two_bit_limbs - .iter() - .tuples() - .map(|(&a, &b)| self.mul_add(b, four, a)) - .collect(); - - combined_limbs - } - - pub fn split_nonnative_to_4_bit_limbs( - &mut self, - val: &NonNativeTarget, - ) -> Vec { - val.value - .limbs - .iter() - .flat_map(|&l| self.split_u32_to_4_bit_limbs(l)) - .collect() - } - - pub fn split_nonnative_to_2_bit_limbs( - &mut self, - val: &NonNativeTarget, - ) -> Vec { - val.value - .limbs - .iter() - .flat_map(|&l| self.split_le_base::<4>(l.0, 16)) - .collect() - } - - // Note: assumes its inputs are 4-bit limbs, and does not range-check. - pub fn recombine_nonnative_4_bit_limbs( - &mut self, - limbs: Vec, - ) -> NonNativeTarget { - let base = self.constant_u32(1 << 4); - let u32_limbs = limbs - .chunks(8) - .map(|chunk| { - let mut combined_chunk = self.zero_u32(); - for i in (0..8).rev() { - let (low, _high) = self.mul_add_u32(combined_chunk, base, U32Target(chunk[i])); - combined_chunk = low; - } - combined_chunk - }) - .collect(); - - NonNativeTarget { - value: BigUintTarget { limbs: u32_limbs }, - _phantom: PhantomData, - } - } -} - -#[cfg(test)] -mod tests { - use anyhow::Result; - use plonky2_field::field_types::Field; - use plonky2_field::secp256k1_scalar::Secp256K1Scalar; - - use crate::gadgets::nonnative::NonNativeTarget; - use crate::iop::witness::PartialWitness; - use crate::plonk::circuit_builder::CircuitBuilder; - use crate::plonk::circuit_data::CircuitConfig; - use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig}; - use crate::plonk::verifier::verify; - - #[test] - fn test_split_nonnative() -> Result<()> { - type FF = Secp256K1Scalar; - const D: usize = 2; - type C = PoseidonGoldilocksConfig; - type F = >::F; - - let config = CircuitConfig::standard_ecc_config(); - let pw = PartialWitness::new(); - let mut builder = CircuitBuilder::::new(config); - - let x = FF::rand(); - let x_target = builder.constant_nonnative(x); - let split = builder.split_nonnative_to_4_bit_limbs(&x_target); - let combined: NonNativeTarget = - builder.recombine_nonnative_4_bit_limbs(split); - builder.connect_nonnative(&x_target, &combined); - - let data = builder.build::(); - let proof = data.prove(pw).unwrap(); - verify(proof, &data.verifier_only, &data.common) - } -} diff --git a/plonky2/src/iop/generator.rs b/plonky2/src/iop/generator.rs index 1569e889..f36ba3aa 100644 --- a/plonky2/src/iop/generator.rs +++ b/plonky2/src/iop/generator.rs @@ -1,13 +1,10 @@ use std::fmt::Debug; use std::marker::PhantomData; -use num::BigUint; use plonky2_field::extension_field::{Extendable, FieldExtension}; -use plonky2_field::field_types::{Field, PrimeField}; +use plonky2_field::field_types::Field; use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; -use crate::gadgets::nonnative::NonNativeTarget; use crate::hash::hash_types::{HashOut, HashOutTarget, RichField}; use crate::iop::ext_target::ExtensionTarget; use crate::iop::target::{BoolTarget, Target}; @@ -169,21 +166,6 @@ impl GeneratedValues { self.set_target(target.0, F::from_canonical_u32(value)) } - pub fn set_biguint_target(&mut self, target: BigUintTarget, value: BigUint) { - let mut limbs = value.to_u32_digits(); - - assert!(target.num_limbs() >= limbs.len()); - - limbs.resize(target.num_limbs(), 0); - for i in 0..target.num_limbs() { - self.set_u32_target(target.get_limb(i), limbs[i]); - } - } - - pub fn set_nonnative_target(&mut self, target: NonNativeTarget, value: FF) { - self.set_biguint_target(target.value, value.to_canonical_biguint()) - } - pub fn set_hash_target(&mut self, ht: HashOutTarget, value: HashOut) { ht.elements .iter() diff --git a/plonky2/src/iop/witness.rs b/plonky2/src/iop/witness.rs index a013f811..4a565d02 100644 --- a/plonky2/src/iop/witness.rs +++ b/plonky2/src/iop/witness.rs @@ -1,16 +1,12 @@ use std::collections::HashMap; -use std::iter::repeat; use itertools::Itertools; -use num::{BigUint, FromPrimitive, Zero}; use plonky2_field::extension_field::{Extendable, FieldExtension}; -use plonky2_field::field_types::{Field, PrimeField}; +use plonky2_field::field_types::Field; use crate::fri::structure::{FriOpenings, FriOpeningsTarget}; use crate::fri::witness_util::set_fri_proof_target; use crate::gadgets::arithmetic_u32::U32Target; -use crate::gadgets::biguint::BigUintTarget; -use crate::gadgets::nonnative::NonNativeTarget; use crate::hash::hash_types::HashOutTarget; use crate::hash::hash_types::RichField; use crate::hash::hash_types::{HashOut, MerkleCapTarget}; @@ -64,30 +60,6 @@ pub trait Witness { panic!("not a bool") } - fn get_biguint_target(&self, target: BigUintTarget) -> BigUint - where - F: PrimeField, - { - let mut result = BigUint::zero(); - - let limb_base = BigUint::from_u64(1 << 32u64).unwrap(); - for i in (0..target.num_limbs()).rev() { - let limb = target.get_limb(i); - result *= &limb_base; - result += self.get_target(limb.0).to_canonical_biguint(); - } - - result - } - - fn get_nonnative_target(&self, target: NonNativeTarget) -> FF - where - F: PrimeField, - { - let val = self.get_biguint_target(target.value); - FF::from_biguint(val) - } - fn get_hash_target(&self, ht: HashOutTarget) -> HashOut { HashOut { elements: self.get_targets(&ht.elements).try_into().unwrap(), @@ -160,16 +132,6 @@ pub trait Witness { self.set_target(target.0, F::from_canonical_u32(value)) } - fn set_biguint_target(&mut self, target: &BigUintTarget, value: &BigUint) { - for (<, l) in target - .limbs - .iter() - .zip(value.to_u32_digits().into_iter().chain(repeat(0))) - { - self.set_u32_target(lt, l); - } - } - /// Set the targets in a `ProofWithPublicInputsTarget` to their corresponding values in a /// `ProofWithPublicInputs`. fn set_proof_with_pis_target, const D: usize>( diff --git a/plonky2/src/lib.rs b/plonky2/src/lib.rs index e5e77bb9..1502cea9 100644 --- a/plonky2/src/lib.rs +++ b/plonky2/src/lib.rs @@ -12,7 +12,6 @@ pub use plonky2_field as field; -pub mod curve; pub mod fri; pub mod gadgets; pub mod gates;