Skip to content

Commit

Permalink
Small Gadgets refactor (#353)
Browse files Browse the repository at this point in the history
* refactor: restrict visibility of nonnative

* refactor: restrict visibility of ECC

* refactor: restrict visibility of gadgets::r1cs

* refactor: restrict visibility of gadgets::utils

* refactor: simple cleanup

* test: check field representations in used libraries

* chore: minor cleanups

* refactor: simplify AllocatedPoint::default

* refactor: simplify AllocatedPointNonInfinity::to_allocated_point
  • Loading branch information
huitseeker authored Feb 29, 2024
1 parent ba34148 commit bb2b233
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 57 deletions.
9 changes: 3 additions & 6 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,8 @@
use crate::{
constants::{NIO_NOVA_FOLD, NUM_FE_WITHOUT_IO_FOR_CRHF, NUM_HASH_BITS},
gadgets::{
ecc::AllocatedPoint,
r1cs::{AllocatedR1CSInstance, AllocatedRelaxedR1CSInstance},
utils::{
alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select_vec, le_bits_to_num,
},
alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select_vec, le_bits_to_num,
AllocatedPoint, AllocatedR1CSInstance, AllocatedRelaxedR1CSInstance,
},
r1cs::{R1CSInstance, RelaxedR1CSInstance},
traits::{
Expand Down Expand Up @@ -370,7 +367,7 @@ mod tests {
test_shape_cs::TestShapeCS,
},
constants::{BN_LIMB_WIDTH, BN_N_LIMBS},
gadgets::utils::scalar_as_base,
gadgets::scalar_as_base,
provider::{
poseidon::PoseidonConstantsCircuit, Bn256EngineKZG, GrumpkinEngine, PallasEngine,
Secp256k1Engine, Secq256k1Engine, VestaEngine,
Expand Down
25 changes: 13 additions & 12 deletions src/gadgets/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,18 +101,19 @@ impl<G: Group> AllocatedPoint<G> {
}

/// Allocates a default point on the curve, set to the identity point.
pub fn default<CS: ConstraintSystem<G::Base>>(mut cs: CS) -> Result<Self, SynthesisError> {
pub fn default<CS: ConstraintSystem<G::Base>>(mut cs: CS) -> Self {
let zero = alloc_zero(cs.namespace(|| "zero"));
let one = alloc_one(cs.namespace(|| "one"));

Ok(Self {
Self {
x: zero.clone(),
y: zero,
is_infinity: one,
})
}
}

/// Returns coordinates associated with the point.
#[allow(unused)]
pub const fn get_coordinates(
&self,
) -> (
Expand Down Expand Up @@ -490,7 +491,7 @@ impl<G: Group> AllocatedPoint<G> {
// convert back to AllocatedPoint
let res = {
// we set acc.is_infinity = self.is_infinity
let acc = acc.to_allocated_point(&self.is_infinity)?;
let acc = acc.to_allocated_point(&self.is_infinity);

// we remove the initial slack if bits[0] is as not as assumed (i.e., it is not 1)
let acc_minus_initial = {
Expand All @@ -508,7 +509,7 @@ impl<G: Group> AllocatedPoint<G> {

// when self.is_infinity = 1, return the default point, else return res
// we already set res.is_infinity to be self.is_infinity, so we do not need to set it here
let default = Self::default(cs.namespace(|| "default"))?;
let default = Self::default(cs.namespace(|| "default"));
let x = conditionally_select2(
cs.namespace(|| "check if self.is_infinity is zero (x)"),
&default.x,
Expand All @@ -529,7 +530,7 @@ impl<G: Group> AllocatedPoint<G> {
y,
is_infinity: res.is_infinity,
};
let mut p_complete = p.to_allocated_point(&self.is_infinity)?;
let mut p_complete = p.to_allocated_point(&self.is_infinity);

for (i, bit) in complete_bits.iter().enumerate() {
let temp = acc.add(cs.namespace(|| format!("add_complete {i}")), &p_complete)?;
Expand Down Expand Up @@ -596,11 +597,13 @@ pub struct AllocatedPointNonInfinity<G: Group> {

impl<G: Group> AllocatedPointNonInfinity<G> {
/// Creates a new `AllocatedPointNonInfinity` from the specified coordinates
#[allow(unused)]
pub const fn new(x: AllocatedNum<G::Base>, y: AllocatedNum<G::Base>) -> Self {
Self { x, y }
}

/// Allocates a new point on the curve using coordinates provided by `coords`.
#[allow(unused)]
pub fn alloc<CS: ConstraintSystem<G::Base>>(
mut cs: CS,
coords: Option<(G::Base, G::Base)>,
Expand All @@ -624,18 +627,16 @@ impl<G: Group> AllocatedPointNonInfinity<G> {
}

/// Returns an `AllocatedPoint` from an `AllocatedPointNonInfinity`
pub fn to_allocated_point(
&self,
is_infinity: &AllocatedNum<G::Base>,
) -> Result<AllocatedPoint<G>, SynthesisError> {
Ok(AllocatedPoint {
pub fn to_allocated_point(&self, is_infinity: &AllocatedNum<G::Base>) -> AllocatedPoint<G> {
AllocatedPoint {
x: self.x.clone(),
y: self.y.clone(),
is_infinity: is_infinity.clone(),
})
}
}

/// Returns coordinates associated with the point.
#[allow(unused)]
pub const fn get_coordinates(&self) -> (&AllocatedNum<G::Base>, &AllocatedNum<G::Base>) {
(&self.x, &self.y)
}
Expand Down
23 changes: 19 additions & 4 deletions src/gadgets/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
//! This module implements various gadgets necessary for Nova and applications built with Nova.
pub mod ecc;
pub(crate) mod nonnative;
pub(crate) mod r1cs;
pub(crate) mod utils;
mod ecc;
pub(crate) use ecc::AllocatedPoint;

mod nonnative;
pub(crate) use nonnative::{bignat::nat_to_limbs, util::f_to_nat};

mod r1cs;
pub(crate) use r1cs::{
conditionally_select_alloc_relaxed_r1cs, conditionally_select_vec_allocated_relaxed_r1cs_instance,
};
pub(crate) use r1cs::{AllocatedR1CSInstance, AllocatedRelaxedR1CSInstance};

mod utils;
#[cfg(test)]
pub(crate) use utils::alloc_one;
pub(crate) use utils::{
alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select_vec, le_bits_to_num,
scalar_as_base,
};
47 changes: 42 additions & 5 deletions src/gadgets/nonnative/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ impl<Scalar: PrimeField> Num<Scalar> {
/// Computes the natural number represented by an array of bits.
/// Checks if the natural number equals `self`
pub fn is_equal<CS: ConstraintSystem<Scalar>>(&self, mut cs: CS, other: &Bitvector<Scalar>) {
let allocations = other.allocations.clone();
let mut f = Scalar::ONE;
let sum = allocations
let sum = other
.allocations
.iter()
.fold(LinearCombination::zero(), |lc, bit| {
let l = lc + (f, &bit.bit);
Expand Down Expand Up @@ -202,8 +202,7 @@ impl<Scalar: PrimeField> Num<Scalar> {
let sum_lc = LinearCombination::zero() + &self.num - &sum;
cs.enforce(|| "sum", |lc| lc + &sum_lc, |lc| lc + CS::one(), |lc| lc);
let bits: Vec<LinearCombination<Scalar>> = allocations
.clone()
.into_iter()
.iter()
.map(|a| LinearCombination::zero() + &a.bit)
.collect();
Ok(Bitvector {
Expand Down Expand Up @@ -245,7 +244,7 @@ fn write_be<F: PrimeField, W: Write>(f: &F, mut writer: W) -> io::Result<()> {
/// Convert a field element to a natural number
pub fn f_to_nat<Scalar: PrimeField>(f: &Scalar) -> BigInt {
let mut s = Vec::new();
write_be(f, &mut s).unwrap(); // f.to_repr().write_be(&mut s).unwrap();
write_be(f, &mut s).unwrap();
BigInt::from_bytes_le(Sign::Plus, f.to_repr().as_ref())
}

Expand All @@ -254,3 +253,41 @@ pub fn f_to_nat<Scalar: PrimeField>(f: &Scalar) -> BigInt {
pub fn nat_to_f<Scalar: PrimeField>(n: &BigInt) -> Option<Scalar> {
Scalar::from_str_vartime(&format!("{n}"))
}

#[cfg(test)]
mod tests {
use bitvec::field::BitField as _;
use ff::PrimeFieldBits;
use rand::SeedableRng;
use rand_chacha::ChaCha20Rng;

// the write_be function above assumes Field::to_repr() outputs a representation that's an instance
// of `AsRef<[u8]>` in lower endian. We test that here, as this is not what the I2OSP standard recommends
// and may change in some implementations.
fn test_repr_is_le_with<F: PrimeFieldBits>() {
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
for _i in 0..50 {
let f = F::random(&mut rng);
// This is guaranteed to be in LE
let le_bits = f.to_le_bits();
let leftmost_u64 = le_bits[..64].load_le::<u64>();

// This is not
let f_repr = f.to_repr();
let bytes: [u8; 8] = f_repr.as_ref()[..8].try_into().unwrap();
let u64_from_repr = u64::from_le_bytes(bytes);

assert_eq!(leftmost_u64, u64_from_repr);
}
}

#[test]
fn test_repr_is_le() {
test_repr_is_le_with::<pasta_curves::pallas::Scalar>();
test_repr_is_le_with::<pasta_curves::pallas::Base>();
test_repr_is_le_with::<crate::provider::bn256_grumpkin::bn256::Scalar>();
test_repr_is_le_with::<crate::provider::bn256_grumpkin::bn256::Base>();
test_repr_is_le_with::<crate::provider::secp_secq::secp256k1::Scalar>();
test_repr_is_le_with::<crate::provider::secp_secq::secp256k1::Base>();
}
}
4 changes: 2 additions & 2 deletions src/gadgets/r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ impl<E: Engine, const N: usize> AllocatedRelaxedR1CSInstance<E, N> {
limb_width: usize,
n_limbs: usize,
) -> Result<Self, SynthesisError> {
let W = AllocatedPoint::default(cs.namespace(|| "allocate W"))?;
let W = AllocatedPoint::default(cs.namespace(|| "allocate W"));
let E = W.clone();

let u = W.x.clone(); // In the default case, W.x = u = 0
Expand Down Expand Up @@ -159,7 +159,7 @@ impl<E: Engine, const N: usize> AllocatedRelaxedR1CSInstance<E, N> {
limb_width: usize,
n_limbs: usize,
) -> Result<Self, SynthesisError> {
let E = AllocatedPoint::default(cs.namespace(|| "allocate default E"))?;
let E = AllocatedPoint::default(cs.namespace(|| "allocate default E"));

let u = alloc_one(cs.namespace(|| "one"));

Expand Down
10 changes: 1 addition & 9 deletions src/gadgets/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,15 +80,7 @@ where
CS: ConstraintSystem<<E as Engine>::Base>,
{
AllocatedNum::alloc(cs.namespace(|| "allocate scalar as base"), || {
let input_bits = input.unwrap_or(E::Scalar::ZERO).clone().to_le_bits();
let mut mult = E::Base::ONE;
let mut val = E::Base::ZERO;
for bit in input_bits {
if bit {
val += mult;
}
mult = mult + mult;
}
let val = scalar_as_base::<E>(input.unwrap_or(E::Scalar::ZERO));
Ok(val)
})
}
Expand Down
2 changes: 1 addition & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use circuit::{NovaAugmentedCircuit, NovaAugmentedCircuitInputs, NovaAugmentedCir
use constants::{BN_LIMB_WIDTH, BN_N_LIMBS, NUM_FE_WITHOUT_IO_FOR_CRHF, NUM_HASH_BITS};
use errors::NovaError;
use ff::{Field, PrimeField};
use gadgets::utils::scalar_as_base;
use gadgets::scalar_as_base;
use nifs::NIFS;
use r1cs::{
CommitmentKeyHint, R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness,
Expand Down
2 changes: 1 addition & 1 deletion src/provider/poseidon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ mod tests {
};
use crate::{
bellpepper::solver::SatisfyingAssignment, constants::NUM_CHALLENGE_BITS,
gadgets::utils::le_bits_to_num, traits::Engine,
gadgets::le_bits_to_num, traits::Engine,
};
use ff::Field;
use rand::rngs::OsRng;
Expand Down
5 changes: 1 addition & 4 deletions src/r1cs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,7 @@ use crate::{
constants::{BN_LIMB_WIDTH, BN_N_LIMBS},
digest::{DigestComputer, SimpleDigestible},
errors::NovaError,
gadgets::{
nonnative::{bignat::nat_to_limbs, util::f_to_nat},
utils::scalar_as_base,
},
gadgets::{f_to_nat, nat_to_limbs, scalar_as_base},
traits::{
commitment::CommitmentEngineTrait, AbsorbInROTrait, Engine, ROTrait, TranscriptReprTrait,
},
Expand Down
14 changes: 4 additions & 10 deletions src/supernova/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,9 @@
use crate::{
constants::{NIO_NOVA_FOLD, NUM_HASH_BITS},
gadgets::{
ecc::AllocatedPoint,
r1cs::{
conditionally_select_alloc_relaxed_r1cs,
conditionally_select_vec_allocated_relaxed_r1cs_instance, AllocatedR1CSInstance,
AllocatedRelaxedR1CSInstance,
},
utils::{
alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select_vec, le_bits_to_num,
},
alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select_alloc_relaxed_r1cs,
conditionally_select_vec, conditionally_select_vec_allocated_relaxed_r1cs_instance,
le_bits_to_num, AllocatedPoint, AllocatedR1CSInstance, AllocatedRelaxedR1CSInstance,
},
r1cs::{R1CSInstance, RelaxedR1CSInstance},
traits::{commitment::CommitmentTrait, Engine, ROCircuitTrait, ROConstantsCircuit},
Expand Down Expand Up @@ -711,7 +705,7 @@ mod tests {
test_shape_cs::TestShapeCS,
},
constants::{BN_LIMB_WIDTH, BN_N_LIMBS},
gadgets::utils::scalar_as_base,
gadgets::scalar_as_base,
provider::{
poseidon::PoseidonConstantsCircuit, Bn256EngineIPA, GrumpkinEngine, PallasEngine,
Secp256k1Engine, Secq256k1Engine, VestaEngine,
Expand Down
4 changes: 2 additions & 2 deletions src/supernova/test.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::gadgets::utils::alloc_zero;
use crate::gadgets::alloc_zero;
use crate::provider::poseidon::PoseidonConstantsCircuit;
use crate::provider::Bn256EngineIPA;
use crate::provider::PallasEngine;
use crate::provider::Secp256k1Engine;
use crate::provider::VestaEngine;
use crate::supernova::circuit::{StepCircuit, TrivialSecondaryCircuit, TrivialTestCircuit};
use crate::traits::snark::default_ck_hint;
use crate::{bellpepper::test_shape_cs::TestShapeCS, gadgets::utils::alloc_one};
use crate::{bellpepper::test_shape_cs::TestShapeCS, gadgets::alloc_one};
use abomonation::Abomonation;
use bellpepper_core::num::AllocatedNum;
use bellpepper_core::{ConstraintSystem, SynthesisError};
Expand Down
2 changes: 1 addition & 1 deletion src/supernova/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use itertools::Itertools as _;

use crate::{
constants::NIO_NOVA_FOLD,
gadgets::r1cs::{conditionally_select_alloc_relaxed_r1cs, AllocatedRelaxedR1CSInstance},
gadgets::{conditionally_select_alloc_relaxed_r1cs, AllocatedRelaxedR1CSInstance},
traits::Engine,
};

Expand Down

1 comment on commit bb2b233

@github-actions
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Benchmarks

Table of Contents

Overview

This benchmark report shows the Arecibo GPU benchmarks.
NVIDIA L4
Intel(R) Xeon(R) CPU @ 2.20GHz
32 vCPUs
125 GB RAM
Workflow run: https://github.com/lurk-lab/arecibo/actions/runs/8102493867

Benchmark Results

RecursiveSNARK-NIVC-2

ref=ba34148 ref=bb2b233
Prove-NumCons-6540 44.55 ms (✅ 1.00x) 44.33 ms (✅ 1.00x faster)
Verify-NumCons-6540 34.13 ms (✅ 1.00x) 34.03 ms (✅ 1.00x faster)
Prove-NumCons-1028888 327.18 ms (✅ 1.00x) 317.28 ms (✅ 1.03x faster)
Verify-NumCons-1028888 248.14 ms (✅ 1.00x) 249.44 ms (✅ 1.01x slower)

CompressedSNARK-NIVC-Commitments-2

ref=ba34148 ref=bb2b233
Prove-NumCons-6540 10.57 s (✅ 1.00x) 10.50 s (✅ 1.01x faster)
Verify-NumCons-6540 50.70 ms (✅ 1.00x) 50.29 ms (✅ 1.01x faster)
Prove-NumCons-1028888 53.69 s (✅ 1.00x) 53.64 s (✅ 1.00x faster)
Verify-NumCons-1028888 50.72 ms (✅ 1.00x) 51.07 ms (✅ 1.01x slower)

Made with criterion-table

Please sign in to comment.