diff --git a/src/gadgets/biguint.rs b/src/gadgets/biguint.rs index 1ccf9c3a..2c34d044 100644 --- a/src/gadgets/biguint.rs +++ b/src/gadgets/biguint.rs @@ -52,7 +52,7 @@ impl, const D: usize> CircuitBuilder { } } - pub fn pad_biguints<'a>( + pub fn pad_biguints( &mut self, a: BigUintTarget, b: BigUintTarget, @@ -141,12 +141,11 @@ impl, const D: usize> CircuitBuilder { } pub fn mul_biguint(&mut self, a: &BigUintTarget, b: &BigUintTarget) -> BigUintTarget { - let num_limbs = a.limbs.len(); - debug_assert!(b.limbs.len() == num_limbs); + let total_limbs = a.limbs.len() + b.limbs.len(); - let mut to_add = vec![vec![]; 2 * num_limbs]; - for i in 0..num_limbs { - for j in 0..num_limbs { + 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); @@ -155,7 +154,7 @@ impl, const D: usize> CircuitBuilder { let mut combined_limbs = vec![]; let mut carry = self.zero_u32(); - for i in 0..2 * num_limbs { + for i in 0..total_limbs { to_add[i].push(carry); let (new_result, new_carry) = self.add_many_u32(to_add[i].clone()); combined_limbs.push(new_result); @@ -243,7 +242,7 @@ mod tests { use num::{BigUint, FromPrimitive, Integer}; use crate::{ - field::{crandall_field::CrandallField, field_types::PrimeField}, + field::crandall_field::CrandallField, iop::witness::PartialWitness, plonk::{circuit_builder::CircuitBuilder, circuit_data::CircuitConfig, verifier::verify}, }; diff --git a/src/gadgets/nonnative.rs b/src/gadgets/nonnative.rs index 16a62776..c8539629 100644 --- a/src/gadgets/nonnative.rs +++ b/src/gadgets/nonnative.rs @@ -21,12 +21,44 @@ impl, const D: usize> CircuitBuilder { .collect() } + pub fn biguint_to_ff(&mut self, x: &BigUintTarget) -> ForeignFieldTarget { + ForeignFieldTarget { + limbs: x.limbs.clone(), + _phantom: PhantomData, + } + } + pub fn ff_to_biguint(&mut self, x: &ForeignFieldTarget) -> BigUintTarget { BigUintTarget { limbs: x.limbs.clone(), } } + pub fn constant_ff(&mut self, x: FF) -> ForeignFieldTarget { + let x_biguint = self.constant_biguint(&x.to_biguint()); + self.biguint_to_ff(&x_biguint) + } + + // Assert that two ForeignFieldTarget's, both assumed to be in reduced form, are equal. + pub fn connect_ff_reduced( + &mut self, + lhs: &ForeignFieldTarget, + rhs: &ForeignFieldTarget, + ) { + let min_limbs = lhs.limbs.len().min(rhs.limbs.len()); + + for i in 0..min_limbs { + self.connect_u32(lhs.limbs[i], rhs.limbs[i]); + } + + for i in min_limbs..lhs.limbs.len() { + self.assert_zero_u32(lhs.limbs[i]); + } + for i in min_limbs..rhs.limbs.len() { + self.assert_zero_u32(rhs.limbs[i]); + } + } + // Add two `ForeignFieldTarget`s. pub fn add_nonnative( &mut self, @@ -82,3 +114,40 @@ impl, const D: usize> CircuitBuilder { self.reduce(&x_biguint) } } + +#[cfg(test)] +mod tests { + use anyhow::Result; + + use crate::field::crandall_field::CrandallField; + use crate::field::field_types::Field; + use crate::field::secp256k1::Secp256K1Base; + use crate::iop::witness::PartialWitness; + use crate::plonk::circuit_builder::CircuitBuilder; + use crate::plonk::circuit_data::CircuitConfig; + use crate::plonk::verifier::verify; + + #[test] + fn test_nonnative_add() -> Result<()> { + type FF = Secp256K1Base; + let x_ff = FF::rand(); + let y_ff = FF::rand(); + let sum_ff = x_ff + y_ff; + + type F = CrandallField; + let config = CircuitConfig::large_config(); + let pw = PartialWitness::new(); + let mut builder = CircuitBuilder::::new(config); + + let x = builder.constant_ff(x_ff); + let y = builder.constant_ff(y_ff); + let sum = builder.add_nonnative(&x, &y); + + let sum_expected = builder.constant_ff(sum_ff); + builder.connect_ff_reduced(&sum, &sum_expected); + + let data = builder.build(); + let proof = data.prove(pw).unwrap(); + verify(proof, &data.verifier_only, &data.common) + } +}