mirror of
https://github.com/arnaucube/Nova.git
synced 2026-01-10 16:11:29 +01:00
hash of public parameters in the transcript (#168)
This commit is contained in:
@@ -378,6 +378,7 @@ mod tests {
|
||||
use crate::constants::{BN_LIMB_WIDTH, BN_N_LIMBS};
|
||||
use crate::{
|
||||
bellperson::r1cs::{NovaShape, NovaWitness},
|
||||
gadgets::utils::scalar_as_base,
|
||||
provider::poseidon::PoseidonConstantsCircuit,
|
||||
traits::{circuit::TrivialTestCircuit, ROConstantsTrait},
|
||||
};
|
||||
@@ -420,7 +421,7 @@ mod tests {
|
||||
let zero1 = <<G2 as Group>::Base as Field>::ZERO;
|
||||
let mut cs1: SatisfyingAssignment<G1> = SatisfyingAssignment::new();
|
||||
let inputs1: NovaAugmentedCircuitInputs<G2> = NovaAugmentedCircuitInputs::new(
|
||||
shape2.get_digest(),
|
||||
scalar_as_base::<G1>(zero1), // pass zero for testing
|
||||
zero1,
|
||||
vec![zero1],
|
||||
None,
|
||||
@@ -444,7 +445,7 @@ mod tests {
|
||||
let zero2 = <<G1 as Group>::Base as Field>::ZERO;
|
||||
let mut cs2: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
|
||||
let inputs2: NovaAugmentedCircuitInputs<G1> = NovaAugmentedCircuitInputs::new(
|
||||
shape1.get_digest(),
|
||||
scalar_as_base::<G2>(zero2), // pass zero for testing
|
||||
zero2,
|
||||
vec![zero2],
|
||||
None,
|
||||
|
||||
73
src/lib.rs
73
src/lib.rs
@@ -36,10 +36,12 @@ use constants::{BN_LIMB_WIDTH, BN_N_LIMBS, NUM_FE_WITHOUT_IO_FOR_CRHF, NUM_HASH_
|
||||
use core::marker::PhantomData;
|
||||
use errors::NovaError;
|
||||
use ff::Field;
|
||||
use flate2::{write::ZlibEncoder, Compression};
|
||||
use gadgets::utils::scalar_as_base;
|
||||
use nifs::NIFS;
|
||||
use r1cs::{R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha3::{Digest, Sha3_256};
|
||||
use traits::{
|
||||
circuit::StepCircuit,
|
||||
commitment::{CommitmentEngineTrait, CommitmentTrait},
|
||||
@@ -69,6 +71,7 @@ where
|
||||
r1cs_shape_secondary: R1CSShape<G2>,
|
||||
augmented_circuit_params_primary: NovaAugmentedCircuitParams,
|
||||
augmented_circuit_params_secondary: NovaAugmentedCircuitParams,
|
||||
digest: G1::Scalar, // digest of everything else with this field set to G1::Scalar::ZERO
|
||||
_p_c1: PhantomData<C1>,
|
||||
_p_c2: PhantomData<C2>,
|
||||
}
|
||||
@@ -119,7 +122,7 @@ where
|
||||
let _ = circuit_secondary.synthesize(&mut cs);
|
||||
let (r1cs_shape_secondary, ck_secondary) = cs.r1cs_shape();
|
||||
|
||||
Self {
|
||||
let mut pp = Self {
|
||||
F_arity_primary,
|
||||
F_arity_secondary,
|
||||
ro_consts_primary,
|
||||
@@ -132,9 +135,15 @@ where
|
||||
r1cs_shape_secondary,
|
||||
augmented_circuit_params_primary,
|
||||
augmented_circuit_params_secondary,
|
||||
digest: G1::Scalar::ZERO,
|
||||
_p_c1: Default::default(),
|
||||
_p_c2: Default::default(),
|
||||
}
|
||||
};
|
||||
|
||||
// set the digest in pp
|
||||
pp.digest = compute_digest::<G1, PublicParams<G1, G2, C1, C2>>(&pp);
|
||||
|
||||
pp
|
||||
}
|
||||
|
||||
/// Returns the number of constraints in the primary and secondary circuits
|
||||
@@ -205,7 +214,7 @@ where
|
||||
// base case for the primary
|
||||
let mut cs_primary: SatisfyingAssignment<G1> = SatisfyingAssignment::new();
|
||||
let inputs_primary: NovaAugmentedCircuitInputs<G2> = NovaAugmentedCircuitInputs::new(
|
||||
pp.r1cs_shape_secondary.get_digest(),
|
||||
scalar_as_base::<G1>(pp.digest),
|
||||
G1::Scalar::ZERO,
|
||||
z0_primary.clone(),
|
||||
None,
|
||||
@@ -228,7 +237,7 @@ where
|
||||
// base case for the secondary
|
||||
let mut cs_secondary: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
|
||||
let inputs_secondary: NovaAugmentedCircuitInputs<G1> = NovaAugmentedCircuitInputs::new(
|
||||
pp.r1cs_shape_primary.get_digest(),
|
||||
pp.digest,
|
||||
G2::Scalar::ZERO,
|
||||
z0_secondary.clone(),
|
||||
None,
|
||||
@@ -294,6 +303,7 @@ where
|
||||
let (nifs_secondary, (r_U_secondary, r_W_secondary)) = NIFS::prove(
|
||||
&pp.ck_secondary,
|
||||
&pp.ro_consts_secondary,
|
||||
&scalar_as_base::<G1>(pp.digest),
|
||||
&pp.r1cs_shape_secondary,
|
||||
&r_snark.r_U_secondary,
|
||||
&r_snark.r_W_secondary,
|
||||
@@ -303,7 +313,7 @@ where
|
||||
|
||||
let mut cs_primary: SatisfyingAssignment<G1> = SatisfyingAssignment::new();
|
||||
let inputs_primary: NovaAugmentedCircuitInputs<G2> = NovaAugmentedCircuitInputs::new(
|
||||
pp.r1cs_shape_secondary.get_digest(),
|
||||
scalar_as_base::<G1>(pp.digest),
|
||||
G1::Scalar::from(r_snark.i as u64),
|
||||
z0_primary,
|
||||
Some(r_snark.zi_primary.clone()),
|
||||
@@ -328,6 +338,7 @@ where
|
||||
let (nifs_primary, (r_U_primary, r_W_primary)) = NIFS::prove(
|
||||
&pp.ck_primary,
|
||||
&pp.ro_consts_primary,
|
||||
&pp.digest,
|
||||
&pp.r1cs_shape_primary,
|
||||
&r_snark.r_U_primary,
|
||||
&r_snark.r_W_primary,
|
||||
@@ -337,7 +348,7 @@ where
|
||||
|
||||
let mut cs_secondary: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
|
||||
let inputs_secondary: NovaAugmentedCircuitInputs<G1> = NovaAugmentedCircuitInputs::new(
|
||||
pp.r1cs_shape_primary.get_digest(),
|
||||
pp.digest,
|
||||
G2::Scalar::from(r_snark.i as u64),
|
||||
z0_secondary,
|
||||
Some(r_snark.zi_secondary.clone()),
|
||||
@@ -414,7 +425,7 @@ where
|
||||
pp.ro_consts_secondary.clone(),
|
||||
NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.F_arity_primary,
|
||||
);
|
||||
hasher.absorb(scalar_as_base::<G2>(pp.r1cs_shape_secondary.get_digest()));
|
||||
hasher.absorb(pp.digest);
|
||||
hasher.absorb(G1::Scalar::from(num_steps as u64));
|
||||
for e in &z0_primary {
|
||||
hasher.absorb(*e);
|
||||
@@ -428,7 +439,7 @@ where
|
||||
pp.ro_consts_primary.clone(),
|
||||
NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * pp.F_arity_secondary,
|
||||
);
|
||||
hasher2.absorb(scalar_as_base::<G1>(pp.r1cs_shape_primary.get_digest()));
|
||||
hasher2.absorb(scalar_as_base::<G1>(pp.digest));
|
||||
hasher2.absorb(G2::Scalar::from(num_steps as u64));
|
||||
for e in &z0_secondary {
|
||||
hasher2.absorb(*e);
|
||||
@@ -531,8 +542,7 @@ where
|
||||
F_arity_secondary: usize,
|
||||
ro_consts_primary: ROConstants<G1>,
|
||||
ro_consts_secondary: ROConstants<G2>,
|
||||
r1cs_shape_primary_digest: G1::Scalar,
|
||||
r1cs_shape_secondary_digest: G2::Scalar,
|
||||
digest: G1::Scalar,
|
||||
vk_primary: S1::VerifierKey,
|
||||
vk_secondary: S2::VerifierKey,
|
||||
_p_c1: PhantomData<C1>,
|
||||
@@ -602,8 +612,7 @@ where
|
||||
F_arity_secondary: pp.F_arity_secondary,
|
||||
ro_consts_primary: pp.ro_consts_primary.clone(),
|
||||
ro_consts_secondary: pp.ro_consts_secondary.clone(),
|
||||
r1cs_shape_primary_digest: pp.r1cs_shape_primary.get_digest(),
|
||||
r1cs_shape_secondary_digest: pp.r1cs_shape_secondary.get_digest(),
|
||||
digest: pp.digest,
|
||||
vk_primary,
|
||||
vk_secondary,
|
||||
_p_c1: Default::default(),
|
||||
@@ -625,6 +634,7 @@ where
|
||||
NIFS::prove(
|
||||
&pp.ck_primary,
|
||||
&pp.ro_consts_primary,
|
||||
&pp.digest,
|
||||
&pp.r1cs_shape_primary,
|
||||
&recursive_snark.r_U_primary,
|
||||
&recursive_snark.r_W_primary,
|
||||
@@ -637,6 +647,7 @@ where
|
||||
NIFS::prove(
|
||||
&pp.ck_secondary,
|
||||
&pp.ro_consts_secondary,
|
||||
&scalar_as_base::<G1>(pp.digest),
|
||||
&pp.r1cs_shape_secondary,
|
||||
&recursive_snark.r_U_secondary,
|
||||
&recursive_snark.r_W_secondary,
|
||||
@@ -709,7 +720,7 @@ where
|
||||
vk.ro_consts_secondary.clone(),
|
||||
NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * vk.F_arity_primary,
|
||||
);
|
||||
hasher.absorb(scalar_as_base::<G2>(vk.r1cs_shape_secondary_digest));
|
||||
hasher.absorb(vk.digest);
|
||||
hasher.absorb(G1::Scalar::from(num_steps as u64));
|
||||
for e in z0_primary {
|
||||
hasher.absorb(e);
|
||||
@@ -723,7 +734,7 @@ where
|
||||
vk.ro_consts_primary.clone(),
|
||||
NUM_FE_WITHOUT_IO_FOR_CRHF + 2 * vk.F_arity_secondary,
|
||||
);
|
||||
hasher2.absorb(scalar_as_base::<G1>(vk.r1cs_shape_primary_digest));
|
||||
hasher2.absorb(scalar_as_base::<G1>(vk.digest));
|
||||
hasher2.absorb(G2::Scalar::from(num_steps as u64));
|
||||
for e in z0_secondary {
|
||||
hasher2.absorb(e);
|
||||
@@ -748,13 +759,13 @@ where
|
||||
// fold the running instance and last instance to get a folded instance
|
||||
let f_U_primary = self.nifs_primary.verify(
|
||||
&vk.ro_consts_primary,
|
||||
&vk.r1cs_shape_primary_digest,
|
||||
&vk.digest,
|
||||
&self.r_U_primary,
|
||||
&self.l_u_primary,
|
||||
)?;
|
||||
let f_U_secondary = self.nifs_secondary.verify(
|
||||
&vk.ro_consts_secondary,
|
||||
&vk.r1cs_shape_secondary_digest,
|
||||
&scalar_as_base::<G1>(vk.digest),
|
||||
&self.r_U_secondary,
|
||||
&self.l_u_secondary,
|
||||
)?;
|
||||
@@ -781,6 +792,36 @@ type Commitment<G> = <<G as Group>::CE as CommitmentEngineTrait<G>>::Commitment;
|
||||
type CompressedCommitment<G> = <<<G as Group>::CE as CommitmentEngineTrait<G>>::Commitment as CommitmentTrait<G>>::CompressedCommitment;
|
||||
type CE<G> = <G as Group>::CE;
|
||||
|
||||
fn compute_digest<G: Group, T: Serialize>(o: &T) -> G::Scalar {
|
||||
// obtain a vector of bytes representing public parameters
|
||||
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
||||
bincode::serialize_into(&mut encoder, o).unwrap();
|
||||
let pp_bytes = encoder.finish().unwrap();
|
||||
|
||||
// convert pp_bytes into a short digest
|
||||
let mut hasher = Sha3_256::new();
|
||||
hasher.input(&pp_bytes);
|
||||
let digest = hasher.result();
|
||||
|
||||
// truncate the digest to NUM_HASH_BITS bits
|
||||
let bv = (0..NUM_HASH_BITS).map(|i| {
|
||||
let (byte_pos, bit_pos) = (i / 8, i % 8);
|
||||
let bit = (digest[byte_pos] >> bit_pos) & 1;
|
||||
bit == 1
|
||||
});
|
||||
|
||||
// turn the bit vector into a scalar
|
||||
let mut digest = G::Scalar::ZERO;
|
||||
let mut coeff = G::Scalar::ONE;
|
||||
for bit in bv {
|
||||
if bit {
|
||||
digest += coeff;
|
||||
}
|
||||
coeff += coeff;
|
||||
}
|
||||
digest
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
44
src/nifs.rs
44
src/nifs.rs
@@ -32,9 +32,11 @@ impl<G: Group> NIFS<G> {
|
||||
/// a folded Relaxed R1CS instance-witness tuple `(U, W)` of the same shape `shape`,
|
||||
/// with the guarantee that the folded witness `W` satisfies the folded instance `U`
|
||||
/// if and only if `W1` satisfies `U1` and `W2` satisfies `U2`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn prove(
|
||||
ck: &CommitmentKey<G>,
|
||||
ro_consts: &ROConstants<G>,
|
||||
pp_digest: &G::Scalar,
|
||||
S: &R1CSShape<G>,
|
||||
U1: &RelaxedR1CSInstance<G>,
|
||||
W1: &RelaxedR1CSWitness<G>,
|
||||
@@ -44,8 +46,8 @@ impl<G: Group> NIFS<G> {
|
||||
// initialize a new RO
|
||||
let mut ro = G::RO::new(ro_consts.clone(), NUM_FE_FOR_RO);
|
||||
|
||||
// append S to the transcript
|
||||
S.absorb_in_ro(&mut ro);
|
||||
// append the digest of pp to the transcript
|
||||
ro.absorb(scalar_as_base::<G>(*pp_digest));
|
||||
|
||||
// append U1 and U2 to transcript
|
||||
U1.absorb_in_ro(&mut ro);
|
||||
@@ -84,15 +86,15 @@ impl<G: Group> NIFS<G> {
|
||||
pub fn verify(
|
||||
&self,
|
||||
ro_consts: &ROConstants<G>,
|
||||
S_digest: &G::Scalar,
|
||||
pp_digest: &G::Scalar,
|
||||
U1: &RelaxedR1CSInstance<G>,
|
||||
U2: &R1CSInstance<G>,
|
||||
) -> Result<RelaxedR1CSInstance<G>, NovaError> {
|
||||
// initialize a new RO
|
||||
let mut ro = G::RO::new(ro_consts.clone(), NUM_FE_FOR_RO);
|
||||
|
||||
// append the digest of S to the transcript
|
||||
ro.absorb(scalar_as_base::<G>(*S_digest));
|
||||
// append the digest of pp to the transcript
|
||||
ro.absorb(scalar_as_base::<G>(*pp_digest));
|
||||
|
||||
// append U1 and U2 to transcript
|
||||
U1.absorb_in_ro(&mut ro);
|
||||
@@ -192,12 +194,23 @@ mod tests {
|
||||
assert!(shape.is_sat(&ck, &U2, &W2).is_ok());
|
||||
|
||||
// execute a sequence of folds
|
||||
execute_sequence(&ck, &ro_consts, &shape, &U1, &W1, &U2, &W2);
|
||||
execute_sequence(
|
||||
&ck,
|
||||
&ro_consts,
|
||||
&<G as Group>::Scalar::ZERO,
|
||||
&shape,
|
||||
&U1,
|
||||
&W1,
|
||||
&U2,
|
||||
&W2,
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn execute_sequence(
|
||||
ck: &CommitmentKey<G>,
|
||||
ro_consts: &<<G as Group>::RO as ROTrait<<G as Group>::Base, <G as Group>::Scalar>>::Constants,
|
||||
pp_digest: &<G as Group>::Scalar,
|
||||
shape: &R1CSShape<G>,
|
||||
U1: &R1CSInstance<G>,
|
||||
W1: &R1CSWitness<G>,
|
||||
@@ -209,12 +222,12 @@ mod tests {
|
||||
let mut r_U = RelaxedR1CSInstance::default(ck, shape);
|
||||
|
||||
// produce a step SNARK with (W1, U1) as the first incoming witness-instance pair
|
||||
let res = NIFS::prove(ck, ro_consts, shape, &r_U, &r_W, U1, W1);
|
||||
let res = NIFS::prove(ck, ro_consts, pp_digest, shape, &r_U, &r_W, U1, W1);
|
||||
assert!(res.is_ok());
|
||||
let (nifs, (_U, W)) = res.unwrap();
|
||||
|
||||
// verify the step SNARK with U1 as the first incoming instance
|
||||
let res = nifs.verify(ro_consts, &shape.get_digest(), &r_U, U1);
|
||||
let res = nifs.verify(ro_consts, pp_digest, &r_U, U1);
|
||||
assert!(res.is_ok());
|
||||
let U = res.unwrap();
|
||||
|
||||
@@ -225,12 +238,12 @@ mod tests {
|
||||
r_U = U;
|
||||
|
||||
// produce a step SNARK with (W2, U2) as the second incoming witness-instance pair
|
||||
let res = NIFS::prove(ck, ro_consts, shape, &r_U, &r_W, U2, W2);
|
||||
let res = NIFS::prove(ck, ro_consts, pp_digest, shape, &r_U, &r_W, U2, W2);
|
||||
assert!(res.is_ok());
|
||||
let (nifs, (_U, W)) = res.unwrap();
|
||||
|
||||
// verify the step SNARK with U1 as the first incoming instance
|
||||
let res = nifs.verify(ro_consts, &shape.get_digest(), &r_U, U2);
|
||||
let res = nifs.verify(ro_consts, pp_digest, &r_U, U2);
|
||||
assert!(res.is_ok());
|
||||
let U = res.unwrap();
|
||||
|
||||
@@ -349,6 +362,15 @@ mod tests {
|
||||
let (_O, U2, W2) = rand_inst_witness_generator(&ck, &O);
|
||||
|
||||
// execute a sequence of folds
|
||||
execute_sequence(&ck, &ro_consts, &S, &U1, &W1, &U2, &W2);
|
||||
execute_sequence(
|
||||
&ck,
|
||||
&ro_consts,
|
||||
&<G as Group>::Scalar::ZERO,
|
||||
&S,
|
||||
&U1,
|
||||
&W1,
|
||||
&U2,
|
||||
&W2,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
100
src/r1cs.rs
100
src/r1cs.rs
@@ -1,7 +1,7 @@
|
||||
//! This module defines R1CS related types and a folding scheme for Relaxed R1CS
|
||||
#![allow(clippy::type_complexity)]
|
||||
use crate::{
|
||||
constants::{BN_LIMB_WIDTH, BN_N_LIMBS, NUM_HASH_BITS},
|
||||
constants::{BN_LIMB_WIDTH, BN_N_LIMBS},
|
||||
errors::NovaError,
|
||||
gadgets::{
|
||||
nonnative::{bignat::nat_to_limbs, util::f_to_nat},
|
||||
@@ -14,11 +14,9 @@ use crate::{
|
||||
};
|
||||
use core::{cmp::max, marker::PhantomData};
|
||||
use ff::Field;
|
||||
use flate2::{write::ZlibEncoder, Compression};
|
||||
use itertools::concat;
|
||||
use rayon::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha3::{Digest, Sha3_256};
|
||||
|
||||
/// Public parameters for a given R1CS
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
@@ -36,7 +34,6 @@ pub struct R1CSShape<G: Group> {
|
||||
pub(crate) A: Vec<(usize, usize, G::Scalar)>,
|
||||
pub(crate) B: Vec<(usize, usize, G::Scalar)>,
|
||||
pub(crate) C: Vec<(usize, usize, G::Scalar)>,
|
||||
digest: G::Scalar, // digest of the rest of R1CSShape
|
||||
}
|
||||
|
||||
/// A type that holds a witness for a given R1CS instance
|
||||
@@ -126,19 +123,14 @@ impl<G: Group> R1CSShape<G> {
|
||||
return Err(NovaError::OddInputLength);
|
||||
}
|
||||
|
||||
let digest = Self::compute_digest(num_cons, num_vars, num_io, A, B, C);
|
||||
|
||||
let shape = R1CSShape {
|
||||
Ok(R1CSShape {
|
||||
num_cons,
|
||||
num_vars,
|
||||
num_io,
|
||||
A: A.to_owned(),
|
||||
B: B.to_owned(),
|
||||
C: C.to_owned(),
|
||||
digest,
|
||||
};
|
||||
|
||||
Ok(shape)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn multiply_vec(
|
||||
@@ -303,67 +295,6 @@ impl<G: Group> R1CSShape<G> {
|
||||
Ok((T, comm_T))
|
||||
}
|
||||
|
||||
/// returns the digest of R1CSShape
|
||||
pub fn get_digest(&self) -> G::Scalar {
|
||||
self.digest
|
||||
}
|
||||
|
||||
fn compute_digest(
|
||||
num_cons: usize,
|
||||
num_vars: usize,
|
||||
num_io: usize,
|
||||
A: &[(usize, usize, G::Scalar)],
|
||||
B: &[(usize, usize, G::Scalar)],
|
||||
C: &[(usize, usize, G::Scalar)],
|
||||
) -> G::Scalar {
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct R1CSShapeWithoutDigest<G: Group> {
|
||||
num_cons: usize,
|
||||
num_vars: usize,
|
||||
num_io: usize,
|
||||
A: Vec<(usize, usize, G::Scalar)>,
|
||||
B: Vec<(usize, usize, G::Scalar)>,
|
||||
C: Vec<(usize, usize, G::Scalar)>,
|
||||
}
|
||||
|
||||
let shape = R1CSShapeWithoutDigest::<G> {
|
||||
num_cons,
|
||||
num_vars,
|
||||
num_io,
|
||||
A: A.to_vec(),
|
||||
B: B.to_vec(),
|
||||
C: C.to_vec(),
|
||||
};
|
||||
|
||||
// obtain a vector of bytes representing the R1CS shape
|
||||
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::default());
|
||||
bincode::serialize_into(&mut encoder, &shape).unwrap();
|
||||
let shape_bytes = encoder.finish().unwrap();
|
||||
|
||||
// convert shape_bytes into a short digest
|
||||
let mut hasher = Sha3_256::new();
|
||||
hasher.input(&shape_bytes);
|
||||
let digest = hasher.result();
|
||||
|
||||
// truncate the digest to 250 bits
|
||||
let bv = (0..NUM_HASH_BITS).map(|i| {
|
||||
let (byte_pos, bit_pos) = (i / 8, i % 8);
|
||||
let bit = (digest[byte_pos] >> bit_pos) & 1;
|
||||
bit == 1
|
||||
});
|
||||
|
||||
// turn the bit vector into a scalar
|
||||
let mut res = G::Scalar::ZERO;
|
||||
let mut coeff = G::Scalar::ONE;
|
||||
for bit in bv {
|
||||
if bit {
|
||||
res += coeff;
|
||||
}
|
||||
coeff += coeff;
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
/// Pads the R1CSShape so that the number of variables is a power of two
|
||||
/// Renumbers variables to accomodate padded variables
|
||||
pub fn pad(&self) -> Self {
|
||||
@@ -378,8 +309,6 @@ impl<G: Group> R1CSShape<G> {
|
||||
// check if the number of variables are as expected, then
|
||||
// we simply set the number of constraints to the next power of two
|
||||
if self.num_vars == m {
|
||||
let digest = Self::compute_digest(m, self.num_vars, self.num_io, &self.A, &self.B, &self.C);
|
||||
|
||||
return R1CSShape {
|
||||
num_cons: m,
|
||||
num_vars: m,
|
||||
@@ -387,7 +316,6 @@ impl<G: Group> R1CSShape<G> {
|
||||
A: self.A.clone(),
|
||||
B: self.B.clone(),
|
||||
C: self.C.clone(),
|
||||
digest,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -414,15 +342,6 @@ impl<G: Group> R1CSShape<G> {
|
||||
let B_padded = apply_pad(&self.B);
|
||||
let C_padded = apply_pad(&self.C);
|
||||
|
||||
let digest = Self::compute_digest(
|
||||
num_cons_padded,
|
||||
num_vars_padded,
|
||||
self.num_io,
|
||||
&A_padded,
|
||||
&B_padded,
|
||||
&C_padded,
|
||||
);
|
||||
|
||||
R1CSShape {
|
||||
num_cons: num_cons_padded,
|
||||
num_vars: num_vars_padded,
|
||||
@@ -430,23 +349,10 @@ impl<G: Group> R1CSShape<G> {
|
||||
A: A_padded,
|
||||
B: B_padded,
|
||||
C: C_padded,
|
||||
digest,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> TranscriptReprTrait<G> for R1CSShape<G> {
|
||||
fn to_transcript_bytes(&self) -> Vec<u8> {
|
||||
self.get_digest().to_transcript_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> AbsorbInROTrait<G> for R1CSShape<G> {
|
||||
fn absorb_in_ro(&self, ro: &mut G::RO) {
|
||||
ro.absorb(scalar_as_base::<G>(self.get_digest()));
|
||||
}
|
||||
}
|
||||
|
||||
impl<G: Group> R1CSWitness<G> {
|
||||
/// A method to create a witness object using a vector of scalars
|
||||
pub fn new(S: &R1CSShape<G>, W: &[G::Scalar]) -> Result<R1CSWitness<G>, NovaError> {
|
||||
|
||||
@@ -6,6 +6,7 @@ pub mod pp;
|
||||
mod sumcheck;
|
||||
|
||||
use crate::{
|
||||
compute_digest,
|
||||
errors::NovaError,
|
||||
r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
|
||||
traits::{
|
||||
@@ -129,6 +130,7 @@ impl<G: Group> PolyEvalInstance<G> {
|
||||
pub struct ProverKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
||||
pk_ee: EE::ProverKey,
|
||||
S: R1CSShape<G>,
|
||||
vk_digest: G::Scalar, // digest of the verifier's key
|
||||
}
|
||||
|
||||
/// A type that represents the verifier's key
|
||||
@@ -137,6 +139,7 @@ pub struct ProverKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
||||
pub struct VerifierKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
||||
vk_ee: EE::VerifierKey,
|
||||
S: R1CSShape<G>,
|
||||
digest: G::Scalar,
|
||||
}
|
||||
|
||||
/// A succinct proof of knowledge of a witness to a relaxed R1CS instance
|
||||
@@ -169,12 +172,21 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
|
||||
let S = S.pad();
|
||||
|
||||
let vk = VerifierKey {
|
||||
vk_ee,
|
||||
S: S.clone(),
|
||||
let vk = {
|
||||
let mut vk = VerifierKey {
|
||||
vk_ee,
|
||||
S: S.clone(),
|
||||
digest: G::Scalar::ZERO,
|
||||
};
|
||||
vk.digest = compute_digest::<G, VerifierKey<G, EE>>(&vk);
|
||||
vk
|
||||
};
|
||||
|
||||
let pk = ProverKey { pk_ee, S };
|
||||
let pk = ProverKey {
|
||||
pk_ee,
|
||||
S,
|
||||
vk_digest: vk.digest,
|
||||
};
|
||||
|
||||
Ok((pk, vk))
|
||||
}
|
||||
@@ -195,8 +207,8 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
assert_eq!(pk.S.num_io.next_power_of_two(), pk.S.num_io);
|
||||
assert!(pk.S.num_io < pk.S.num_vars);
|
||||
|
||||
// append the digest of R1CS matrices and the RelaxedR1CSInstance to the transcript
|
||||
transcript.absorb(b"S", &pk.S);
|
||||
// append the digest of vk (which includes R1CS matrices) and the RelaxedR1CSInstance to the transcript
|
||||
transcript.absorb(b"vk", &pk.vk_digest);
|
||||
transcript.absorb(b"U", U);
|
||||
|
||||
// compute the full satisfying assignment by concatenating W.W, U.u, and U.X
|
||||
@@ -437,7 +449,7 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
let mut transcript = G::TE::new(b"RelaxedR1CSSNARK");
|
||||
|
||||
// append the digest of R1CS matrices and the RelaxedR1CSInstance to the transcript
|
||||
transcript.absorb(b"S", &vk.S);
|
||||
transcript.absorb(b"vk", &vk.digest);
|
||||
transcript.absorb(b"U", U);
|
||||
|
||||
let (num_rounds_x, num_rounds_y) = (
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
shape_cs::ShapeCS,
|
||||
solver::SatisfyingAssignment,
|
||||
},
|
||||
compute_digest,
|
||||
errors::NovaError,
|
||||
r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness},
|
||||
spartan::{
|
||||
@@ -736,6 +737,7 @@ pub struct ProverKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
||||
S: R1CSShape<G>,
|
||||
S_repr: R1CSShapeSparkRepr<G>,
|
||||
S_comm: R1CSShapeSparkCommitment<G>,
|
||||
vk_digest: G::Scalar, // digest of verifier's key
|
||||
}
|
||||
|
||||
/// A type that represents the verifier's key
|
||||
@@ -746,6 +748,7 @@ pub struct VerifierKey<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> {
|
||||
num_vars: usize,
|
||||
vk_ee: EE::VerifierKey,
|
||||
S_comm: R1CSShapeSparkCommitment<G>,
|
||||
digest: G::Scalar,
|
||||
}
|
||||
|
||||
/// A succinct proof of knowledge of a witness to a relaxed R1CS instance
|
||||
@@ -938,11 +941,16 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
let S_repr = R1CSShapeSparkRepr::new(&S);
|
||||
let S_comm = S_repr.commit(ck);
|
||||
|
||||
let vk = VerifierKey {
|
||||
num_cons: S.num_cons,
|
||||
num_vars: S.num_vars,
|
||||
S_comm: S_comm.clone(),
|
||||
vk_ee,
|
||||
let vk = {
|
||||
let mut vk = VerifierKey {
|
||||
num_cons: S.num_cons,
|
||||
num_vars: S.num_vars,
|
||||
S_comm: S_comm.clone(),
|
||||
vk_ee,
|
||||
digest: G::Scalar::ZERO,
|
||||
};
|
||||
vk.digest = compute_digest::<G, VerifierKey<G, EE>>(&vk);
|
||||
vk
|
||||
};
|
||||
|
||||
let pk = ProverKey {
|
||||
@@ -950,6 +958,7 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
S,
|
||||
S_repr,
|
||||
S_comm,
|
||||
vk_digest: vk.digest,
|
||||
};
|
||||
|
||||
Ok((pk, vk))
|
||||
@@ -974,8 +983,8 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
assert_eq!(pk.S.num_io.next_power_of_two(), pk.S.num_io);
|
||||
assert!(pk.S.num_io < pk.S.num_vars);
|
||||
|
||||
// append the commitment to R1CS matrices and the RelaxedR1CSInstance to the transcript
|
||||
transcript.absorb(b"C", &pk.S_comm);
|
||||
// append the verifier key (which includes commitment to R1CS matrices) and the RelaxedR1CSInstance to the transcript
|
||||
transcript.absorb(b"vk", &pk.vk_digest);
|
||||
transcript.absorb(b"U", U);
|
||||
|
||||
// compute the full satisfying assignment by concatenating W.W, U.u, and U.X
|
||||
@@ -1568,8 +1577,8 @@ impl<G: Group, EE: EvaluationEngineTrait<G, CE = G::CE>> RelaxedR1CSSNARKTrait<G
|
||||
let mut transcript = G::TE::new(b"RelaxedR1CSSNARK");
|
||||
let mut u_vec: Vec<PolyEvalInstance<G>> = Vec::new();
|
||||
|
||||
// append the commitment to R1CS matrices and the RelaxedR1CSInstance to the transcript
|
||||
transcript.absorb(b"C", &vk.S_comm);
|
||||
// append the verifier key (including commitment to R1CS matrices) and the RelaxedR1CSInstance to the transcript
|
||||
transcript.absorb(b"vk", &vk.digest);
|
||||
transcript.absorb(b"U", U);
|
||||
|
||||
let comm_Az = Commitment::<G>::decompress(&self.comm_Az)?;
|
||||
|
||||
Reference in New Issue
Block a user