Add fixed base file

This commit is contained in:
wborgeaud 2022-03-02 11:16:32 +01:00
parent 6f3ca6a0bc
commit 850df4dfb1
3 changed files with 108 additions and 148 deletions

View File

@ -0,0 +1,103 @@
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<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
pub fn fixed_base_curve_mul<C: Curve>(
&mut self,
base: &AffinePoint<C>,
scalar: &NonNativeTarget<C::ScalarField>,
) -> AffinePointTarget<C> {
let doubled_base = (0..scalar.value.limbs.len() * 8).scan(base.clone(), |acc, _| {
let tmp = acc.clone();
for _ in 0..4 {
*acc = acc.double();
}
Some(tmp)
});
let bits = 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::<F>::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.clone());
for (limb, point) in bits.into_iter().zip(doubled_base) {
let mul_point = (0..16)
.scan(AffinePoint::ZERO, |acc, _| {
let tmp = acc.clone();
*acc = (point + *acc).to_affine();
Some(tmp)
})
.map(|p| self.constant_affine_point(p))
.collect::<Vec<_>>();
let is_zero = self.is_equal(limb, zero);
let should_add = self.not(is_zero);
let r = self.random_access_curve_points(limb, mul_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]
fn test_fixed_base() -> Result<()> {
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
type F = <C as GenericConfig<D>>::F;
let config = CircuitConfig::standard_ecc_config();
let mut pw = PartialWitness::new();
let mut builder = CircuitBuilder::<F, D>::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::<Secp256K1Scalar>();
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::<C>();
let proof = data.prove(pw).unwrap();
verify(proof, &data.verifier_only, &data.common)
}
}

View File

@ -1,8 +1,7 @@
use itertools::Itertools;
use num::BigUint;
use plonky2_field::extension_field::Extendable;
use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar};
use crate::curve::curve_types::{Curve, CurveScalar};
use crate::field::field_types::Field;
use crate::gadgets::curve::AffinePointTarget;
use crate::gadgets::nonnative::NonNativeTarget;
@ -71,126 +70,18 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
result
}
// pub fn quad_curve_msm<C: Curve>(
// &mut self,
// points: [AffinePointTarget<C>; 4],
// scalars: [NonNativeTarget<C::ScalarField>; 4],
// ) -> AffinePointTarget<C> {
// let limbs = scalars
// .iter()
// .map(|s| self.split_nonnative_to_bits(n))
// .collect_vec();
//
// let hash_0 = KeccakHash::<32>::hash_no_pad(&[F::ZERO]);
// let hash_0_scalar = C::ScalarField::from_biguint(BigUint::from_bytes_le(
// &GenericHashOut::<F>::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);
//
// let mut precomputation = vec![points[0].clone(); 16];
// for i in 0..4 {
// precomputation[1 << i] = points[i].clone();
// for j in 1..1 << (i - 1) {}
// }
// 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..C::ScalarField::BITS).fold(rando, |acc, _| acc.double());
// let to_add = self.constant_affine_point(-starting_point_multiplied);
// result = self.curve_add(&result, &to_add);
//
// result
// }
pub fn fixed_base_curve_mul<C: Curve>(
&mut self,
base: &AffinePoint<C>,
scalar: &NonNativeTarget<C::ScalarField>,
) -> AffinePointTarget<C> {
let doubled_base = (0..scalar.value.limbs.len() * 8).scan(base.clone(), |acc, _| {
let tmp = acc.clone();
for _ in 0..4 {
*acc = acc.double();
}
Some(tmp)
});
let bits = self.split_nonnative_to_4_bit_limbs(scalar);
// let rando = (CurveScalar(C::ScalarField::rand()) * C::GENERATOR_PROJECTIVE).to_affine();
let hash_0 = KeccakHash::<32>::hash_no_pad(&[F::ZERO]);
let hash_0_scalar = C::ScalarField::from_biguint(BigUint::from_bytes_le(
&GenericHashOut::<F>::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.clone());
for (limb, point) in bits.into_iter().zip(doubled_base) {
let mul_point = (0..16)
.scan(AffinePoint::ZERO, |acc, _| {
let tmp = acc.clone();
*acc = (point + *acc).to_affine();
Some(tmp)
})
.map(|p| self.constant_affine_point(p))
.collect::<Vec<_>>();
let is_zero = self.is_equal(limb, zero);
let should_add = self.not(is_zero);
let r = self.random_access_curve_points(limb, mul_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 std::str::FromStr;
use anyhow::Result;
use num::BigUint;
use plonky2_field::field_types::PrimeField;
use plonky2_field::secp256k1_base::Secp256K1Base;
use plonky2_field::secp256k1_scalar::Secp256K1Scalar;
use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar};
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::iop::witness::PartialWitness;
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::circuit_data::CircuitConfig;
use crate::plonk::config::{GenericConfig, PoseidonGoldilocksConfig};
@ -277,38 +168,4 @@ mod tests {
verify(proof, &data.verifier_only, &data.common)
}
#[test]
fn test_fixed_base() -> Result<()> {
const D: usize = 2;
type C = PoseidonGoldilocksConfig;
type F = <C as GenericConfig<D>>::F;
let config = CircuitConfig::standard_ecc_config();
let mut pw = PartialWitness::new();
let mut builder = CircuitBuilder::<F, D>::new(config);
let g = Secp256K1::GENERATOR_AFFINE;
let n = Secp256K1Scalar::from_canonical_usize(10);
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::<Secp256K1Scalar>();
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::<C>();
let proof = data.prove(pw).unwrap();
verify(proof, &data.verifier_only, &data.common)
}
}

View File

@ -3,9 +3,9 @@ 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 curve_fixed_base;
pub mod curve_msm;
pub mod curve_windowed_mul;
pub mod ecdsa;
pub mod glv;
pub mod hash;