moved to new file, and curve random access test

This commit is contained in:
Nicholas Ward 2022-02-11 09:01:02 -08:00
parent 5603816f3b
commit 294a738dc9
3 changed files with 177 additions and 119 deletions

View File

@ -1,18 +1,11 @@
use std::marker::PhantomData;
use plonky2_field::extension_field::Extendable;
use plonky2_field::field_types::Field;
use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar};
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;
const WINDOW_SIZE: usize = 4;
/// 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)]
@ -164,85 +157,6 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
result
}
// TODO: fix if p is the generator
pub fn precompute_window<C: Curve>(
&mut self,
p: &AffinePointTarget<C>,
) -> Vec<AffinePointTarget<C>> {
let mut multiples = Vec::new();
multiples.push(self.constant_affine_point(C::GENERATOR_AFFINE));
let mut cur = p.clone();
for _pow in 0..WINDOW_SIZE {
for existing in multiples.clone() {
multiples.push(self.curve_add(&cur, &existing));
}
cur = self.curve_double(&cur);
}
println!("SIZE OF WINDOW: {}", multiples.len());
multiples
}
pub fn random_access_curve_points<C: Curve>(
&mut self,
access_index: Target,
v: Vec<AffinePointTarget<C>>,
) -> AffinePointTarget<C> {
let num_limbs = v[0].x.value.num_limbs();
let x_limbs: Vec<Vec<_>> = (0..num_limbs)
.map(|i| v.iter().map(|p| p.x.value.limbs[i].0).collect())
.collect();
let y_limbs: Vec<Vec<_>> = (0..num_limbs)
.map(|i| v.iter().map(|p| p.y.value.limbs[i].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 curve_scalar_mul_windowed<C: Curve>(
&mut self,
p: &AffinePointTarget<C>,
n: &NonNativeTarget<C::ScalarField>,
) -> AffinePointTarget<C> {
let mut result = self.constant_affine_point(C::GENERATOR_AFFINE);
let precomputation = self.precompute_window(p);
let windows = self.split_nonnative_to_4_bit_limbs(n);
let m = C::ScalarField::BITS / WINDOW_SIZE;
for i in (0..m).rev() {
result = self.curve_double(&result);
let window = windows[i];
let to_add = self.random_access_curve_points(window, precomputation.clone());
result = self.curve_add(&result, &to_add);
}
result
}
}
#[cfg(test)]
@ -393,7 +307,7 @@ mod tests {
let pw = PartialWitness::new();
let mut builder = CircuitBuilder::<F, D>::new(config);
let g = Secp256K1::GENERATOR_AFFINE;
let g = Secp256K1::GENERATOR_PROJECTIVE.to_affine();
let five = Secp256K1Scalar::from_canonical_usize(5);
let neg_five = five.neg();
let neg_five_scalar = CurveScalar::<Secp256K1>(neg_five);
@ -414,38 +328,6 @@ mod tests {
verify(proof, &data.verifier_only, &data.common)
}
#[test]
fn test_curve_mul_windowed() -> Result<()> {
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
type F = <C as GenericConfig<D>>::F;
let config = CircuitConfig::standard_ecc_config();
let pw = PartialWitness::new();
let mut builder = CircuitBuilder::<F, D>::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::<Secp256K1>(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::<C>();
let proof = data.prove(pw).unwrap();
verify(proof, &data.verifier_only, &data.common)
}
#[test]
#[ignore]
fn test_curve_random() -> Result<()> {

View File

@ -0,0 +1,175 @@
use std::marker::PhantomData;
use plonky2_field::extension_field::Extendable;
use plonky2_field::field_types::Field;
use crate::curve::curve_types::Curve;
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::iop::target::Target;
use crate::plonk::circuit_builder::CircuitBuilder;
const WINDOW_SIZE: usize = 4;
impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
// TODO: fix if p is the generator
pub fn precompute_window<C: Curve>(
&mut self,
p: &AffinePointTarget<C>,
) -> Vec<AffinePointTarget<C>> {
let mut multiples = Vec::new();
multiples.push(self.constant_affine_point(C::GENERATOR_AFFINE));
let mut cur = p.clone();
for _pow in 0..WINDOW_SIZE {
for existing in multiples.clone() {
multiples.push(self.curve_add(&cur, &existing));
}
cur = self.curve_double(&cur);
}
multiples
}
pub fn random_access_curve_points<C: Curve>(
&mut self,
access_index: Target,
v: Vec<AffinePointTarget<C>>,
) -> AffinePointTarget<C> {
let num_limbs = v[0].x.value.num_limbs();
let x_limbs: Vec<Vec<_>> = (0..num_limbs)
.map(|i| v.iter().map(|p| p.x.value.limbs[i].0).collect())
.collect();
let y_limbs: Vec<Vec<_>> = (0..num_limbs)
.map(|i| v.iter().map(|p| p.y.value.limbs[i].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 curve_scalar_mul_windowed<C: Curve>(
&mut self,
p: &AffinePointTarget<C>,
n: &NonNativeTarget<C::ScalarField>,
) -> AffinePointTarget<C> {
let mut result = self.constant_affine_point(C::GENERATOR_AFFINE);
let precomputation = self.precompute_window(p);
let windows = self.split_nonnative_to_4_bit_limbs(n);
let m = C::ScalarField::BITS / WINDOW_SIZE;
for i in (0..m).rev() {
result = self.curve_double(&result);
let window = windows[i];
let to_add = self.random_access_curve_points(window, precomputation.clone());
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 = <C as GenericConfig<D>>::F;
let config = CircuitConfig::standard_ecc_config();
let pw = PartialWitness::new();
let mut builder = CircuitBuilder::<F, D>::new(config);
let num_points = 8;
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 mut access_index = rng.gen::<usize>() % 8;
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::<C>();
let proof = data.prove(pw).unwrap();
verify(proof, &data.verifier_only, &data.common)
}
#[test]
fn test_curve_mul_windowed() -> Result<()> {
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
type F = <C as GenericConfig<D>>::F;
let config = CircuitConfig::standard_ecc_config();
let pw = PartialWitness::new();
let mut builder = CircuitBuilder::<F, D>::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::<Secp256K1>(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::<C>();
let proof = data.prove(pw).unwrap();
verify(proof, &data.verifier_only, &data.common)
}
}

View File

@ -3,6 +3,7 @@ pub mod arithmetic_extension;
pub mod arithmetic_u32;
pub mod biguint;
pub mod curve;
pub mod curve_windowed_mul;
// pub mod curve_msm;
pub mod ecdsa;
pub mod glv;