Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "nova-snark"
version = "0.73.0"
version = "0.74.0"
authors = ["Srinath Setty <srinath@microsoft.com>"]
edition = "2021"
description = "High-speed recursive arguments from folding schemes"
Expand Down
6 changes: 4 additions & 2 deletions src/frontend/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ mod tests {
r1cs::R1CSShape,
traits::{snark::default_ck_hint, Engine},
};
use ff::PrimeField;
use ff::{Field, PrimeField};

fn synthesize_alloc_bit<Fr: PrimeField, CS: ConstraintSystem<Fr>>(cs: &mut CS) {
// get two bits as input and check that they are indeed bits
Expand Down Expand Up @@ -71,7 +71,9 @@ mod tests {
// Now get the assignment
let mut cs = SatisfyingAssignment::<E>::new();
synthesize_alloc_bit(&mut cs);
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let (inst, witness) = cs
.r1cs_instance_and_witness(&shape, &ck, E::Scalar::ZERO)
Comment thread
sai-deng marked this conversation as resolved.
Outdated
.unwrap();

// Make sure that this is satisfiable
assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
Expand Down
13 changes: 8 additions & 5 deletions src/frontend/r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,16 @@ use ff::PrimeField;

/// `NovaWitness` provide a method for acquiring an `R1CSInstance` and `R1CSWitness` from implementers.
pub trait NovaWitness<E: Engine> {
/// Return an instance and witness, given a shape and ck.
/// Return an instance and witness, given a shape, commitment key, and blind.
///
/// Hiding commitments require a uniformly random, secret, single-use blind.
/// Protocols that explicitly derandomize a commitment may instead reveal
Comment thread
sai-deng marked this conversation as resolved.
Outdated
/// the blind as part of the proof.
fn r1cs_instance_and_witness(
&self,
shape: &R1CSShape<E>,
ck: &CommitmentKey<E>,
r_W: E::Scalar,
) -> Result<(R1CSInstance<E>, R1CSWitness<E>), NovaError>;
}

Expand All @@ -30,14 +35,12 @@ impl<E: Engine> NovaWitness<E> for SatisfyingAssignment<E> {
&self,
shape: &R1CSShape<E>,
ck: &CommitmentKey<E>,
r_W: E::Scalar,
) -> Result<(R1CSInstance<E>, R1CSWitness<E>), NovaError> {
let W = R1CSWitness::<E>::new(shape, self.aux_assignment())?;
let W = R1CSWitness::<E>::new(shape, self.aux_assignment(), r_W)?;
let X = &self.input_assignment()[1..];

let comm_W = W.commit(ck);

let instance = R1CSInstance::<E>::new(shape, &comm_W, X)?;

Ok((instance, W))
}
}
Expand Down
16 changes: 12 additions & 4 deletions src/gadgets/ecc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1287,7 +1287,9 @@ mod tests {
// Then the satisfying assignment
let mut cs = SatisfyingAssignment::<E2>::new();
let (a, e, s) = synthesize_smul::<E1, _>(cs.namespace(|| "synthesize"));
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let (inst, witness) = cs
.r1cs_instance_and_witness(&shape, &ck, E2::Scalar::ZERO)
Comment thread
sai-deng marked this conversation as resolved.
Outdated
.unwrap();

let a_p: Point<E1> = Point::new(
a.x.get_value().unwrap(),
Expand Down Expand Up @@ -1344,7 +1346,9 @@ mod tests {
// Then the satisfying assignment
let mut cs = SatisfyingAssignment::<E2>::new();
let (a, e) = synthesize_add_equal::<E1, _>(cs.namespace(|| "synthesize add equal"));
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let (inst, witness) = cs
.r1cs_instance_and_witness(&shape, &ck, E2::Scalar::ZERO)
Comment thread
sai-deng marked this conversation as resolved.
Outdated
.unwrap();
let a_p: Point<E1> = Point::new(
a.x.get_value().unwrap(),
a.y.get_value().unwrap(),
Expand Down Expand Up @@ -1405,7 +1409,9 @@ mod tests {
// Then the satisfying assignment
let mut cs = SatisfyingAssignment::<E2>::new();
let e = synthesize_add_negation::<E1, _>(cs.namespace(|| "synthesize add negation"));
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let (inst, witness) = cs
.r1cs_instance_and_witness(&shape, &ck, E2::Scalar::ZERO)
Comment thread
sai-deng marked this conversation as resolved.
Outdated
.unwrap();
let e_p: Point<E1> = Point::new(
e.x.get_value().unwrap(),
e.y.get_value().unwrap(),
Expand Down Expand Up @@ -1457,7 +1463,9 @@ mod tests {
// Build the satisfying assignment.
let mut cs = SatisfyingAssignment::<E2>::new();
let (sum, p) = synthesize_add_identity_matching_x::<E1, _>(cs.namespace(|| "assignment"));
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let (inst, witness) = cs
.r1cs_instance_and_witness(&shape, &ck, E2::Scalar::ZERO)
.unwrap();

// O + P must equal P (and must NOT be the point at infinity).
assert!(
Expand Down
4 changes: 3 additions & 1 deletion src/neutron/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,9 @@ mod tests {
let circuit: NeutronAugmentedCircuit<'_, E1, TrivialCircuit<E1::Scalar>> =
NeutronAugmentedCircuit::new(Some(inputs), &tc, ro_consts);
let _ = circuit.synthesize(&mut cs);
let (inst, witness) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let (inst, witness) = cs
.r1cs_instance_and_witness(&shape, &ck, E1::Scalar::ZERO)
.unwrap();
// Make sure that this is satisfiable
assert!(shape.is_sat(&ck, &inst, &witness).is_ok());
}
Expand Down
6 changes: 4 additions & 2 deletions src/neutron/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,8 @@ where
let circuit: NeutronAugmentedCircuit<'_, E1, C> =
NeutronAugmentedCircuit::new(Some(inputs), c, pp.ro_consts_circuit.clone());
let zi = circuit.synthesize(&mut cs)?;
let (l_u, l_w) = cs.r1cs_instance_and_witness(&pp.structure.S, &pp.ck)?;
let (l_u, l_w) =
cs.r1cs_instance_and_witness(&pp.structure.S, &pp.ck, E1::Scalar::random(&mut OsRng))?;

assert!((zi.len() == pp.F_arity), "Invalid step length");

Expand Down Expand Up @@ -345,7 +346,8 @@ where
NeutronAugmentedCircuit::new(Some(inputs), c, pp.ro_consts_circuit.clone());
let zi = circuit.synthesize(&mut cs)?;

let (l_u, l_w) = cs.r1cs_instance_and_witness(&pp.structure.S, &pp.ck)?;
let (l_u, l_w) =
cs.r1cs_instance_and_witness(&pp.structure.S, &pp.ck, E1::Scalar::random(&mut OsRng))?;

// update the running instances and witnesses
self.zi = zi
Expand Down
10 changes: 6 additions & 4 deletions src/neutron/nifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ mod tests {
let mut cs = SatisfyingAssignment::<E>::new();
let _ = circuit.synthesize(&mut cs);
let (U1, W1) = cs
.r1cs_instance_and_witness(&shape, &ck)
.r1cs_instance_and_witness(&shape, &ck, E::Scalar::ZERO)
.map_err(|_e| NovaError::UnSat {
reason: "Unable to generate a satisfying witness".to_string(),
})
Expand All @@ -471,7 +471,7 @@ mod tests {
let mut cs = SatisfyingAssignment::<E>::new();
let _ = circuit.synthesize(&mut cs);
let (U2, W2) = cs
.r1cs_instance_and_witness(&shape, &ck)
.r1cs_instance_and_witness(&shape, &ck, E::Scalar::ZERO)
.map_err(|_e| NovaError::UnSat {
reason: "Unable to generate a satisfying witness".to_string(),
})
Expand Down Expand Up @@ -577,7 +577,7 @@ mod benchmarks {
.into_par_iter()
.map(|i| <E as Engine>::Scalar::from(w[i] as u64))
.collect::<Vec<_>>();
R1CSWitness::new(&S, &W).unwrap()
R1CSWitness::new(&S, &W, E::Scalar::ZERO).unwrap()
};

let x = vec![E::Scalar::from(0)];
Expand Down Expand Up @@ -641,7 +641,9 @@ mod benchmarks {

let mut cs = SatisfyingAssignment::<E>::new();
let _ = circuit.synthesize(&mut cs);
let (U, W) = cs.r1cs_instance_and_witness(&S, &ck).unwrap();
let (U, W) = cs
.r1cs_instance_and_witness(&S, &ck, E::Scalar::ZERO)
.unwrap();

let S = S.pad();
let W = W.pad(&S);
Expand Down
2 changes: 1 addition & 1 deletion src/neutron/relation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ mod tests {
let mut cs = SatisfyingAssignment::<E>::new();
let _ = circuit.synthesize(&mut cs);
let (u, w) = cs
.r1cs_instance_and_witness(&shape, &ck)
.r1cs_instance_and_witness(&shape, &ck, E::Scalar::random(&mut OsRng))
.map_err(|_e| NovaError::UnSat {
reason: "Unable to generate a satisfying witness".to_string(),
})?;
Expand Down
8 changes: 6 additions & 2 deletions src/nova/circuit/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -422,7 +422,9 @@ mod tests {
let circuit1: NovaAugmentedCircuit<'_, E2, TrivialCircuit<<E2 as Engine>::Base>> =
NovaAugmentedCircuit::new(true, Some(inputs1), &tc1, ro_consts1);
let _ = circuit1.synthesize(&mut cs1);
let (inst1, witness1) = cs1.r1cs_instance_and_witness(&shape1, &ck1).unwrap();
let (inst1, witness1) = cs1
.r1cs_instance_and_witness(&shape1, &ck1, E1::Scalar::ZERO)
.unwrap();
// Make sure that this is satisfiable
assert!(shape1.is_sat(&ck1, &inst1, &witness1).is_ok());

Expand All @@ -444,7 +446,9 @@ mod tests {
let circuit2: NovaAugmentedCircuit<'_, E1, TrivialCircuit<<E1 as Engine>::Base>> =
NovaAugmentedCircuit::new(false, Some(inputs2), &tc2, ro_consts2);
let _ = circuit2.synthesize(&mut cs2);
let (inst2, witness2) = cs2.r1cs_instance_and_witness(&shape2, &ck2).unwrap();
let (inst2, witness2) = cs2
.r1cs_instance_and_witness(&shape2, &ck2, E2::Scalar::ZERO)
.unwrap();
// Make sure that it is satisfiable
assert!(shape2.is_sat(&ck2, &inst2, &witness2).is_ok());
}
Expand Down
27 changes: 20 additions & 7 deletions src/nova/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,8 +380,11 @@ where
pp.ro_consts_circuit_primary.clone(),
);
let zi_primary = circuit_primary.synthesize(&mut cs_primary)?;
let (u_primary, w_primary) =
cs_primary.r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.ck_primary)?;
let (u_primary, w_primary) = cs_primary.r1cs_instance_and_witness(
&pp.r1cs_shape_primary,
&pp.ck_primary,
E1::Scalar::random(&mut OsRng),
)?;

// base case for the secondary
let mut cs_secondary = SatisfyingAssignment::<E2>::new();
Expand All @@ -404,8 +407,11 @@ where
pp.ro_consts_circuit_secondary.clone(),
);
let _ = circuit_secondary.synthesize(&mut cs_secondary)?;
let (u_secondary, w_secondary) =
cs_secondary.r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.ck_secondary)?;
let (u_secondary, w_secondary) = cs_secondary.r1cs_instance_and_witness(
&pp.r1cs_shape_secondary,
&pp.ck_secondary,
E2::Scalar::random(&mut OsRng),
)?;

// IVC proof for the primary circuit
let l_w_primary = w_primary;
Expand Down Expand Up @@ -495,8 +501,11 @@ where
);
let zi_primary = circuit_primary.synthesize(&mut cs_primary)?;

let (l_u_primary, l_w_primary) =
cs_primary.r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.ck_primary)?;
let (l_u_primary, l_w_primary) = cs_primary.r1cs_instance_and_witness(
&pp.r1cs_shape_primary,
&pp.ck_primary,
E1::Scalar::random(&mut OsRng),
)?;

// fold the primary circuit's instance
let (nifs_primary, (r_U_primary, r_W_primary)) = NIFS::prove(
Expand Down Expand Up @@ -535,7 +544,11 @@ where
let _ = circuit_secondary.synthesize(&mut cs_secondary)?;

let (l_u_secondary, l_w_secondary) = cs_secondary
.r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.ck_secondary)
.r1cs_instance_and_witness(
&pp.r1cs_shape_secondary,
&pp.ck_secondary,
E2::Scalar::random(&mut OsRng),
)
.map_err(|_e| NovaError::UnSat {
reason: "Unable to generate a satisfying witness on the secondary curve".to_string(),
})?;
Expand Down
12 changes: 8 additions & 4 deletions src/nova/nifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,15 +263,19 @@ mod tests {
// Now get the instance and assignment for one instance
let mut cs = SatisfyingAssignment::<E>::new();
let _ = synthesize_tiny_r1cs_bellpepper(&mut cs, Some(E::Scalar::from(5)));
let (U1, W1) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let (U1, W1) = cs
.r1cs_instance_and_witness(&shape, &ck, E::Scalar::ZERO)
.unwrap();

// Make sure that the first instance is satisfiable
assert!(shape.is_sat(&ck, &U1, &W1).is_ok());

// Now get the instance and assignment for second instance
let mut cs = SatisfyingAssignment::<E>::new();
let _ = synthesize_tiny_r1cs_bellpepper(&mut cs, Some(E::Scalar::from(135)));
let (U2, W2) = cs.r1cs_instance_and_witness(&shape, &ck).unwrap();
let (U2, W2) = cs
.r1cs_instance_and_witness(&shape, &ck, E::Scalar::ZERO)
.unwrap();

// Make sure that the second instance is satisfiable
assert!(shape.is_sat(&ck, &U2, &W2).is_ok());
Expand Down Expand Up @@ -521,7 +525,7 @@ mod tests {
};

let W = {
let res = R1CSWitness::new(&S, &vars);
let res = R1CSWitness::new(&S, &vars, E::Scalar::ZERO);
assert!(res.is_ok());
res.unwrap()
};
Expand Down Expand Up @@ -657,7 +661,7 @@ mod tests {
};

let W = {
let res = R1CSWitness::new(&S, &vars);
let res = R1CSWitness::new(&S, &vars, E::Scalar::ZERO);
assert!(res.is_ok());
res.unwrap()
};
Expand Down
38 changes: 32 additions & 6 deletions src/r1cs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -805,15 +805,20 @@ impl<E: Engine> R1CSShape<E> {
}

impl<E: Engine> R1CSWitness<E> {
/// A method to create a witness object using a vector of scalars
pub fn new(S: &R1CSShape<E>, W: &[E::Scalar]) -> Result<R1CSWitness<E>, NovaError> {
/// Creates a witness using a caller-supplied commitment blinding factor.
///
/// Hiding commitments require a uniformly random, secret, single-use blind.
/// Protocols that explicitly derandomize a commitment may instead reveal
Comment thread
sai-deng marked this conversation as resolved.
Outdated
/// the blind as part of the proof.
pub fn new(
S: &R1CSShape<E>,
W: &[E::Scalar],
r_W: E::Scalar,
) -> Result<R1CSWitness<E>, NovaError> {
let mut W = W.to_vec();
W.resize(S.num_vars, E::Scalar::ZERO);

Ok(R1CSWitness {
W,
r_W: E::Scalar::random(&mut OsRng),
})
Ok(R1CSWitness { W, r_W })
}

/// Returns a reference to the witness vector W.
Expand Down Expand Up @@ -1436,6 +1441,27 @@ mod tests {
test_random_sample_with::<Secp256k1Engine>();
}

#[test]
fn test_witness_with_blind_is_deterministic() {
let shape = tiny_r1cs::<Bn256EngineKZG>(4);
let ck = R1CSShape::commitment_key(&[&shape], &[&*default_ck_hint()]).unwrap();
let values = vec![<Bn256EngineKZG as Engine>::Scalar::ONE; 3];
let blind = <Bn256EngineKZG as Engine>::Scalar::from(42_u64);

let witness_1 = R1CSWitness::new(&shape, &values, blind).unwrap();
let witness_2 = R1CSWitness::new(&shape, &values, blind).unwrap();
let witness_3 = R1CSWitness::new(
&shape,
&values,
<Bn256EngineKZG as Engine>::Scalar::from(43_u64),
)
.unwrap();

assert_eq!(witness_1, witness_2);
assert_eq!(witness_1.commit(&ck), witness_2.commit(&ck));
assert_ne!(witness_1.commit(&ck), witness_3.commit(&ck));
}

fn test_multiply_vec_pair_with<E: Engine>() {
// tiny_r1cs(4) has num_cons=4, num_vars=4, num_io=2
// z has length num_vars + 1 + num_io = 7
Expand Down
3 changes: 2 additions & 1 deletion src/spartan/direct.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use crate::{
};
use core::marker::PhantomData;
use ff::Field;
use rand_core::OsRng;
use serde::{Deserialize, Serialize};
use serde_with::serde_as;

Expand Down Expand Up @@ -150,7 +151,7 @@ impl<E: Engine, S: RelaxedR1CSSNARKTrait<E>, C: StepCircuit<E::Scalar>> DirectSN

let _ = circuit.synthesize(&mut cs);
let (u, w) = cs
.r1cs_instance_and_witness(&pk.S, &pk.ck)
.r1cs_instance_and_witness(&pk.S, &pk.ck, E::Scalar::random(&mut OsRng))
.map_err(|_e| NovaError::UnSat {
reason: "Unable to generate a satisfying witness".to_string(),
})?;
Expand Down
Loading