new curve_mul

This commit is contained in:
Nicholas Ward 2021-11-18 15:48:28 -08:00
parent 284f9a412c
commit 2ec3ea8634
2 changed files with 75 additions and 12 deletions

View File

@ -201,18 +201,18 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let two = self.constant_nonnative(C::ScalarField::TWO);
let num_bits = C::ScalarField::BITS;
let bits = self.split_nonnative_to_bits(&n);
let bits_as_base: Vec<NonNativeTarget<C::BaseField>> =
bits.iter().map(|b| self.bool_to_nonnative(b)).collect();
// Result starts at p, 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(p, &result);
let mut two_i_times_p = self.add_virtual_affine_point_target();
self.connect_affine_point(p, &two_i_times_p);
let mut cur_n = self.add_virtual_nonnative_target::<C::ScalarField>();
for _i in 0..num_bits {
let (bit_scalar, new_n) = self.div_rem_nonnative(&cur_n, &two);
let bit_biguint = self.nonnative_to_biguint(&bit_scalar);
let bit = self.biguint_to_nonnative::<C::BaseField>(&bit_biguint);
let not_bit = self.sub_nonnative(&one, &bit);
for bit in bits_as_base.iter() {
let not_bit = self.sub_nonnative(&one, bit);
let result_plus_2_i_p = self.curve_add(&result, &two_i_times_p);
@ -221,9 +221,9 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let result_plus_2_i_p_x = result_plus_2_i_p.x;
let result_plus_2_i_p_y = result_plus_2_i_p.y;
let new_x_if_bit = self.mul_nonnative(&bit, &result_plus_2_i_p_x);
let new_x_if_bit = self.mul_nonnative(bit, &result_plus_2_i_p_x);
let new_x_if_not_bit = self.mul_nonnative(&not_bit, &result_x);
let new_y_if_bit = self.mul_nonnative(&bit, &result_plus_2_i_p_y);
let new_y_if_bit = self.mul_nonnative(bit, &result_plus_2_i_p_y);
let new_y_if_not_bit = self.mul_nonnative(&not_bit, &result_y);
let new_x = self.add_nonnative(&new_x_if_bit, &new_x_if_not_bit);
@ -232,7 +232,6 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
result = AffinePointTarget { x: new_x, y: new_y };
two_i_times_p = self.curve_double(&two_i_times_p);
cur_n = new_n;
}
// Subtract off result's intial value of p.
@ -244,15 +243,16 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
}
mod tests {
use std::ops::Neg;
use std::ops::{Mul, Neg};
use anyhow::Result;
use crate::curve::curve_types::{AffinePoint, Curve};
use crate::curve::curve_types::{AffinePoint, Curve, CurveScalar};
use crate::curve::secp256k1::Secp256K1;
use crate::field::field_types::Field;
use crate::field::goldilocks_field::GoldilocksField;
use crate::field::secp256k1_base::Secp256K1Base;
use crate::field::secp256k1_scalar::Secp256K1Scalar;
use crate::iop::witness::PartialWitness;
use crate::plonk::circuit_builder::CircuitBuilder;
use crate::plonk::circuit_data::CircuitConfig;
@ -372,4 +372,34 @@ mod tests {
verify(proof, &data.verifier_only, &data.common)
}
#[test]
fn test_curve_mul() -> Result<()> {
type F = GoldilocksField;
const D: usize = 4;
let config = CircuitConfig::standard_recursion_config();
let pw = PartialWitness::new();
let mut builder = CircuitBuilder::<F, D>::new(config);
let g = Secp256K1::GENERATOR_AFFINE;
let five = Secp256K1Scalar::from_canonical_usize(5);
let five_scalar = CurveScalar::<Secp256K1>(five);
let five_g = (five_scalar * g.to_projective()).to_affine();
let five_g_expected = builder.constant_affine_point(five_g);
builder.curve_assert_valid(&five_g_expected);
let g_target = builder.constant_affine_point(g);
let five_target = builder.constant_nonnative(five);
let five_g_actual = builder.curve_scalar_mul(&g_target, &five_target);
builder.curve_assert_valid(&five_g_actual);
builder.connect_affine_point(&five_g_expected, &five_g_actual);
let data = builder.build();
let proof = data.prove(pw).unwrap();
verify(proof, &data.verifier_only, &data.common)
}
}

View File

@ -4,9 +4,10 @@ use num::{BigUint, One, Zero};
use crate::field::field_types::RichField;
use crate::field::{extension_field::Extendable, field_types::Field};
use crate::gadgets::arithmetic_u32::U32Target;
use crate::gadgets::biguint::BigUintTarget;
use crate::iop::generator::{GeneratedValues, SimpleGenerator};
use crate::iop::target::Target;
use crate::iop::target::{BoolTarget, Target};
use crate::iop::witness::{PartitionWitness, Witness};
use crate::plonk::circuit_builder::CircuitBuilder;
@ -158,6 +159,38 @@ impl<F: RichField + Extendable<D>, const D: usize> CircuitBuilder<F, D> {
let x_biguint = self.nonnative_to_biguint(x);
self.reduce(&x_biguint)
}
pub fn bool_to_nonnative<FF: Field>(&mut self, b: &BoolTarget) -> NonNativeTarget<FF> {
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<FF: Field>(
&mut self,
x: &NonNativeTarget<FF>,
) -> Vec<BoolTarget> {
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
}
}
#[derive(Debug)]