mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-26 05:53:51 +01:00
Unify the computation of digests and challenges in different folding schemes (#94)
* Remove the trait bound `C::BaseField: PrimeField` for better DX
* Methods in `TranscriptVar` now exactly matches the ones in `Transcript`
* Add `ProtoGalaxyTranscriptVar` and `CommittedInstanceVar` for protogalaxy
* betas are unnecessary in "plain" (incoming) instances
* Absorb the result of `get_challenge_nbits` as well
* `ProtoGalaxyTranscript` now allows absorbing mulitple instances
* Always return `Result<(), SynthesisError>` in `ProtoGalaxyTranscriptVar`
* Impl `Transcript{Var}` for `PoseidonSponge{Var}` directly and remove `PoseidonTranscript{Var}`
* `Transcript::absorb_point` doesn't need to return `Error`
* Add `AbsorbNonNative` trait for hashing non-native values
Note that now `absorb_point` only supports hashing points whose BaseField is equal to the sponge's field
* More efficient `TranscriptVar::absorb_point` by securely removing `is_inf`
* Use `sponge` and `transcript` consistently
* Clarify the usage of `AbsorbNonNative{Gadget}`
* Generic `sponge` and `transcript` params
* Avoid unstable `associated_type_bounds`
* Reuse `sponge` in hypernova
* Clean up redundant imports
* Remove unstable code
* Clarify the usage of `absorb_point` and `absorb_nonnative`
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
/// Implements the scheme described in [HyperNova](https://eprint.iacr.org/2023/573.pdf)
|
||||
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
|
||||
use ark_crypto_primitives::sponge::{
|
||||
poseidon::{PoseidonConfig, PoseidonSponge},
|
||||
Absorb, CryptographicSponge,
|
||||
};
|
||||
use ark_ec::{CurveGroup, Group};
|
||||
use ark_ff::{BigInteger, PrimeField};
|
||||
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
|
||||
@@ -18,6 +21,10 @@ use cccs::CCCS;
|
||||
use lcccs::LCCCS;
|
||||
use nimfs::NIMFS;
|
||||
|
||||
use crate::arith::{
|
||||
ccs::CCS,
|
||||
r1cs::{extract_w_x, R1CS},
|
||||
};
|
||||
use crate::commitment::CommitmentScheme;
|
||||
use crate::folding::circuits::{
|
||||
cyclefold::{fold_cyclefold_circuit, CycleFoldCircuit},
|
||||
@@ -31,13 +38,6 @@ use crate::frontend::FCircuit;
|
||||
use crate::utils::{get_cm_coordinates, pp_hash};
|
||||
use crate::Error;
|
||||
use crate::FoldingScheme;
|
||||
use crate::{
|
||||
arith::{
|
||||
ccs::CCS,
|
||||
r1cs::{extract_w_x, R1CS},
|
||||
},
|
||||
transcript::{poseidon::PoseidonTranscript, Transcript},
|
||||
};
|
||||
|
||||
/// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment.
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
@@ -233,6 +233,8 @@ where
|
||||
z_0: Vec<C1::ScalarField>,
|
||||
) -> Result<Self, Error> {
|
||||
let (pp, vp) = params;
|
||||
// `sponge` is for digest computation.
|
||||
let sponge = PoseidonSponge::<C1::ScalarField>::new(&pp.poseidon_config);
|
||||
|
||||
// prepare the HyperNova's AugmentedFCircuit and CycleFold's circuits and obtain its CCS
|
||||
// and R1CS respectively
|
||||
@@ -258,13 +260,13 @@ where
|
||||
cf_r1cs.dummy_instance();
|
||||
u_dummy.x = vec![
|
||||
U_dummy.hash(
|
||||
&pp.poseidon_config,
|
||||
&sponge,
|
||||
pp_hash,
|
||||
C1::ScalarField::zero(),
|
||||
z_0.clone(),
|
||||
z_0.clone(),
|
||||
)?,
|
||||
cf_U_dummy.hash_cyclefold(&pp.poseidon_config, pp_hash)?,
|
||||
),
|
||||
cf_U_dummy.hash_cyclefold(&sponge, pp_hash),
|
||||
];
|
||||
|
||||
// W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the
|
||||
@@ -299,6 +301,9 @@ where
|
||||
mut rng: impl RngCore,
|
||||
external_inputs: Vec<C1::ScalarField>,
|
||||
) -> Result<(), Error> {
|
||||
// `sponge` is for digest computation.
|
||||
let sponge = PoseidonSponge::<C1::ScalarField>::new(&self.poseidon_config);
|
||||
|
||||
let augmented_f_circuit: AugmentedFCircuit<C1, C2, GC2, FC>;
|
||||
|
||||
if self.z_i.len() != self.F.state_len() {
|
||||
@@ -339,18 +344,16 @@ where
|
||||
U_i1 = LCCCS::dummy(self.ccs.l, self.ccs.t, self.ccs.s);
|
||||
|
||||
let u_i1_x = U_i1.hash(
|
||||
&self.poseidon_config,
|
||||
&sponge,
|
||||
self.pp_hash,
|
||||
C1::ScalarField::one(),
|
||||
self.z_0.clone(),
|
||||
z_i1.clone(),
|
||||
)?;
|
||||
);
|
||||
|
||||
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
||||
// input in the AugmentedFCircuit
|
||||
cf_u_i1_x = self
|
||||
.cf_U_i
|
||||
.hash_cyclefold(&self.poseidon_config, self.pp_hash)?;
|
||||
cf_u_i1_x = self.cf_U_i.hash_cyclefold(&sponge, self.pp_hash);
|
||||
|
||||
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
||||
_c2: PhantomData,
|
||||
@@ -377,30 +380,31 @@ where
|
||||
cf_cmT: None,
|
||||
};
|
||||
} else {
|
||||
let mut transcript_p: PoseidonTranscript<C1> =
|
||||
PoseidonTranscript::<C1>::new(&self.poseidon_config);
|
||||
let mut transcript_p: PoseidonSponge<C1::ScalarField> =
|
||||
PoseidonSponge::<C1::ScalarField>::new(&self.poseidon_config);
|
||||
transcript_p.absorb(&self.pp_hash);
|
||||
let (rho_bits, nimfs_proof);
|
||||
(nimfs_proof, U_i1, W_i1, rho_bits) = NIMFS::<C1, PoseidonTranscript<C1>>::prove(
|
||||
&mut transcript_p,
|
||||
&self.ccs,
|
||||
&[self.U_i.clone()],
|
||||
&[self.u_i.clone()],
|
||||
&[self.W_i.clone()],
|
||||
&[self.w_i.clone()],
|
||||
)?;
|
||||
(nimfs_proof, U_i1, W_i1, rho_bits) =
|
||||
NIMFS::<C1, PoseidonSponge<C1::ScalarField>>::prove(
|
||||
&mut transcript_p,
|
||||
&self.ccs,
|
||||
&[self.U_i.clone()],
|
||||
&[self.u_i.clone()],
|
||||
&[self.W_i.clone()],
|
||||
&[self.w_i.clone()],
|
||||
)?;
|
||||
|
||||
// sanity check: check the folded instance relation
|
||||
#[cfg(test)]
|
||||
U_i1.check_relation(&self.ccs, &W_i1)?;
|
||||
|
||||
let u_i1_x = U_i1.hash(
|
||||
&self.poseidon_config,
|
||||
&sponge,
|
||||
self.pp_hash,
|
||||
self.i + C1::ScalarField::one(),
|
||||
self.z_0.clone(),
|
||||
z_i1.clone(),
|
||||
)?;
|
||||
);
|
||||
|
||||
let rho_Fq = C2::ScalarField::from_bigint(BigInteger::from_bits_le(&rho_bits))
|
||||
.ok_or(Error::OutOfBounds)?;
|
||||
@@ -425,7 +429,7 @@ where
|
||||
|
||||
let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) =
|
||||
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2>(
|
||||
&self.poseidon_config,
|
||||
&mut transcript_p,
|
||||
self.cf_r1cs.clone(),
|
||||
self.cf_cs_params.clone(),
|
||||
self.pp_hash,
|
||||
@@ -435,7 +439,7 @@ where
|
||||
cf_circuit,
|
||||
)?;
|
||||
|
||||
cf_u_i1_x = cf_U_i1.hash_cyclefold(&self.poseidon_config, self.pp_hash)?;
|
||||
cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, self.pp_hash);
|
||||
|
||||
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
||||
_c2: PhantomData,
|
||||
@@ -541,6 +545,8 @@ where
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
// `sponge` is for digest computation.
|
||||
let sponge = PoseidonSponge::<C1::ScalarField>::new(&vp.poseidon_config);
|
||||
|
||||
let (U_i, W_i) = running_instance;
|
||||
let (u_i, w_i) = incoming_instance;
|
||||
@@ -553,12 +559,12 @@ where
|
||||
|
||||
// check that u_i's output points to the running instance
|
||||
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
||||
let expected_u_i_x = U_i.hash(&vp.poseidon_config, pp_hash, num_steps, z_0, z_i.clone())?;
|
||||
let expected_u_i_x = U_i.hash(&sponge, pp_hash, num_steps, z_0, z_i.clone());
|
||||
if expected_u_i_x != u_i.x[0] {
|
||||
return Err(Error::IVCVerificationFail);
|
||||
}
|
||||
// u_i.X[1] == H(cf_U_i)
|
||||
let expected_cf_u_i_x = cf_U_i.hash_cyclefold(&vp.poseidon_config, pp_hash)?;
|
||||
let expected_cf_u_i_x = cf_U_i.hash_cyclefold(&sponge, pp_hash);
|
||||
if expected_cf_u_i_x != u_i.x[1] {
|
||||
return Err(Error::IVCVerificationFail);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user