mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-08 15:01:30 +01:00
Traits for witnesses and committed instances (#157)
* Add traits for witness and committed instance
* Implement witness and committed instance traits for Nova and HyperNova
* Implement witness and committed instance traits for ProtoGalaxy
* Improve the clarity of docs for `Witness{Var}Ext::get_openings`
* Avoid cloning `z_i`
* Fix grammar issues
* Rename `Ext` traits for committed instances and witnesses to `Ops`
* Implement `to_sponge_bytes`
This commit is contained in:
@@ -9,9 +9,11 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use ark_std::rand::Rng;
|
use ark_std::rand::Rng;
|
||||||
|
|
||||||
|
use super::circuits::CCCSVar;
|
||||||
use super::Witness;
|
use super::Witness;
|
||||||
use crate::arith::{ccs::CCS, Arith};
|
use crate::arith::{ccs::CCS, Arith};
|
||||||
use crate::commitment::CommitmentScheme;
|
use crate::commitment::CommitmentScheme;
|
||||||
|
use crate::folding::traits::CommittedInstanceOps;
|
||||||
use crate::transcript::AbsorbNonNative;
|
use crate::transcript::AbsorbNonNative;
|
||||||
use crate::utils::mle::dense_vec_to_dense_mle;
|
use crate::utils::mle::dense_vec_to_dense_mle;
|
||||||
use crate::utils::vec::mat_vec_mul;
|
use crate::utils::vec::mat_vec_mul;
|
||||||
@@ -126,9 +128,8 @@ impl<C: CurveGroup> Absorb for CCCS<C>
|
|||||||
where
|
where
|
||||||
C::ScalarField: Absorb,
|
C::ScalarField: Absorb,
|
||||||
{
|
{
|
||||||
fn to_sponge_bytes(&self, _dest: &mut Vec<u8>) {
|
fn to_sponge_bytes(&self, dest: &mut Vec<u8>) {
|
||||||
// This is never called
|
C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest);
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
|
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
|
||||||
@@ -142,6 +143,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C: CurveGroup> CommittedInstanceOps<C> for CCCS<C> {
|
||||||
|
type Var = CCCSVar<C>;
|
||||||
|
|
||||||
|
fn get_commitments(&self) -> Vec<C> {
|
||||||
|
vec![self.C]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_incoming(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use ark_pallas::Fr;
|
use ark_pallas::Fr;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/// Implementation of [HyperNova](https://eprint.iacr.org/2023/573.pdf) circuits
|
/// Implementation of [HyperNova](https://eprint.iacr.org/2023/573.pdf) circuits
|
||||||
use ark_crypto_primitives::sponge::{
|
use ark_crypto_primitives::sponge::{
|
||||||
constraints::CryptographicSpongeVar,
|
constraints::{AbsorbGadget, CryptographicSpongeVar},
|
||||||
poseidon::{constraints::PoseidonSpongeVar, PoseidonSponge},
|
poseidon::{constraints::PoseidonSpongeVar, PoseidonSponge},
|
||||||
CryptographicSponge,
|
CryptographicSponge,
|
||||||
};
|
};
|
||||||
@@ -14,6 +14,7 @@ use ark_r1cs_std::{
|
|||||||
fields::{fp::FpVar, FieldVar},
|
fields::{fp::FpVar, FieldVar},
|
||||||
groups::GroupOpsBounds,
|
groups::GroupOpsBounds,
|
||||||
prelude::CurveVar,
|
prelude::CurveVar,
|
||||||
|
uint8::UInt8,
|
||||||
R1CSVar, ToConstraintFieldGadget,
|
R1CSVar, ToConstraintFieldGadget,
|
||||||
};
|
};
|
||||||
use ark_relations::r1cs::{
|
use ark_relations::r1cs::{
|
||||||
@@ -41,6 +42,7 @@ use crate::folding::{
|
|||||||
CF1, CF2,
|
CF1, CF2,
|
||||||
},
|
},
|
||||||
nova::get_r1cs_from_cs,
|
nova::get_r1cs_from_cs,
|
||||||
|
traits::CommittedInstanceVarOps,
|
||||||
};
|
};
|
||||||
use crate::frontend::FCircuit;
|
use crate::frontend::FCircuit;
|
||||||
use crate::utils::virtual_polynomial::VPAuxInfo;
|
use crate::utils::virtual_polynomial::VPAuxInfo;
|
||||||
@@ -52,19 +54,16 @@ use crate::{
|
|||||||
|
|
||||||
/// Committed CCS instance
|
/// Committed CCS instance
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CCCSVar<C: CurveGroup>
|
pub struct CCCSVar<C: CurveGroup> {
|
||||||
where
|
|
||||||
<C as CurveGroup>::BaseField: PrimeField,
|
|
||||||
{
|
|
||||||
// Commitment to witness
|
// Commitment to witness
|
||||||
pub C: NonNativeAffineVar<C>,
|
pub C: NonNativeAffineVar<C>,
|
||||||
// Public io
|
// Public io
|
||||||
pub x: Vec<FpVar<CF1<C>>>,
|
pub x: Vec<FpVar<CF1<C>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> AllocVar<CCCS<C>, CF1<C>> for CCCSVar<C>
|
impl<C> AllocVar<CCCS<C>, CF1<C>> for CCCSVar<C>
|
||||||
where
|
where
|
||||||
C: CurveGroup,
|
C: CurveGroup,
|
||||||
<C as ark_ec::CurveGroup>::BaseField: PrimeField,
|
|
||||||
{
|
{
|
||||||
fn new_variable<T: Borrow<CCCS<C>>>(
|
fn new_variable<T: Borrow<CCCS<C>>>(
|
||||||
cs: impl Into<Namespace<CF1<C>>>,
|
cs: impl Into<Namespace<CF1<C>>>,
|
||||||
@@ -83,12 +82,30 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C: CurveGroup> CommittedInstanceVarOps<C> for CCCSVar<C> {
|
||||||
|
type PointVar = NonNativeAffineVar<C>;
|
||||||
|
|
||||||
|
fn get_commitments(&self) -> Vec<Self::PointVar> {
|
||||||
|
vec![self.C.clone()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_public_inputs(&self) -> &[FpVar<CF1<C>>] {
|
||||||
|
&self.x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_incoming(&self) -> Result<(), SynthesisError> {
|
||||||
|
// `CCCSVar` is always the incoming instance
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_partial_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
||||||
|
self.x.enforce_equal(&other.x)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Linearized Committed CCS instance
|
/// Linearized Committed CCS instance
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LCCCSVar<C: CurveGroup>
|
pub struct LCCCSVar<C: CurveGroup> {
|
||||||
where
|
|
||||||
<C as CurveGroup>::BaseField: PrimeField,
|
|
||||||
{
|
|
||||||
// Commitment to witness
|
// Commitment to witness
|
||||||
pub C: NonNativeAffineVar<C>,
|
pub C: NonNativeAffineVar<C>,
|
||||||
// Relaxation factor of z for folded LCCCS
|
// Relaxation factor of z for folded LCCCS
|
||||||
@@ -100,10 +117,10 @@ where
|
|||||||
// Vector of v_i
|
// Vector of v_i
|
||||||
pub v: Vec<FpVar<CF1<C>>>,
|
pub v: Vec<FpVar<CF1<C>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> AllocVar<LCCCS<C>, CF1<C>> for LCCCSVar<C>
|
impl<C> AllocVar<LCCCS<C>, CF1<C>> for LCCCSVar<C>
|
||||||
where
|
where
|
||||||
C: CurveGroup,
|
C: CurveGroup,
|
||||||
<C as ark_ec::CurveGroup>::BaseField: PrimeField,
|
|
||||||
{
|
{
|
||||||
fn new_variable<T: Borrow<LCCCS<C>>>(
|
fn new_variable<T: Borrow<LCCCS<C>>>(
|
||||||
cs: impl Into<Namespace<CF1<C>>>,
|
cs: impl Into<Namespace<CF1<C>>>,
|
||||||
@@ -127,41 +144,44 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> LCCCSVar<C>
|
impl<C: CurveGroup> AbsorbGadget<C::ScalarField> for LCCCSVar<C> {
|
||||||
where
|
fn to_sponge_bytes(&self) -> Result<Vec<UInt8<C::ScalarField>>, SynthesisError> {
|
||||||
C: CurveGroup,
|
FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?)
|
||||||
<C as Group>::ScalarField: Absorb,
|
}
|
||||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
|
||||||
{
|
fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
|
||||||
/// [`LCCCSVar`].hash implements the LCCCS instance hash compatible with the native
|
Ok([
|
||||||
/// implementation from LCCCS.hash.
|
&self.C.to_constraint_field()?,
|
||||||
/// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and `U` is the LCCCS.
|
&[self.u.clone()][..],
|
||||||
/// Additionally it returns the vector of the field elements from the self parameters, so they
|
&self.x,
|
||||||
/// can be reused in other gadgets avoiding recalculating (reconstraining) them.
|
&self.r_x,
|
||||||
#[allow(clippy::type_complexity)]
|
&self.v,
|
||||||
pub fn hash(
|
|
||||||
self,
|
|
||||||
sponge: &PoseidonSpongeVar<CF1<C>>,
|
|
||||||
pp_hash: FpVar<CF1<C>>,
|
|
||||||
i: FpVar<CF1<C>>,
|
|
||||||
z_0: Vec<FpVar<CF1<C>>>,
|
|
||||||
z_i: Vec<FpVar<CF1<C>>>,
|
|
||||||
) -> Result<(FpVar<CF1<C>>, Vec<FpVar<CF1<C>>>), SynthesisError> {
|
|
||||||
let mut sponge = sponge.clone();
|
|
||||||
let U_vec = [
|
|
||||||
self.C.to_constraint_field()?,
|
|
||||||
vec![self.u],
|
|
||||||
self.x,
|
|
||||||
self.r_x,
|
|
||||||
self.v,
|
|
||||||
]
|
]
|
||||||
.concat();
|
.concat())
|
||||||
sponge.absorb(&pp_hash)?;
|
}
|
||||||
sponge.absorb(&i)?;
|
}
|
||||||
sponge.absorb(&z_0)?;
|
|
||||||
sponge.absorb(&z_i)?;
|
impl<C: CurveGroup> CommittedInstanceVarOps<C> for LCCCSVar<C> {
|
||||||
sponge.absorb(&U_vec)?;
|
type PointVar = NonNativeAffineVar<C>;
|
||||||
Ok((sponge.squeeze_field_elements(1)?.pop().unwrap(), U_vec))
|
|
||||||
|
fn get_commitments(&self) -> Vec<Self::PointVar> {
|
||||||
|
vec![self.C.clone()]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_public_inputs(&self) -> &[FpVar<CF1<C>>] {
|
||||||
|
&self.x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_incoming(&self) -> Result<(), SynthesisError> {
|
||||||
|
// `LCCCSVar` is always the running instance
|
||||||
|
Err(SynthesisError::Unsatisfiable)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enforce_partial_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
||||||
|
self.u.enforce_equal(&other.u)?;
|
||||||
|
self.x.enforce_equal(&other.x)?;
|
||||||
|
self.r_x.enforce_equal(&other.r_x)?;
|
||||||
|
self.v.enforce_equal(&other.v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,25 +762,13 @@ where
|
|||||||
|
|
||||||
let sponge = PoseidonSpongeVar::<C1::ScalarField>::new(cs.clone(), &self.poseidon_config);
|
let sponge = PoseidonSpongeVar::<C1::ScalarField>::new(cs.clone(), &self.poseidon_config);
|
||||||
|
|
||||||
// get z_{i+1} from the F circuit
|
|
||||||
let i_usize = self.i_usize.unwrap_or(0);
|
|
||||||
let z_i1 =
|
|
||||||
self.F
|
|
||||||
.generate_step_constraints(cs.clone(), i_usize, z_i.clone(), external_inputs)?;
|
|
||||||
|
|
||||||
let is_basecase = i.is_zero()?;
|
let is_basecase = i.is_zero()?;
|
||||||
let is_not_basecase = is_basecase.not();
|
let is_not_basecase = is_basecase.not();
|
||||||
|
|
||||||
// Primary Part
|
// Primary Part
|
||||||
// P.1. Compute u_i.x
|
// P.1. Compute u_i.x
|
||||||
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
||||||
let (u_i_x, _) = U_i.clone().hash(
|
let (u_i_x, _) = U_i.clone().hash(&sponge, &pp_hash, &i, &z_0, &z_i)?;
|
||||||
&sponge,
|
|
||||||
pp_hash.clone(),
|
|
||||||
i.clone(),
|
|
||||||
z_0.clone(),
|
|
||||||
z_i.clone(),
|
|
||||||
)?;
|
|
||||||
// u_i.x[1] = H(cf_U_i)
|
// u_i.x[1] = H(cf_U_i)
|
||||||
let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&sponge, pp_hash.clone())?;
|
let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&sponge, pp_hash.clone())?;
|
||||||
|
|
||||||
@@ -795,19 +803,26 @@ where
|
|||||||
U_i1.C = U_i1_C;
|
U_i1.C = U_i1_C;
|
||||||
|
|
||||||
// P.4.a compute and check the first output of F'
|
// P.4.a compute and check the first output of F'
|
||||||
|
|
||||||
|
// get z_{i+1} from the F circuit
|
||||||
|
let i_usize = self.i_usize.unwrap_or(0);
|
||||||
|
let z_i1 = self
|
||||||
|
.F
|
||||||
|
.generate_step_constraints(cs.clone(), i_usize, z_i, external_inputs)?;
|
||||||
|
|
||||||
let (u_i1_x, _) = U_i1.clone().hash(
|
let (u_i1_x, _) = U_i1.clone().hash(
|
||||||
&sponge,
|
&sponge,
|
||||||
pp_hash.clone(),
|
&pp_hash,
|
||||||
i + FpVar::<CF1<C1>>::one(),
|
&(i + FpVar::<CF1<C1>>::one()),
|
||||||
z_0.clone(),
|
&z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
)?;
|
)?;
|
||||||
let (u_i1_x_base, _) = LCCCSVar::new_constant(cs.clone(), U_dummy)?.hash(
|
let (u_i1_x_base, _) = LCCCSVar::new_constant(cs.clone(), U_dummy)?.hash(
|
||||||
&sponge,
|
&sponge,
|
||||||
pp_hash.clone(),
|
&pp_hash,
|
||||||
FpVar::<CF1<C1>>::one(),
|
&FpVar::<CF1<C1>>::one(),
|
||||||
z_0.clone(),
|
&z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
)?;
|
)?;
|
||||||
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
|
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
|
||||||
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
|
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
|
||||||
@@ -900,6 +915,7 @@ mod tests {
|
|||||||
utils::{compute_c, compute_sigmas_thetas},
|
utils::{compute_c, compute_sigmas_thetas},
|
||||||
HyperNovaCycleFoldCircuit,
|
HyperNovaCycleFoldCircuit,
|
||||||
},
|
},
|
||||||
|
traits::CommittedInstanceOps,
|
||||||
},
|
},
|
||||||
frontend::utils::CubicFCircuit,
|
frontend::utils::CubicFCircuit,
|
||||||
transcript::poseidon::poseidon_canonical_config,
|
transcript::poseidon::poseidon_canonical_config,
|
||||||
@@ -1113,6 +1129,37 @@ mod tests {
|
|||||||
assert_eq!(folded_lcccsVar.u.value().unwrap(), folded_lcccs.u);
|
assert_eq!(folded_lcccsVar.u.value().unwrap(), folded_lcccs.u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// test that checks the native LCCCS.to_sponge_{bytes,field_elements} vs
|
||||||
|
/// the R1CS constraints version
|
||||||
|
#[test]
|
||||||
|
pub fn test_lcccs_to_sponge_preimage() {
|
||||||
|
let mut rng = test_rng();
|
||||||
|
|
||||||
|
let ccs = get_test_ccs();
|
||||||
|
let z1 = get_test_z::<Fr>(3);
|
||||||
|
|
||||||
|
let (pedersen_params, _) =
|
||||||
|
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||||
|
|
||||||
|
let (lcccs, _) = ccs
|
||||||
|
.to_lcccs::<_, _, Pedersen<Projective, true>, true>(&mut rng, &pedersen_params, &z1)
|
||||||
|
.unwrap();
|
||||||
|
let bytes = lcccs.to_sponge_bytes_as_vec();
|
||||||
|
let field_elements = lcccs.to_sponge_field_elements_as_vec();
|
||||||
|
|
||||||
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
|
let lcccsVar = LCCCSVar::<Projective>::new_witness(cs.clone(), || Ok(lcccs)).unwrap();
|
||||||
|
let bytes_var = lcccsVar.to_sponge_bytes().unwrap();
|
||||||
|
let field_elements_var = lcccsVar.to_sponge_field_elements().unwrap();
|
||||||
|
|
||||||
|
assert!(cs.is_satisfied().unwrap());
|
||||||
|
|
||||||
|
// check that the natively computed and in-circuit computed hashes match
|
||||||
|
assert_eq!(bytes_var.value().unwrap(), bytes);
|
||||||
|
assert_eq!(field_elements_var.value().unwrap(), field_elements);
|
||||||
|
}
|
||||||
|
|
||||||
/// test that checks the native LCCCS.hash vs the R1CS constraints version
|
/// test that checks the native LCCCS.hash vs the R1CS constraints version
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_lcccs_hash() {
|
pub fn test_lcccs_hash() {
|
||||||
@@ -1133,9 +1180,7 @@ mod tests {
|
|||||||
let (lcccs, _) = ccs
|
let (lcccs, _) = ccs
|
||||||
.to_lcccs::<_, _, Pedersen<Projective, true>, true>(&mut rng, &pedersen_params, &z1)
|
.to_lcccs::<_, _, Pedersen<Projective, true>, true>(&mut rng, &pedersen_params, &z1)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let h = lcccs
|
let h = lcccs.clone().hash(&sponge, pp_hash, i, &z_0, &z_i);
|
||||||
.clone()
|
|
||||||
.hash(&sponge, pp_hash, i, z_0.clone(), z_i.clone());
|
|
||||||
|
|
||||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
@@ -1147,13 +1192,7 @@ mod tests {
|
|||||||
let lcccsVar = LCCCSVar::<Projective>::new_witness(cs.clone(), || Ok(lcccs)).unwrap();
|
let lcccsVar = LCCCSVar::<Projective>::new_witness(cs.clone(), || Ok(lcccs)).unwrap();
|
||||||
let (hVar, _) = lcccsVar
|
let (hVar, _) = lcccsVar
|
||||||
.clone()
|
.clone()
|
||||||
.hash(
|
.hash(&spongeVar, &pp_hashVar, &iVar, &z_0Var, &z_iVar)
|
||||||
&spongeVar,
|
|
||||||
pp_hashVar,
|
|
||||||
iVar.clone(),
|
|
||||||
z_0Var.clone(),
|
|
||||||
z_iVar.clone(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(cs.is_satisfied().unwrap());
|
assert!(cs.is_satisfied().unwrap());
|
||||||
|
|
||||||
@@ -1225,7 +1264,7 @@ mod tests {
|
|||||||
let mut cf_W_i = cf_W_dummy.clone();
|
let mut cf_W_i = cf_W_dummy.clone();
|
||||||
let mut cf_U_i = cf_U_dummy.clone();
|
let mut cf_U_i = cf_U_dummy.clone();
|
||||||
u_i.x = vec![
|
u_i.x = vec![
|
||||||
U_i.hash(&sponge, pp_hash, Fr::zero(), z_0.clone(), z_i.clone()),
|
U_i.hash(&sponge, pp_hash, Fr::zero(), &z_0, &z_i),
|
||||||
cf_U_i.hash_cyclefold(&sponge, pp_hash),
|
cf_U_i.hash_cyclefold(&sponge, pp_hash),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -1252,7 +1291,7 @@ mod tests {
|
|||||||
W_i1 = Witness::<Fr>::dummy(&ccs);
|
W_i1 = Witness::<Fr>::dummy(&ccs);
|
||||||
U_i1 = LCCCS::dummy(ccs.l, ccs.t, ccs.s);
|
U_i1 = LCCCS::dummy(ccs.l, ccs.t, ccs.s);
|
||||||
|
|
||||||
let u_i1_x = U_i1.hash(&sponge, pp_hash, Fr::one(), z_0.clone(), z_i1.clone());
|
let u_i1_x = U_i1.hash(&sponge, pp_hash, Fr::one(), &z_0, &z_i1);
|
||||||
|
|
||||||
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
||||||
// input in the AugmentedFCircuit
|
// input in the AugmentedFCircuit
|
||||||
@@ -1309,8 +1348,7 @@ mod tests {
|
|||||||
// sanity check: check the folded instance relation
|
// sanity check: check the folded instance relation
|
||||||
U_i1.check_relation(&ccs, &W_i1).unwrap();
|
U_i1.check_relation(&ccs, &W_i1).unwrap();
|
||||||
|
|
||||||
let u_i1_x =
|
let u_i1_x = U_i1.hash(&sponge, pp_hash, iFr + Fr::one(), &z_0, &z_i1);
|
||||||
U_i1.hash(&sponge, pp_hash, iFr + Fr::one(), z_0.clone(), z_i1.clone());
|
|
||||||
|
|
||||||
let rho_bits = rho.into_bigint().to_bits_le()[..NOVA_N_BITS_RO].to_vec();
|
let rho_bits = rho.into_bigint().to_bits_le()[..NOVA_N_BITS_RO].to_vec();
|
||||||
let rho_Fq = Fq::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();
|
let rho_Fq = Fq::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();
|
||||||
@@ -1434,8 +1472,7 @@ mod tests {
|
|||||||
assert_eq!(u_i.x, r1cs_x_i1);
|
assert_eq!(u_i.x, r1cs_x_i1);
|
||||||
assert_eq!(u_i.x[0], augmented_f_circuit.x.unwrap());
|
assert_eq!(u_i.x[0], augmented_f_circuit.x.unwrap());
|
||||||
assert_eq!(u_i.x[1], augmented_f_circuit.cf_x.unwrap());
|
assert_eq!(u_i.x[1], augmented_f_circuit.cf_x.unwrap());
|
||||||
let expected_u_i1_x =
|
let expected_u_i1_x = U_i1.hash(&sponge, pp_hash, iFr + Fr::one(), &z_0, &z_i1);
|
||||||
U_i1.hash(&sponge, pp_hash, iFr + Fr::one(), z_0.clone(), z_i1.clone());
|
|
||||||
let expected_cf_U_i1_x = cf_U_i.hash_cyclefold(&sponge, pp_hash);
|
let expected_cf_U_i1_x = cf_U_i.hash_cyclefold(&sponge, pp_hash);
|
||||||
// u_i is already u_i1 at this point, check that has the expected value at x[0]
|
// u_i is already u_i1 at this point, check that has the expected value at x[0]
|
||||||
assert_eq!(u_i.x[0], expected_u_i1_x);
|
assert_eq!(u_i.x[0], expected_u_i1_x);
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ use super::{
|
|||||||
nimfs::{NIMFSProof, NIMFS},
|
nimfs::{NIMFSProof, NIMFS},
|
||||||
HyperNova, Witness, CCCS, LCCCS,
|
HyperNova, Witness, CCCS, LCCCS,
|
||||||
};
|
};
|
||||||
use crate::arith::ccs::CCS;
|
|
||||||
use crate::arith::r1cs::R1CS;
|
|
||||||
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
|
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
|
||||||
use crate::folding::circuits::{
|
use crate::folding::circuits::{
|
||||||
cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness},
|
cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness},
|
||||||
@@ -40,6 +38,8 @@ use crate::utils::{
|
|||||||
vec::poly_from_vec,
|
vec::poly_from_vec,
|
||||||
};
|
};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
use crate::{arith::ccs::CCS, folding::traits::CommittedInstanceVarOps};
|
||||||
|
use crate::{arith::r1cs::R1CS, folding::traits::WitnessVarOps};
|
||||||
|
|
||||||
/// In-circuit representation of the Witness associated to the CommittedInstance.
|
/// In-circuit representation of the Witness associated to the CommittedInstance.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -66,6 +66,12 @@ impl<F: PrimeField> AllocVar<Witness<F>, F> for WitnessVar<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F: PrimeField> WitnessVarOps<F> for WitnessVar<F> {
|
||||||
|
fn get_openings(&self) -> Vec<(&[FpVar<F>], FpVar<F>)> {
|
||||||
|
vec![(&self.w, self.r_w.clone())]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// CCSMatricesVar contains the matrices 'M' of the CCS without the rest of CCS parameters.
|
/// CCSMatricesVar contains the matrices 'M' of the CCS without the rest of CCS parameters.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CCSMatricesVar<F: PrimeField> {
|
pub struct CCSMatricesVar<F: PrimeField> {
|
||||||
@@ -340,13 +346,7 @@ where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// 3.a u_i.x[0] == H(i, z_0, z_i, U_i)
|
// 3.a u_i.x[0] == H(i, z_0, z_i, U_i)
|
||||||
let (u_i_x, _) = U_i.clone().hash(
|
let (u_i_x, _) = U_i.clone().hash(&sponge, &pp_hash, &i, &z_0, &z_i)?;
|
||||||
&sponge,
|
|
||||||
pp_hash.clone(),
|
|
||||||
i.clone(),
|
|
||||||
z_0.clone(),
|
|
||||||
z_i.clone(),
|
|
||||||
)?;
|
|
||||||
(u_i.x[0]).enforce_equal(&u_i_x)?;
|
(u_i.x[0]).enforce_equal(&u_i_x)?;
|
||||||
|
|
||||||
#[cfg(feature = "light-test")]
|
#[cfg(feature = "light-test")]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use ark_crypto_primitives::sponge::Absorb;
|
use ark_crypto_primitives::sponge::Absorb;
|
||||||
use ark_ec::{CurveGroup, Group};
|
use ark_ec::CurveGroup;
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use ark_poly::DenseMultilinearExtension;
|
use ark_poly::DenseMultilinearExtension;
|
||||||
use ark_poly::MultilinearExtension;
|
use ark_poly::MultilinearExtension;
|
||||||
@@ -8,10 +8,12 @@ use ark_serialize::CanonicalSerialize;
|
|||||||
use ark_std::rand::Rng;
|
use ark_std::rand::Rng;
|
||||||
use ark_std::Zero;
|
use ark_std::Zero;
|
||||||
|
|
||||||
|
use super::circuits::LCCCSVar;
|
||||||
use super::Witness;
|
use super::Witness;
|
||||||
use crate::arith::ccs::CCS;
|
use crate::arith::ccs::CCS;
|
||||||
use crate::commitment::CommitmentScheme;
|
use crate::commitment::CommitmentScheme;
|
||||||
use crate::transcript::{AbsorbNonNative, Transcript};
|
use crate::folding::traits::CommittedInstanceOps;
|
||||||
|
use crate::transcript::AbsorbNonNative;
|
||||||
use crate::utils::mle::dense_vec_to_dense_mle;
|
use crate::utils::mle::dense_vec_to_dense_mle;
|
||||||
use crate::utils::vec::mat_vec_mul;
|
use crate::utils::vec::mat_vec_mul;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
@@ -121,9 +123,8 @@ impl<C: CurveGroup> Absorb for LCCCS<C>
|
|||||||
where
|
where
|
||||||
C::ScalarField: Absorb,
|
C::ScalarField: Absorb,
|
||||||
{
|
{
|
||||||
fn to_sponge_bytes(&self, _dest: &mut Vec<u8>) {
|
fn to_sponge_bytes(&self, dest: &mut Vec<u8>) {
|
||||||
// This is never called
|
C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest);
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
|
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
|
||||||
@@ -140,29 +141,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CurveGroup> LCCCS<C>
|
impl<C: CurveGroup> CommittedInstanceOps<C> for LCCCS<C> {
|
||||||
where
|
type Var = LCCCSVar<C>;
|
||||||
<C as Group>::ScalarField: Absorb,
|
|
||||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
fn get_commitments(&self) -> Vec<C> {
|
||||||
{
|
vec![self.C]
|
||||||
/// [`LCCCS`].hash implements the committed instance hash compatible with the gadget
|
}
|
||||||
/// implemented in nova/circuits.rs::CommittedInstanceVar.hash.
|
|
||||||
/// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and `U_i` is the LCCCS.
|
fn is_incoming(&self) -> bool {
|
||||||
pub fn hash<T: Transcript<C::ScalarField>>(
|
false
|
||||||
&self,
|
|
||||||
sponge: &T,
|
|
||||||
pp_hash: C::ScalarField,
|
|
||||||
i: C::ScalarField,
|
|
||||||
z_0: Vec<C::ScalarField>,
|
|
||||||
z_i: Vec<C::ScalarField>,
|
|
||||||
) -> C::ScalarField {
|
|
||||||
let mut sponge = sponge.clone();
|
|
||||||
sponge.absorb(&pp_hash);
|
|
||||||
sponge.absorb(&i);
|
|
||||||
sponge.absorb(&z_0);
|
|
||||||
sponge.absorb(&z_i);
|
|
||||||
sponge.absorb(&self);
|
|
||||||
sponge.squeeze_field_elements(1)[0]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ pub mod utils;
|
|||||||
|
|
||||||
use cccs::CCCS;
|
use cccs::CCCS;
|
||||||
use circuits::AugmentedFCircuit;
|
use circuits::AugmentedFCircuit;
|
||||||
|
use decider_eth_circuit::WitnessVar;
|
||||||
use lcccs::LCCCS;
|
use lcccs::LCCCS;
|
||||||
use nimfs::NIMFS;
|
use nimfs::NIMFS;
|
||||||
|
|
||||||
@@ -32,6 +33,7 @@ use crate::folding::circuits::{
|
|||||||
CF2,
|
CF2,
|
||||||
};
|
};
|
||||||
use crate::folding::nova::{get_r1cs_from_cs, PreprocessorParam};
|
use crate::folding::nova::{get_r1cs_from_cs, PreprocessorParam};
|
||||||
|
use crate::folding::traits::{CommittedInstanceOps, WitnessOps};
|
||||||
use crate::frontend::FCircuit;
|
use crate::frontend::FCircuit;
|
||||||
use crate::utils::{get_cm_coordinates, pp_hash};
|
use crate::utils::{get_cm_coordinates, pp_hash};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
@@ -81,6 +83,14 @@ impl<F: PrimeField> Witness<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F: PrimeField> WitnessOps<F> for Witness<F> {
|
||||||
|
type Var = WitnessVar<F>;
|
||||||
|
|
||||||
|
fn get_openings(&self) -> Vec<(&[F], F)> {
|
||||||
|
vec![(&self.w, self.r_w)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Proving parameters for HyperNova-based IVC
|
/// Proving parameters for HyperNova-based IVC
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProverParams<C1, C2, CS1, CS2, const H: bool>
|
pub struct ProverParams<C1, C2, CS1, CS2, const H: bool>
|
||||||
@@ -307,8 +317,8 @@ where
|
|||||||
&sponge,
|
&sponge,
|
||||||
self.pp_hash,
|
self.pp_hash,
|
||||||
C1::ScalarField::zero(), // i
|
C1::ScalarField::zero(), // i
|
||||||
self.z_0.clone(),
|
&self.z_0,
|
||||||
state.clone(),
|
&state,
|
||||||
),
|
),
|
||||||
cf_U_i.hash_cyclefold(&sponge, self.pp_hash),
|
cf_U_i.hash_cyclefold(&sponge, self.pp_hash),
|
||||||
];
|
];
|
||||||
@@ -324,8 +334,8 @@ where
|
|||||||
&sponge,
|
&sponge,
|
||||||
self.pp_hash,
|
self.pp_hash,
|
||||||
C1::ScalarField::one(), // i+1, where i=0
|
C1::ScalarField::one(), // i+1, where i=0
|
||||||
self.z_0.clone(),
|
&self.z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
);
|
);
|
||||||
|
|
||||||
let cf_u_i1_x = cf_U_i.hash_cyclefold(&sponge, self.pp_hash);
|
let cf_u_i1_x = cf_U_i.hash_cyclefold(&sponge, self.pp_hash);
|
||||||
@@ -494,13 +504,7 @@ where
|
|||||||
let (cf_W_dummy, cf_U_dummy): (CycleFoldWitness<C2>, CycleFoldCommittedInstance<C2>) =
|
let (cf_W_dummy, cf_U_dummy): (CycleFoldWitness<C2>, CycleFoldCommittedInstance<C2>) =
|
||||||
cf_r1cs.dummy_running_instance();
|
cf_r1cs.dummy_running_instance();
|
||||||
u_dummy.x = vec![
|
u_dummy.x = vec![
|
||||||
U_dummy.hash(
|
U_dummy.hash(&sponge, pp_hash, C1::ScalarField::zero(), &z_0, &z_0),
|
||||||
&sponge,
|
|
||||||
pp_hash,
|
|
||||||
C1::ScalarField::zero(),
|
|
||||||
z_0.clone(),
|
|
||||||
z_0.clone(),
|
|
||||||
),
|
|
||||||
cf_U_dummy.hash_cyclefold(&sponge, pp_hash),
|
cf_U_dummy.hash_cyclefold(&sponge, pp_hash),
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -643,8 +647,8 @@ where
|
|||||||
&sponge,
|
&sponge,
|
||||||
self.pp_hash,
|
self.pp_hash,
|
||||||
C1::ScalarField::one(),
|
C1::ScalarField::one(),
|
||||||
self.z_0.clone(),
|
&self.z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
);
|
);
|
||||||
|
|
||||||
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
||||||
@@ -699,8 +703,8 @@ where
|
|||||||
&sponge,
|
&sponge,
|
||||||
self.pp_hash,
|
self.pp_hash,
|
||||||
self.i + C1::ScalarField::one(),
|
self.i + C1::ScalarField::one(),
|
||||||
self.z_0.clone(),
|
&self.z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
);
|
);
|
||||||
|
|
||||||
let rho_bits = rho.into_bigint().to_bits_le()[..NOVA_N_BITS_RO].to_vec();
|
let rho_bits = rho.into_bigint().to_bits_le()[..NOVA_N_BITS_RO].to_vec();
|
||||||
@@ -884,7 +888,7 @@ where
|
|||||||
|
|
||||||
// check that u_i's output points to the running instance
|
// check that u_i's output points to the running instance
|
||||||
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
||||||
let expected_u_i_x = U_i.hash(&sponge, 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);
|
||||||
if expected_u_i_x != u_i.x[0] {
|
if expected_u_i_x != u_i.x[0] {
|
||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,3 +2,4 @@ pub mod circuits;
|
|||||||
pub mod hypernova;
|
pub mod hypernova;
|
||||||
pub mod nova;
|
pub mod nova;
|
||||||
pub mod protogalaxy;
|
pub mod protogalaxy;
|
||||||
|
pub mod traits;
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ use ark_std::{fmt::Debug, One, Zero};
|
|||||||
use core::{borrow::Borrow, marker::PhantomData};
|
use core::{borrow::Borrow, marker::PhantomData};
|
||||||
|
|
||||||
use super::{CommittedInstance, NovaCycleFoldConfig};
|
use super::{CommittedInstance, NovaCycleFoldConfig};
|
||||||
use crate::constants::NOVA_N_BITS_RO;
|
|
||||||
use crate::folding::circuits::{
|
use crate::folding::circuits::{
|
||||||
cyclefold::{
|
cyclefold::{
|
||||||
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
|
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
|
||||||
@@ -32,15 +31,13 @@ use crate::folding::circuits::{
|
|||||||
};
|
};
|
||||||
use crate::frontend::FCircuit;
|
use crate::frontend::FCircuit;
|
||||||
use crate::transcript::{AbsorbNonNativeGadget, Transcript, TranscriptVar};
|
use crate::transcript::{AbsorbNonNativeGadget, Transcript, TranscriptVar};
|
||||||
|
use crate::{constants::NOVA_N_BITS_RO, folding::traits::CommittedInstanceVarOps};
|
||||||
|
|
||||||
/// CommittedInstanceVar contains the u, x, cmE and cmW values which are folded on the main Nova
|
/// CommittedInstanceVar contains the u, x, cmE and cmW values which are folded on the main Nova
|
||||||
/// constraints field (E1::Fr, where E1 is the main curve). The peculiarity is that cmE and cmW are
|
/// constraints field (E1::Fr, where E1 is the main curve). The peculiarity is that cmE and cmW are
|
||||||
/// represented non-natively over the constraint field.
|
/// represented non-natively over the constraint field.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct CommittedInstanceVar<C: CurveGroup>
|
pub struct CommittedInstanceVar<C: CurveGroup> {
|
||||||
where
|
|
||||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
|
||||||
{
|
|
||||||
pub u: FpVar<C::ScalarField>,
|
pub u: FpVar<C::ScalarField>,
|
||||||
pub x: Vec<FpVar<C::ScalarField>>,
|
pub x: Vec<FpVar<C::ScalarField>>,
|
||||||
pub cmE: NonNativeAffineVar<C>,
|
pub cmE: NonNativeAffineVar<C>,
|
||||||
@@ -50,7 +47,6 @@ where
|
|||||||
impl<C> AllocVar<CommittedInstance<C>, CF1<C>> for CommittedInstanceVar<C>
|
impl<C> AllocVar<CommittedInstance<C>, CF1<C>> for CommittedInstanceVar<C>
|
||||||
where
|
where
|
||||||
C: CurveGroup,
|
C: CurveGroup,
|
||||||
<C as ark_ec::CurveGroup>::BaseField: PrimeField,
|
|
||||||
{
|
{
|
||||||
fn new_variable<T: Borrow<CommittedInstance<C>>>(
|
fn new_variable<T: Borrow<CommittedInstance<C>>>(
|
||||||
cs: impl Into<Namespace<CF1<C>>>,
|
cs: impl Into<Namespace<CF1<C>>>,
|
||||||
@@ -80,7 +76,7 @@ where
|
|||||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
||||||
{
|
{
|
||||||
fn to_sponge_bytes(&self) -> Result<Vec<UInt8<C::ScalarField>>, SynthesisError> {
|
fn to_sponge_bytes(&self) -> Result<Vec<UInt8<C::ScalarField>>, SynthesisError> {
|
||||||
unimplemented!()
|
FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
|
fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
|
||||||
@@ -94,35 +90,27 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C> CommittedInstanceVar<C>
|
impl<C: CurveGroup> CommittedInstanceVarOps<C> for CommittedInstanceVar<C> {
|
||||||
where
|
type PointVar = NonNativeAffineVar<C>;
|
||||||
C: CurveGroup,
|
|
||||||
<C as Group>::ScalarField: Absorb,
|
fn get_commitments(&self) -> Vec<Self::PointVar> {
|
||||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
vec![self.cmW.clone(), self.cmE.clone()]
|
||||||
{
|
}
|
||||||
/// hash implements the committed instance hash compatible with the native implementation from
|
|
||||||
/// CommittedInstance.hash.
|
fn get_public_inputs(&self) -> &[FpVar<CF1<C>>] {
|
||||||
/// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and `U` is the
|
&self.x
|
||||||
/// `CommittedInstance`.
|
}
|
||||||
/// Additionally it returns the vector of the field elements from the self parameters, so they
|
|
||||||
/// can be reused in other gadgets avoiding recalculating (reconstraining) them.
|
fn enforce_incoming(&self) -> Result<(), SynthesisError> {
|
||||||
#[allow(clippy::type_complexity)]
|
let zero = NonNativeUintVar::new_constant(ConstraintSystemRef::None, CF2::<C>::zero())?;
|
||||||
pub fn hash<S: CryptographicSponge, T: TranscriptVar<CF1<C>, S>>(
|
self.cmE.x.enforce_equal_unaligned(&zero)?;
|
||||||
self,
|
self.cmE.y.enforce_equal_unaligned(&zero)?;
|
||||||
sponge: &T,
|
self.u.enforce_equal(&FpVar::one())
|
||||||
pp_hash: FpVar<CF1<C>>,
|
}
|
||||||
i: FpVar<CF1<C>>,
|
|
||||||
z_0: Vec<FpVar<CF1<C>>>,
|
fn enforce_partial_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
||||||
z_i: Vec<FpVar<CF1<C>>>,
|
self.u.enforce_equal(&other.u)?;
|
||||||
) -> Result<(FpVar<CF1<C>>, Vec<FpVar<CF1<C>>>), SynthesisError> {
|
self.x.enforce_equal(&other.x)
|
||||||
let mut sponge = sponge.clone();
|
|
||||||
let U_vec = self.to_sponge_field_elements()?;
|
|
||||||
sponge.absorb(&pp_hash)?;
|
|
||||||
sponge.absorb(&i)?;
|
|
||||||
sponge.absorb(&z_0)?;
|
|
||||||
sponge.absorb(&z_i)?;
|
|
||||||
sponge.absorb(&U_vec)?;
|
|
||||||
Ok((sponge.squeeze_field_elements(1)?.pop().unwrap(), U_vec))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,24 +347,12 @@ where
|
|||||||
// `transcript` is for challenge generation.
|
// `transcript` is for challenge generation.
|
||||||
let mut transcript = sponge.clone();
|
let mut transcript = sponge.clone();
|
||||||
|
|
||||||
// get z_{i+1} from the F circuit
|
|
||||||
let i_usize = self.i_usize.unwrap_or(0);
|
|
||||||
let z_i1 =
|
|
||||||
self.F
|
|
||||||
.generate_step_constraints(cs.clone(), i_usize, z_i.clone(), external_inputs)?;
|
|
||||||
|
|
||||||
let is_basecase = i.is_zero()?;
|
let is_basecase = i.is_zero()?;
|
||||||
|
|
||||||
// Primary Part
|
// Primary Part
|
||||||
// P.1. Compute u_i.x
|
// P.1. Compute u_i.x
|
||||||
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
||||||
let (u_i_x, U_i_vec) = U_i.clone().hash(
|
let (u_i_x, U_i_vec) = U_i.clone().hash(&sponge, &pp_hash, &i, &z_0, &z_i)?;
|
||||||
&sponge,
|
|
||||||
pp_hash.clone(),
|
|
||||||
i.clone(),
|
|
||||||
z_0.clone(),
|
|
||||||
z_i.clone(),
|
|
||||||
)?;
|
|
||||||
// u_i.x[1] = H(cf_U_i)
|
// u_i.x[1] = H(cf_U_i)
|
||||||
let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&sponge, pp_hash.clone())?;
|
let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&sponge, pp_hash.clone())?;
|
||||||
|
|
||||||
@@ -421,21 +397,28 @@ where
|
|||||||
U_i1.cmW = U_i1_cmW;
|
U_i1.cmW = U_i1_cmW;
|
||||||
|
|
||||||
// P.4.a compute and check the first output of F'
|
// P.4.a compute and check the first output of F'
|
||||||
|
|
||||||
|
// get z_{i+1} from the F circuit
|
||||||
|
let i_usize = self.i_usize.unwrap_or(0);
|
||||||
|
let z_i1 = self
|
||||||
|
.F
|
||||||
|
.generate_step_constraints(cs.clone(), i_usize, z_i, external_inputs)?;
|
||||||
|
|
||||||
// Base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{\bot})
|
// Base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{\bot})
|
||||||
// Non-base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{i+1})
|
// Non-base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{i+1})
|
||||||
let (u_i1_x, _) = U_i1.clone().hash(
|
let (u_i1_x, _) = U_i1.clone().hash(
|
||||||
&sponge,
|
&sponge,
|
||||||
pp_hash.clone(),
|
&pp_hash,
|
||||||
i + FpVar::<CF1<C1>>::one(),
|
&(i + FpVar::<CF1<C1>>::one()),
|
||||||
z_0.clone(),
|
&z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
)?;
|
)?;
|
||||||
let (u_i1_x_base, _) = CommittedInstanceVar::new_constant(cs.clone(), u_dummy)?.hash(
|
let (u_i1_x_base, _) = CommittedInstanceVar::new_constant(cs.clone(), u_dummy)?.hash(
|
||||||
&sponge,
|
&sponge,
|
||||||
pp_hash.clone(),
|
&pp_hash,
|
||||||
FpVar::<CF1<C1>>::one(),
|
&FpVar::<CF1<C1>>::one(),
|
||||||
z_0.clone(),
|
&z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
)?;
|
)?;
|
||||||
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
|
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
|
||||||
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
|
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
|
||||||
@@ -538,6 +521,7 @@ pub mod tests {
|
|||||||
use crate::commitment::pedersen::Pedersen;
|
use crate::commitment::pedersen::Pedersen;
|
||||||
use crate::folding::nova::nifs::tests::prepare_simple_fold_inputs;
|
use crate::folding::nova::nifs::tests::prepare_simple_fold_inputs;
|
||||||
use crate::folding::nova::nifs::NIFS;
|
use crate::folding::nova::nifs::NIFS;
|
||||||
|
use crate::folding::traits::CommittedInstanceOps;
|
||||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -591,6 +575,36 @@ pub mod tests {
|
|||||||
assert!(cs.is_satisfied().unwrap());
|
assert!(cs.is_satisfied().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// test that checks the native CommittedInstance.to_sponge_{bytes,field_elements}
|
||||||
|
/// vs the R1CS constraints version
|
||||||
|
#[test]
|
||||||
|
pub fn test_committed_instance_to_sponge_preimage() {
|
||||||
|
let mut rng = ark_std::test_rng();
|
||||||
|
|
||||||
|
let ci = CommittedInstance::<Projective> {
|
||||||
|
cmE: Projective::rand(&mut rng),
|
||||||
|
u: Fr::rand(&mut rng),
|
||||||
|
cmW: Projective::rand(&mut rng),
|
||||||
|
x: vec![Fr::rand(&mut rng); 1],
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytes = ci.to_sponge_bytes_as_vec();
|
||||||
|
let field_elements = ci.to_sponge_field_elements_as_vec();
|
||||||
|
|
||||||
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
|
let ciVar =
|
||||||
|
CommittedInstanceVar::<Projective>::new_witness(cs.clone(), || Ok(ci.clone())).unwrap();
|
||||||
|
let bytes_var = ciVar.to_sponge_bytes().unwrap();
|
||||||
|
let field_elements_var = ciVar.to_sponge_field_elements().unwrap();
|
||||||
|
|
||||||
|
assert!(cs.is_satisfied().unwrap());
|
||||||
|
|
||||||
|
// check that the natively computed and in-circuit computed hashes match
|
||||||
|
assert_eq!(bytes_var.value().unwrap(), bytes);
|
||||||
|
assert_eq!(field_elements_var.value().unwrap(), field_elements);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_committed_instance_hash() {
|
fn test_committed_instance_hash() {
|
||||||
let mut rng = ark_std::test_rng();
|
let mut rng = ark_std::test_rng();
|
||||||
@@ -609,7 +623,7 @@ pub mod tests {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// compute the CommittedInstance hash natively
|
// compute the CommittedInstance hash natively
|
||||||
let h = ci.hash(&sponge, pp_hash, i, z_0.clone(), z_i.clone());
|
let h = ci.hash(&sponge, pp_hash, i, &z_0, &z_i);
|
||||||
|
|
||||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
@@ -624,7 +638,7 @@ pub mod tests {
|
|||||||
|
|
||||||
// compute the CommittedInstance hash in-circuit
|
// compute the CommittedInstance hash in-circuit
|
||||||
let (hVar, _) = ciVar
|
let (hVar, _) = ciVar
|
||||||
.hash(&sponge, pp_hashVar, iVar, z_0Var, z_iVar)
|
.hash(&sponge, &pp_hashVar, &iVar, &z_0Var, &z_iVar)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(cs.is_satisfied().unwrap());
|
assert!(cs.is_satisfied().unwrap());
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ use super::{
|
|||||||
nifs::NIFS,
|
nifs::NIFS,
|
||||||
CommittedInstance, Nova, Witness,
|
CommittedInstance, Nova, Witness,
|
||||||
};
|
};
|
||||||
use crate::arith::r1cs::R1CS;
|
|
||||||
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
|
|
||||||
use crate::folding::circuits::{
|
use crate::folding::circuits::{
|
||||||
cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness},
|
cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness},
|
||||||
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
|
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
|
||||||
@@ -41,6 +39,11 @@ use crate::utils::{
|
|||||||
vec::poly_from_vec,
|
vec::poly_from_vec,
|
||||||
};
|
};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
use crate::{arith::r1cs::R1CS, folding::traits::WitnessVarOps};
|
||||||
|
use crate::{
|
||||||
|
commitment::{pedersen::Params as PedersenParams, CommitmentScheme},
|
||||||
|
folding::traits::CommittedInstanceVarOps,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RelaxedR1CSGadget {}
|
pub struct RelaxedR1CSGadget {}
|
||||||
@@ -135,7 +138,6 @@ pub struct WitnessVar<C: CurveGroup> {
|
|||||||
impl<C> AllocVar<Witness<C>, CF1<C>> for WitnessVar<C>
|
impl<C> AllocVar<Witness<C>, CF1<C>> for WitnessVar<C>
|
||||||
where
|
where
|
||||||
C: CurveGroup,
|
C: CurveGroup,
|
||||||
<C as ark_ec::CurveGroup>::BaseField: PrimeField,
|
|
||||||
{
|
{
|
||||||
fn new_variable<T: Borrow<Witness<C>>>(
|
fn new_variable<T: Borrow<Witness<C>>>(
|
||||||
cs: impl Into<Namespace<CF1<C>>>,
|
cs: impl Into<Namespace<CF1<C>>>,
|
||||||
@@ -160,6 +162,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C: CurveGroup> WitnessVarOps<C::ScalarField> for WitnessVar<C> {
|
||||||
|
fn get_openings(&self) -> Vec<(&[FpVar<C::ScalarField>], FpVar<C::ScalarField>)> {
|
||||||
|
vec![(&self.E, self.rE.clone()), (&self.W, self.rW.clone())]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Circuit that implements the in-circuit checks needed for the onchain (Ethereum's EVM)
|
/// Circuit that implements the in-circuit checks needed for the onchain (Ethereum's EVM)
|
||||||
/// verification.
|
/// verification.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -398,13 +406,7 @@ where
|
|||||||
(u_i.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
|
(u_i.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
|
||||||
|
|
||||||
// 3.a u_i.x[0] == H(i, z_0, z_i, U_i)
|
// 3.a u_i.x[0] == H(i, z_0, z_i, U_i)
|
||||||
let (u_i_x, U_i_vec) = U_i.clone().hash(
|
let (u_i_x, U_i_vec) = U_i.clone().hash(&sponge, &pp_hash, &i, &z_0, &z_i)?;
|
||||||
&sponge,
|
|
||||||
pp_hash.clone(),
|
|
||||||
i.clone(),
|
|
||||||
z_0.clone(),
|
|
||||||
z_i.clone(),
|
|
||||||
)?;
|
|
||||||
(u_i.x[0]).enforce_equal(&u_i_x)?;
|
(u_i.x[0]).enforce_equal(&u_i_x)?;
|
||||||
|
|
||||||
#[cfg(feature = "light-test")]
|
#[cfg(feature = "light-test")]
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ use ark_std::fmt::Debug;
|
|||||||
use ark_std::rand::RngCore;
|
use ark_std::rand::RngCore;
|
||||||
use ark_std::{One, UniformRand, Zero};
|
use ark_std::{One, UniformRand, Zero};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
use decider_eth_circuit::WitnessVar;
|
||||||
|
|
||||||
use crate::folding::circuits::cyclefold::{
|
use crate::folding::circuits::cyclefold::{
|
||||||
fold_cyclefold_circuit, CycleFoldCircuit, CycleFoldCommittedInstance, CycleFoldConfig,
|
fold_cyclefold_circuit, CycleFoldCircuit, CycleFoldCommittedInstance, CycleFoldConfig,
|
||||||
@@ -38,9 +39,11 @@ pub mod nifs;
|
|||||||
pub mod serialize;
|
pub mod serialize;
|
||||||
pub mod traits;
|
pub mod traits;
|
||||||
pub mod zk;
|
pub mod zk;
|
||||||
use circuits::{AugmentedFCircuit, ChallengeGadget};
|
use circuits::{AugmentedFCircuit, ChallengeGadget, CommittedInstanceVar};
|
||||||
use nifs::NIFS;
|
use nifs::NIFS;
|
||||||
|
|
||||||
|
use super::traits::{CommittedInstanceOps, WitnessOps};
|
||||||
|
|
||||||
/// Configuration for Nova's CycleFold circuit
|
/// Configuration for Nova's CycleFold circuit
|
||||||
pub struct NovaCycleFoldConfig<C: CurveGroup> {
|
pub struct NovaCycleFoldConfig<C: CurveGroup> {
|
||||||
_c: PhantomData<C>,
|
_c: PhantomData<C>,
|
||||||
@@ -83,9 +86,8 @@ impl<C: CurveGroup> Absorb for CommittedInstance<C>
|
|||||||
where
|
where
|
||||||
C::ScalarField: Absorb,
|
C::ScalarField: Absorb,
|
||||||
{
|
{
|
||||||
fn to_sponge_bytes(&self, _dest: &mut Vec<u8>) {
|
fn to_sponge_bytes(&self, dest: &mut Vec<u8>) {
|
||||||
// This is never called
|
C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest);
|
||||||
unimplemented!()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
|
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
|
||||||
@@ -103,30 +105,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CurveGroup> CommittedInstance<C>
|
impl<C: CurveGroup> CommittedInstanceOps<C> for CommittedInstance<C> {
|
||||||
where
|
type Var = CommittedInstanceVar<C>;
|
||||||
<C as Group>::ScalarField: Absorb,
|
|
||||||
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
|
fn get_commitments(&self) -> Vec<C> {
|
||||||
{
|
vec![self.cmW, self.cmE]
|
||||||
/// hash implements the committed instance hash compatible with the gadget implemented in
|
}
|
||||||
/// nova/circuits.rs::CommittedInstanceVar.hash.
|
|
||||||
/// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and `U_i` is the
|
fn is_incoming(&self) -> bool {
|
||||||
/// `CommittedInstance`.
|
self.cmE == C::zero() && self.u == One::one()
|
||||||
pub fn hash<T: Transcript<C::ScalarField>>(
|
|
||||||
&self,
|
|
||||||
sponge: &T,
|
|
||||||
pp_hash: C::ScalarField, // public params hash
|
|
||||||
i: C::ScalarField,
|
|
||||||
z_0: Vec<C::ScalarField>,
|
|
||||||
z_i: Vec<C::ScalarField>,
|
|
||||||
) -> C::ScalarField {
|
|
||||||
let mut sponge = sponge.clone();
|
|
||||||
sponge.absorb(&pp_hash);
|
|
||||||
sponge.absorb(&i);
|
|
||||||
sponge.absorb(&z_0);
|
|
||||||
sponge.absorb(&z_i);
|
|
||||||
sponge.absorb(&self);
|
|
||||||
sponge.squeeze_field_elements(1)[0]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,6 +175,14 @@ impl<C: CurveGroup> Witness<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C: CurveGroup> WitnessOps<C::ScalarField> for Witness<C> {
|
||||||
|
type Var = WitnessVar<C>;
|
||||||
|
|
||||||
|
fn get_openings(&self) -> Vec<(&[C::ScalarField], C::ScalarField)> {
|
||||||
|
vec![(&self.W, self.rW), (&self.E, self.rE)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2, const H: bool = false>
|
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2, const H: bool = false>
|
||||||
where
|
where
|
||||||
@@ -696,8 +691,8 @@ where
|
|||||||
&sponge,
|
&sponge,
|
||||||
self.pp_hash,
|
self.pp_hash,
|
||||||
self.i + C1::ScalarField::one(),
|
self.i + C1::ScalarField::one(),
|
||||||
self.z_0.clone(),
|
&self.z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
);
|
);
|
||||||
// u_{i+1}.x[1] = H(cf_U_{i+1})
|
// u_{i+1}.x[1] = H(cf_U_{i+1})
|
||||||
let cf_u_i1_x: C1::ScalarField;
|
let cf_u_i1_x: C1::ScalarField;
|
||||||
@@ -907,7 +902,7 @@ where
|
|||||||
|
|
||||||
// check that u_i's output points to the running instance
|
// check that u_i's output points to the running instance
|
||||||
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
||||||
let expected_u_i_x = U_i.hash(&sponge, 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);
|
||||||
if expected_u_i_x != u_i.x[0] {
|
if expected_u_i_x != u_i.x[0] {
|
||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ use ark_std::{One, Zero};
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
arith::r1cs::{RelaxedR1CS, R1CS},
|
arith::r1cs::{RelaxedR1CS, R1CS},
|
||||||
|
folding::traits::CommittedInstanceOps,
|
||||||
RngCore,
|
RngCore,
|
||||||
};
|
};
|
||||||
use ark_crypto_primitives::sponge::{
|
use ark_crypto_primitives::sponge::{
|
||||||
@@ -226,7 +227,7 @@ where
|
|||||||
|
|
||||||
// b. Check computed hashes are correct
|
// b. Check computed hashes are correct
|
||||||
let mut sponge = PoseidonSponge::<C1::ScalarField>::new(poseidon_config);
|
let mut sponge = PoseidonSponge::<C1::ScalarField>::new(poseidon_config);
|
||||||
let expected_u_i_x = proof.U_i.hash(&sponge, pp_hash, i, z_0, z_i);
|
let expected_u_i_x = proof.U_i.hash(&sponge, pp_hash, i, &z_0, &z_i);
|
||||||
if expected_u_i_x != proof.u_i.x[0] {
|
if expected_u_i_x != proof.u_i.x[0] {
|
||||||
return Err(Error::zkIVCVerificationFail);
|
return Err(Error::zkIVCVerificationFail);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,13 +24,16 @@ use super::{
|
|||||||
CommittedInstance, CommittedInstanceVar, ProtoGalaxyCycleFoldConfig,
|
CommittedInstance, CommittedInstanceVar, ProtoGalaxyCycleFoldConfig,
|
||||||
};
|
};
|
||||||
use crate::{
|
use crate::{
|
||||||
folding::circuits::{
|
folding::{
|
||||||
cyclefold::{
|
circuits::{
|
||||||
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
|
cyclefold::{
|
||||||
CycleFoldConfig, NIFSFullGadget,
|
CycleFoldChallengeGadget, CycleFoldCommittedInstance,
|
||||||
|
CycleFoldCommittedInstanceVar, CycleFoldConfig, NIFSFullGadget,
|
||||||
|
},
|
||||||
|
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
|
||||||
|
CF1, CF2,
|
||||||
},
|
},
|
||||||
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
|
traits::CommittedInstanceVarOps,
|
||||||
CF1, CF2,
|
|
||||||
},
|
},
|
||||||
frontend::FCircuit,
|
frontend::FCircuit,
|
||||||
transcript::{AbsorbNonNativeGadget, TranscriptVar},
|
transcript::{AbsorbNonNativeGadget, TranscriptVar},
|
||||||
@@ -346,24 +349,12 @@ where
|
|||||||
// `transcript` is for challenge generation.
|
// `transcript` is for challenge generation.
|
||||||
let mut transcript = sponge.clone();
|
let mut transcript = sponge.clone();
|
||||||
|
|
||||||
// get z_{i+1} from the F circuit
|
|
||||||
let i_usize = self.i_usize;
|
|
||||||
let z_i1 =
|
|
||||||
self.F
|
|
||||||
.generate_step_constraints(cs.clone(), i_usize, z_i.clone(), external_inputs)?;
|
|
||||||
|
|
||||||
let is_basecase = i.is_zero()?;
|
let is_basecase = i.is_zero()?;
|
||||||
|
|
||||||
// Primary Part
|
// Primary Part
|
||||||
// P.1. Compute u_i.x
|
// P.1. Compute u_i.x
|
||||||
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
||||||
let (u_i_x, _) = U_i.clone().hash(
|
let (u_i_x, _) = U_i.clone().hash(&sponge, &pp_hash, &i, &z_0, &z_i)?;
|
||||||
&sponge,
|
|
||||||
pp_hash.clone(),
|
|
||||||
i.clone(),
|
|
||||||
z_0.clone(),
|
|
||||||
z_i.clone(),
|
|
||||||
)?;
|
|
||||||
// u_i.x[1] = H(cf_U_i)
|
// u_i.x[1] = H(cf_U_i)
|
||||||
let (cf_u_i_x, _) = cf_U_i.clone().hash(&sponge, pp_hash.clone())?;
|
let (cf_u_i_x, _) = cf_U_i.clone().hash(&sponge, pp_hash.clone())?;
|
||||||
|
|
||||||
@@ -380,21 +371,27 @@ where
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
// P.4.a compute and check the first output of F'
|
// P.4.a compute and check the first output of F'
|
||||||
|
|
||||||
|
// get z_{i+1} from the F circuit
|
||||||
|
let z_i1 =
|
||||||
|
self.F
|
||||||
|
.generate_step_constraints(cs.clone(), self.i_usize, z_i, external_inputs)?;
|
||||||
|
|
||||||
// Base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{\bot})
|
// Base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{\bot})
|
||||||
// Non-base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{i+1})
|
// Non-base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{i+1})
|
||||||
let (u_i1_x, _) = U_i1.clone().hash(
|
let (u_i1_x, _) = U_i1.clone().hash(
|
||||||
&sponge,
|
&sponge,
|
||||||
pp_hash.clone(),
|
&pp_hash,
|
||||||
i + FpVar::<CF1<C1>>::one(),
|
&(i + FpVar::<CF1<C1>>::one()),
|
||||||
z_0.clone(),
|
&z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
)?;
|
)?;
|
||||||
let (u_i1_x_base, _) = CommittedInstanceVar::new_constant(cs.clone(), u_dummy)?.hash(
|
let (u_i1_x_base, _) = CommittedInstanceVar::new_constant(cs.clone(), u_dummy)?.hash(
|
||||||
&sponge,
|
&sponge,
|
||||||
pp_hash.clone(),
|
&pp_hash,
|
||||||
FpVar::<CF1<C1>>::one(),
|
&FpVar::<CF1<C1>>::one(),
|
||||||
z_0.clone(),
|
&z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
)?;
|
)?;
|
||||||
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
|
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
|
||||||
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
|
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
/// Implements the scheme described in [ProtoGalaxy](https://eprint.iacr.org/2023/1106.pdf)
|
/// Implements the scheme described in [ProtoGalaxy](https://eprint.iacr.org/2023/1106.pdf)
|
||||||
use ark_crypto_primitives::sponge::{
|
use ark_crypto_primitives::sponge::{
|
||||||
constraints::{AbsorbGadget, CryptographicSpongeVar},
|
poseidon::{PoseidonConfig, PoseidonSponge},
|
||||||
poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge},
|
|
||||||
Absorb, CryptographicSponge,
|
Absorb, CryptographicSponge,
|
||||||
};
|
};
|
||||||
use ark_ec::{CurveGroup, Group};
|
use ark_ec::{CurveGroup, Group};
|
||||||
use ark_ff::{BigInteger, PrimeField};
|
use ark_ff::{BigInteger, PrimeField};
|
||||||
use ark_r1cs_std::{
|
use ark_r1cs_std::{
|
||||||
alloc::{AllocVar, AllocationMode},
|
alloc::{AllocVar, AllocationMode},
|
||||||
fields::fp::FpVar,
|
eq::EqGadget,
|
||||||
|
fields::{fp::FpVar, FieldVar},
|
||||||
groups::{CurveVar, GroupOpsBounds},
|
groups::{CurveVar, GroupOpsBounds},
|
||||||
R1CSVar, ToConstraintFieldGadget,
|
R1CSVar, ToConstraintFieldGadget,
|
||||||
};
|
};
|
||||||
@@ -44,6 +44,8 @@ pub(crate) mod utils;
|
|||||||
use circuits::AugmentedFCircuit;
|
use circuits::AugmentedFCircuit;
|
||||||
use folding::Folding;
|
use folding::Folding;
|
||||||
|
|
||||||
|
use super::traits::{CommittedInstanceOps, CommittedInstanceVarOps, WitnessOps, WitnessVarOps};
|
||||||
|
|
||||||
/// Configuration for ProtoGalaxy's CycleFold circuit
|
/// Configuration for ProtoGalaxy's CycleFold circuit
|
||||||
pub struct ProtoGalaxyCycleFoldConfig<C: CurveGroup> {
|
pub struct ProtoGalaxyCycleFoldConfig<C: CurveGroup> {
|
||||||
_c: PhantomData<C>,
|
_c: PhantomData<C>,
|
||||||
@@ -83,30 +85,15 @@ impl<C: CurveGroup> CommittedInstance<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CurveGroup> CommittedInstance<C>
|
impl<C: CurveGroup> CommittedInstanceOps<C> for CommittedInstance<C> {
|
||||||
where
|
type Var = CommittedInstanceVar<C>;
|
||||||
C::ScalarField: Absorb,
|
|
||||||
C::BaseField: PrimeField,
|
fn get_commitments(&self) -> Vec<C> {
|
||||||
{
|
vec![self.phi]
|
||||||
/// hash implements the committed instance hash compatible with the gadget implemented in
|
}
|
||||||
/// CommittedInstanceVar.hash.
|
|
||||||
/// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and `U_i` is the
|
fn is_incoming(&self) -> bool {
|
||||||
/// `CommittedInstance`.
|
self.e == Zero::zero() && self.betas.is_empty()
|
||||||
pub fn hash(
|
|
||||||
&self,
|
|
||||||
sponge: &PoseidonSponge<C::ScalarField>,
|
|
||||||
pp_hash: C::ScalarField,
|
|
||||||
i: C::ScalarField,
|
|
||||||
z_0: Vec<C::ScalarField>,
|
|
||||||
z_i: Vec<C::ScalarField>,
|
|
||||||
) -> C::ScalarField {
|
|
||||||
let mut sponge = sponge.clone();
|
|
||||||
sponge.absorb(&pp_hash);
|
|
||||||
sponge.absorb(&i);
|
|
||||||
sponge.absorb(&z_0);
|
|
||||||
sponge.absorb(&z_i);
|
|
||||||
sponge.absorb(&self);
|
|
||||||
sponge.squeeze_field_elements(1)[0]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,34 +151,29 @@ impl<C: CurveGroup> R1CSVar<C::ScalarField> for CommittedInstanceVar<C> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C: CurveGroup> CommittedInstanceVar<C>
|
impl<C: CurveGroup> CommittedInstanceVarOps<C> for CommittedInstanceVar<C> {
|
||||||
where
|
type PointVar = NonNativeAffineVar<C>;
|
||||||
C::ScalarField: Absorb,
|
|
||||||
C::BaseField: PrimeField,
|
fn get_commitments(&self) -> Vec<Self::PointVar> {
|
||||||
{
|
vec![self.phi.clone()]
|
||||||
/// hash implements the committed instance hash compatible with the native implementation from
|
}
|
||||||
/// CommittedInstance.hash.
|
|
||||||
/// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and `U` is the
|
fn get_public_inputs(&self) -> &[FpVar<CF1<C>>] {
|
||||||
/// `CommittedInstance`.
|
&self.x
|
||||||
/// Additionally it returns the vector of the field elements from the self parameters, so they
|
}
|
||||||
/// can be reused in other gadgets avoiding recalculating (reconstraining) them.
|
|
||||||
#[allow(clippy::type_complexity)]
|
fn enforce_incoming(&self) -> Result<(), SynthesisError> {
|
||||||
pub fn hash(
|
if self.betas.is_empty() {
|
||||||
self,
|
self.e.enforce_equal(&FpVar::zero())
|
||||||
sponge: &PoseidonSpongeVar<CF1<C>>,
|
} else {
|
||||||
pp_hash: FpVar<CF1<C>>,
|
Err(SynthesisError::Unsatisfiable)
|
||||||
i: FpVar<CF1<C>>,
|
}
|
||||||
z_0: Vec<FpVar<CF1<C>>>,
|
}
|
||||||
z_i: Vec<FpVar<CF1<C>>>,
|
|
||||||
) -> Result<(FpVar<CF1<C>>, Vec<FpVar<CF1<C>>>), SynthesisError> {
|
fn enforce_partial_equal(&self, other: &Self) -> Result<(), SynthesisError> {
|
||||||
let mut sponge = sponge.clone();
|
self.betas.enforce_equal(&other.betas)?;
|
||||||
let U_vec = self.to_sponge_field_elements()?;
|
self.e.enforce_equal(&other.e)?;
|
||||||
sponge.absorb(&pp_hash)?;
|
self.x.enforce_equal(&other.x)
|
||||||
sponge.absorb(&i)?;
|
|
||||||
sponge.absorb(&z_0)?;
|
|
||||||
sponge.absorb(&z_i)?;
|
|
||||||
sponge.absorb(&U_vec)?;
|
|
||||||
Ok((sponge.squeeze_field_elements(1)?.pop().unwrap(), U_vec))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,6 +206,44 @@ impl<F: PrimeField> Witness<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F: PrimeField> WitnessOps<F> for Witness<F> {
|
||||||
|
type Var = WitnessVar<F>;
|
||||||
|
|
||||||
|
fn get_openings(&self) -> Vec<(&[F], F)> {
|
||||||
|
vec![(&self.w, self.r_w)]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// In-circuit representation of the Witness associated to the CommittedInstance.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct WitnessVar<F: PrimeField> {
|
||||||
|
pub W: Vec<FpVar<F>>,
|
||||||
|
pub rW: FpVar<F>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: PrimeField> AllocVar<Witness<F>, F> for WitnessVar<F> {
|
||||||
|
fn new_variable<T: Borrow<Witness<F>>>(
|
||||||
|
cs: impl Into<Namespace<F>>,
|
||||||
|
f: impl FnOnce() -> Result<T, SynthesisError>,
|
||||||
|
mode: AllocationMode,
|
||||||
|
) -> Result<Self, SynthesisError> {
|
||||||
|
f().and_then(|val| {
|
||||||
|
let cs = cs.into();
|
||||||
|
|
||||||
|
let W = Vec::new_variable(cs.clone(), || Ok(val.borrow().w.to_vec()), mode)?;
|
||||||
|
let rW = FpVar::new_variable(cs.clone(), || Ok(val.borrow().r_w), mode)?;
|
||||||
|
|
||||||
|
Ok(Self { W, rW })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<F: PrimeField> WitnessVarOps<F> for WitnessVar<F> {
|
||||||
|
fn get_openings(&self) -> Vec<(&[FpVar<F>], FpVar<F>)> {
|
||||||
|
vec![(&self.W, self.rW.clone())]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error, PartialEq)]
|
#[derive(Debug, thiserror::Error, PartialEq)]
|
||||||
pub enum ProtoGalaxyError {
|
pub enum ProtoGalaxyError {
|
||||||
#[error("The remainder from G(X)-F(α)*L_0(X)) / Z(X) should be zero")]
|
#[error("The remainder from G(X)-F(α)*L_0(X)) / Z(X) should be zero")]
|
||||||
@@ -636,8 +656,8 @@ where
|
|||||||
&sponge,
|
&sponge,
|
||||||
self.pp_hash,
|
self.pp_hash,
|
||||||
self.i + C1::ScalarField::one(),
|
self.i + C1::ScalarField::one(),
|
||||||
self.z_0.clone(),
|
&self.z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
);
|
);
|
||||||
// `cf_U_{i+1}` (i.e., `cf_U_1`) is fixed to `cf_U_dummy`, so we
|
// `cf_U_{i+1}` (i.e., `cf_U_1`) is fixed to `cf_U_dummy`, so we
|
||||||
// just use `self.cf_U_i = cf_U_0 = cf_U_dummy`.
|
// just use `self.cf_U_i = cf_U_0 = cf_U_dummy`.
|
||||||
@@ -744,8 +764,8 @@ where
|
|||||||
&sponge,
|
&sponge,
|
||||||
self.pp_hash,
|
self.pp_hash,
|
||||||
self.i + C1::ScalarField::one(),
|
self.i + C1::ScalarField::one(),
|
||||||
self.z_0.clone(),
|
&self.z_0,
|
||||||
z_i1.clone(),
|
&z_i1,
|
||||||
);
|
);
|
||||||
cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, self.pp_hash);
|
cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, self.pp_hash);
|
||||||
|
|
||||||
@@ -874,7 +894,7 @@ where
|
|||||||
|
|
||||||
// check that u_i's output points to the running instance
|
// check that u_i's output points to the running instance
|
||||||
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
||||||
let expected_u_i_x = U_i.hash(&sponge, 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);
|
||||||
if expected_u_i_x != u_i.x[0] {
|
if expected_u_i_x != u_i.x[0] {
|
||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,8 +18,8 @@ impl<C: CurveGroup> Absorb for CommittedInstance<C>
|
|||||||
where
|
where
|
||||||
C::ScalarField: Absorb,
|
C::ScalarField: Absorb,
|
||||||
{
|
{
|
||||||
fn to_sponge_bytes(&self, _dest: &mut Vec<u8>) {
|
fn to_sponge_bytes(&self, dest: &mut Vec<u8>) {
|
||||||
unimplemented!()
|
C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
|
fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
|
||||||
@@ -35,7 +35,7 @@ where
|
|||||||
// Implements the trait for absorbing ProtoGalaxy's CommittedInstanceVar in-circuit.
|
// Implements the trait for absorbing ProtoGalaxy's CommittedInstanceVar in-circuit.
|
||||||
impl<C: CurveGroup> AbsorbGadget<C::ScalarField> for CommittedInstanceVar<C> {
|
impl<C: CurveGroup> AbsorbGadget<C::ScalarField> for CommittedInstanceVar<C> {
|
||||||
fn to_sponge_bytes(&self) -> Result<Vec<UInt8<C::ScalarField>>, SynthesisError> {
|
fn to_sponge_bytes(&self) -> Result<Vec<UInt8<C::ScalarField>>, SynthesisError> {
|
||||||
unimplemented!()
|
FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
|
fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
|
||||||
@@ -114,3 +114,46 @@ impl<C: CurveGroup> RelaxedR1CS<C, Witness<C::ScalarField>, CommittedInstance<C>
|
|||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
pub mod tests {
|
||||||
|
use super::*;
|
||||||
|
use ark_bn254::{Fr, G1Projective as Projective};
|
||||||
|
use ark_r1cs_std::{alloc::AllocVar, R1CSVar};
|
||||||
|
use ark_relations::r1cs::ConstraintSystem;
|
||||||
|
use ark_std::UniformRand;
|
||||||
|
use rand::Rng;
|
||||||
|
|
||||||
|
/// test that checks the native CommittedInstance.to_sponge_{bytes,field_elements}
|
||||||
|
/// vs the R1CS constraints version
|
||||||
|
#[test]
|
||||||
|
pub fn test_committed_instance_to_sponge_preimage() {
|
||||||
|
let mut rng = ark_std::test_rng();
|
||||||
|
|
||||||
|
let t = rng.gen::<u8>() as usize;
|
||||||
|
let io_len = rng.gen::<u8>() as usize;
|
||||||
|
|
||||||
|
let ci = CommittedInstance::<Projective> {
|
||||||
|
phi: Projective::rand(&mut rng),
|
||||||
|
betas: (0..t).map(|_| Fr::rand(&mut rng)).collect(),
|
||||||
|
e: Fr::rand(&mut rng),
|
||||||
|
x: (0..io_len).map(|_| Fr::rand(&mut rng)).collect(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let bytes = ci.to_sponge_bytes_as_vec();
|
||||||
|
let field_elements = ci.to_sponge_field_elements_as_vec();
|
||||||
|
|
||||||
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
|
let ciVar =
|
||||||
|
CommittedInstanceVar::<Projective>::new_witness(cs.clone(), || Ok(ci.clone())).unwrap();
|
||||||
|
let bytes_var = ciVar.to_sponge_bytes().unwrap();
|
||||||
|
let field_elements_var = ciVar.to_sponge_field_elements().unwrap();
|
||||||
|
|
||||||
|
assert!(cs.is_satisfied().unwrap());
|
||||||
|
|
||||||
|
// check that the natively computed and in-circuit computed hashes match
|
||||||
|
assert_eq!(bytes_var.value().unwrap(), bytes);
|
||||||
|
assert_eq!(field_elements_var.value().unwrap(), field_elements);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
121
folding-schemes/src/folding/traits.rs
Normal file
121
folding-schemes/src/folding/traits.rs
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
use ark_crypto_primitives::sponge::{
|
||||||
|
constraints::{AbsorbGadget, CryptographicSpongeVar},
|
||||||
|
poseidon::constraints::PoseidonSpongeVar,
|
||||||
|
Absorb,
|
||||||
|
};
|
||||||
|
use ark_ec::CurveGroup;
|
||||||
|
use ark_ff::PrimeField;
|
||||||
|
use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, ToConstraintFieldGadget};
|
||||||
|
use ark_relations::r1cs::SynthesisError;
|
||||||
|
|
||||||
|
use crate::{transcript::Transcript, Error};
|
||||||
|
|
||||||
|
use super::circuits::CF1;
|
||||||
|
|
||||||
|
pub trait CommittedInstanceOps<C: CurveGroup> {
|
||||||
|
/// The in-circuit representation of the committed instance.
|
||||||
|
type Var: AllocVar<Self, CF1<C>> + CommittedInstanceVarOps<C>;
|
||||||
|
/// `hash` implements the committed instance hash compatible with the
|
||||||
|
/// in-circuit implementation from `CommittedInstanceVarOps::hash`.
|
||||||
|
///
|
||||||
|
/// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and
|
||||||
|
/// `U_i` is the committed instance `self`.
|
||||||
|
fn hash<T: Transcript<CF1<C>>>(
|
||||||
|
&self,
|
||||||
|
sponge: &T,
|
||||||
|
pp_hash: CF1<C>, // public params hash
|
||||||
|
i: CF1<C>,
|
||||||
|
z_0: &[CF1<C>],
|
||||||
|
z_i: &[CF1<C>],
|
||||||
|
) -> CF1<C>
|
||||||
|
where
|
||||||
|
CF1<C>: Absorb,
|
||||||
|
Self: Sized + Absorb,
|
||||||
|
{
|
||||||
|
let mut sponge = sponge.clone();
|
||||||
|
sponge.absorb(&pp_hash);
|
||||||
|
sponge.absorb(&i);
|
||||||
|
sponge.absorb(&z_0);
|
||||||
|
sponge.absorb(&z_i);
|
||||||
|
sponge.absorb(&self);
|
||||||
|
sponge.squeeze_field_elements(1)[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the commitments contained in the committed instance.
|
||||||
|
fn get_commitments(&self) -> Vec<C>;
|
||||||
|
|
||||||
|
/// Returns `true` if the committed instance is an incoming instance, and
|
||||||
|
/// `false` if it is a running instance.
|
||||||
|
fn is_incoming(&self) -> bool;
|
||||||
|
|
||||||
|
/// Checks if the committed instance is an incoming instance.
|
||||||
|
fn check_incoming(&self) -> Result<(), Error> {
|
||||||
|
self.is_incoming()
|
||||||
|
.then_some(())
|
||||||
|
.ok_or(Error::NotIncomingCommittedInstance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait CommittedInstanceVarOps<C: CurveGroup> {
|
||||||
|
type PointVar: ToConstraintFieldGadget<CF1<C>>;
|
||||||
|
/// `hash` implements the in-circuit committed instance hash compatible with
|
||||||
|
/// the native implementation from `CommittedInstanceOps::hash`.
|
||||||
|
/// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and
|
||||||
|
/// `U_i` is the committed instance `self`.
|
||||||
|
///
|
||||||
|
/// Additionally it returns the in-circuit representation of the committed
|
||||||
|
/// instance `self` as a vector of field elements, so they can be reused in
|
||||||
|
/// other gadgets avoiding recalculating (reconstraining) them.
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
fn hash(
|
||||||
|
&self,
|
||||||
|
sponge: &PoseidonSpongeVar<CF1<C>>,
|
||||||
|
pp_hash: &FpVar<CF1<C>>,
|
||||||
|
i: &FpVar<CF1<C>>,
|
||||||
|
z_0: &[FpVar<CF1<C>>],
|
||||||
|
z_i: &[FpVar<CF1<C>>],
|
||||||
|
) -> Result<(FpVar<CF1<C>>, Vec<FpVar<CF1<C>>>), SynthesisError>
|
||||||
|
where
|
||||||
|
Self: AbsorbGadget<CF1<C>>,
|
||||||
|
{
|
||||||
|
let mut sponge = sponge.clone();
|
||||||
|
let U_vec = self.to_sponge_field_elements()?;
|
||||||
|
sponge.absorb(&pp_hash)?;
|
||||||
|
sponge.absorb(&i)?;
|
||||||
|
sponge.absorb(&z_0)?;
|
||||||
|
sponge.absorb(&z_i)?;
|
||||||
|
sponge.absorb(&U_vec)?;
|
||||||
|
Ok((sponge.squeeze_field_elements(1)?.pop().unwrap(), U_vec))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the commitments contained in the committed instance.
|
||||||
|
fn get_commitments(&self) -> Vec<Self::PointVar>;
|
||||||
|
|
||||||
|
/// Returns the public inputs contained in the committed instance.
|
||||||
|
fn get_public_inputs(&self) -> &[FpVar<CF1<C>>];
|
||||||
|
|
||||||
|
/// Generates constraints to enforce that the committed instance is an
|
||||||
|
/// incoming instance.
|
||||||
|
fn enforce_incoming(&self) -> Result<(), SynthesisError>;
|
||||||
|
|
||||||
|
/// Generates constraints to enforce that the committed instance `self` is
|
||||||
|
/// partially equal to another committed instance `other`.
|
||||||
|
/// Here, only field elements are compared, while commitments (points) are
|
||||||
|
/// not.
|
||||||
|
fn enforce_partial_equal(&self, other: &Self) -> Result<(), SynthesisError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WitnessOps<F: PrimeField> {
|
||||||
|
/// The in-circuit representation of the witness.
|
||||||
|
type Var: AllocVar<Self, F> + WitnessVarOps<F>;
|
||||||
|
|
||||||
|
/// Returns the openings (i.e., the values being committed to and the
|
||||||
|
/// randomness) contained in the witness.
|
||||||
|
fn get_openings(&self) -> Vec<(&[F], F)>;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait WitnessVarOps<F: PrimeField> {
|
||||||
|
/// Returns the openings (i.e., the values being committed to and the
|
||||||
|
/// randomness) contained in the witness.
|
||||||
|
fn get_openings(&self) -> Vec<(&[FpVar<F>], FpVar<F>)>;
|
||||||
|
}
|
||||||
@@ -43,6 +43,8 @@ pub enum Error {
|
|||||||
IVCVerificationFail,
|
IVCVerificationFail,
|
||||||
#[error("zkIVC verification failed")]
|
#[error("zkIVC verification failed")]
|
||||||
zkIVCVerificationFail,
|
zkIVCVerificationFail,
|
||||||
|
#[error("Committed instance is expected to be an incoming (fresh) instance")]
|
||||||
|
NotIncomingCommittedInstance,
|
||||||
#[error("R1CS instance is expected to not be relaxed")]
|
#[error("R1CS instance is expected to not be relaxed")]
|
||||||
R1CSUnrelaxedFail,
|
R1CSUnrelaxedFail,
|
||||||
#[error("Could not find the inner ConstraintSystem")]
|
#[error("Could not find the inner ConstraintSystem")]
|
||||||
|
|||||||
Reference in New Issue
Block a user