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