|
@ -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,
|
|
|
|
|
|
r1cs_shape_secondary_digest: G2::Scalar,
|
|
|
|
|
|
|
|
|
digest: G1::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(),
|
|
|
|
|
|
r1cs_shape_secondary_digest: pp.r1cs_shape_secondary.get_digest(),
|
|
|
|
|
|
|
|
|
digest: pp.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 = <::CE as CommitmentEngineTrait>::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::*;
|
|
|