Skip to content

Commit

Permalink
- Unified transcript
Browse files Browse the repository at this point in the history
- Wrap ECC and EmulatedFieldElement
- Make all structs CurveCycleEquipped
- Specialize R1CS for both curves
- Update Transcript
  • Loading branch information
adr1anh committed Feb 29, 2024
1 parent cb096fe commit 79bb090
Show file tree
Hide file tree
Showing 24 changed files with 1,896 additions and 1,619 deletions.
7 changes: 4 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@ readme = "README.md"
repository = "https://github.com/lurk-lab/arecibo"
license-file = "LICENSE"
keywords = ["zkSNARKs", "cryptography", "proofs"]
rust-version="1.71.0"
rust-version = "1.71.0"

[dependencies]
bellpepper-core = { version = "0.4.0", default-features = false }
bellpepper = { git="https://github.com/lurk-lab/bellpepper", branch="dev", default-features = false }
bellpepper = { git = "https://github.com/lurk-lab/bellpepper", branch = "dev", default-features = false }
bellpepper-emulated = { git = "https://github.com/lurk-lab/bellpepper-gadgets", branch = "main", default-features = false }
ff = { version = "0.13.0", features = ["derive"] }
digest = "0.10"
halo2curves = { version = "0.6.0", features = ["bits", "derive_serde"] }
Expand All @@ -23,7 +24,7 @@ rand_core = { version = "0.6", default-features = false }
rand_chacha = "0.3"
subtle = "2.5"
pasta_curves = { version = "0.5.0", features = ["repr-c", "serde"] }
neptune = { git = "https://github.com/lurk-lab/neptune", branch="dev", default-features = false, features = ["abomonation"] }
neptune = { git = "https://github.com/lurk-lab/neptune", branch = "dev", default-features = false, features = ["abomonation"] }
generic-array = "1.0.0"
num-bigint = { version = "0.4", features = ["serde", "rand"] }
num-traits = "0.2"
Expand Down
85 changes: 41 additions & 44 deletions src/parafold/circuit.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use bellpepper_core::{ConstraintSystem, SynthesisError};

use crate::parafold::nivc::circuit::AllocatedNIVCState;
use crate::parafold::nivc::{NIVCMergeProof, NIVCUpdateProof, NIVCIO};
use crate::parafold::transcript::circuit::AllocatedTranscript;
use crate::parafold::nivc::{NIVCUpdateProof, NIVCIO};
use crate::parafold::transcript::TranscriptConstants;
use crate::supernova::StepCircuit;
use crate::traits::CurveCycleEquipped;
Expand All @@ -12,57 +11,55 @@ pub fn synthesize_step<E, CS, SF>(
ro_consts: &TranscriptConstants<E::Scalar>,
proof: NIVCUpdateProof<E>,
step_circuit: &SF,
) -> Result<NIVCIO<E::Scalar>, SynthesisError>
) -> Result<NIVCIO<E>, SynthesisError>
where
E: CurveCycleEquipped,
CS: ConstraintSystem<E::Scalar>,
SF: StepCircuit<E::Scalar>,
{
// Fold proof for previous state
let (mut state, transcript) =
AllocatedNIVCState::from_proof(cs.namespace(|| "verify self"), ro_consts, proof)?;
let mut state = AllocatedNIVCState::from_proof(cs.namespace(|| "verify self"), ro_consts, proof)?;

let io = state.update_io(cs.namespace(|| "step"), step_circuit);
let io_native = state.update_io(cs.namespace(|| "step"), step_circuit);

transcript.inputize(cs.namespace(|| "inputize transcript"))?;
state.inputize(cs.namespace(|| "inputize state"))?;

io
io_native
}

/// Circuit
pub fn synthesize_merge<E, CS>(
mut cs: CS,
ro_consts: &TranscriptConstants<E::Scalar>,
proof_L: NIVCUpdateProof<E>,
proof_R: NIVCUpdateProof<E>,
proof_merge: NIVCMergeProof<E>,
) -> Result<NIVCIO<E::Scalar>, SynthesisError>
where
E: CurveCycleEquipped,
CS: ConstraintSystem<E::Scalar>,
{
// Verify L
let (self_L, transcript_L) =
AllocatedNIVCState::from_proof(cs.namespace(|| "verify proof_L"), ro_consts, proof_L)?;
// Verify R
let (self_R, transcript_R) =
AllocatedNIVCState::from_proof(cs.namespace(|| "verify proof_R"), ro_consts, proof_R)?;
// Merge transcripts
let mut transcript = AllocatedTranscript::merge(transcript_L, transcript_R);

// Merge states
let (state, io_native) = AllocatedNIVCState::merge(
cs.namespace(|| "merge"),
self_L,
self_R,
ro_consts,
proof_merge,
&mut transcript,
)?;

transcript.inputize(cs.namespace(|| "inputize transcript"))?;
state.inputize(cs.namespace(|| "inputize state"))?;

Ok(io_native)
}
// /// Circuit
// pub fn synthesize_merge<E, CS>(
// mut cs: CS,
// ro_consts: &TranscriptConstants<E::Scalar>,
// proof_L: NIVCUpdateProof<E>,
// proof_R: NIVCUpdateProof<E>,
// proof_merge: NIVCMergeProof<E>,
// ) -> Result<NIVCIO<E>, SynthesisError>
// where
// E: CurveCycleEquipped,
// CS: ConstraintSystem<E::Scalar>,
// {
// // Verify L
// let (self_L, transcript_L) =
// AllocatedNIVCState::from_proof(cs.namespace(|| "verify proof_L"), ro_consts, proof_L)?;
// // Verify R
// let (self_R, transcript_R) =
// AllocatedNIVCState::from_proof(cs.namespace(|| "verify proof_R"), ro_consts, proof_R)?;
// // Merge transcripts
// let mut transcript = AllocatedTranscript::merge(transcript_L, transcript_R);
//
// // Merge states
// let (state, io_native) = AllocatedNIVCState::merge(
// cs.namespace(|| "merge"),
// self_L,
// self_R,
// ro_consts,
// proof_merge,
// &mut transcript,
// )?;
//
// transcript.inputize(cs.namespace(|| "inputize transcript"))?;
// state.inputize(cs.namespace(|| "inputize state"))?;
//
// Ok(io_native)
// }
109 changes: 47 additions & 62 deletions src/parafold/cycle_fold/circuit.rs
Original file line number Diff line number Diff line change
@@ -1,107 +1,92 @@
use bellpepper_core::num::AllocatedNum;
use bellpepper_core::{ConstraintSystem, SynthesisError};
use itertools::{chain, zip_eq};
use bellpepper_core::boolean::Boolean;
use bellpepper_core::{ConstraintSystem, SynthesisError, Variable};

use crate::parafold::cycle_fold::AllocatedHashedCommitment;
use crate::parafold::nifs::circuit_secondary::AllocatedSecondaryRelaxedR1CSInstance;
use crate::parafold::nifs::FoldProof;
use crate::parafold::cycle_fold::gadgets::emulated::AllocatedBase;
use crate::parafold::cycle_fold::nifs::circuit::AllocatedSecondaryRelaxedR1CSInstance;
use crate::parafold::cycle_fold::{AllocatedPrimaryCommitment, NUM_IO_SECONDARY};
use crate::parafold::transcript::circuit::AllocatedTranscript;
use crate::traits::{CurveCycleEquipped, Engine};
use crate::traits::CurveCycleEquipped;

#[derive(Debug, Clone)]
pub struct AllocatedScalarMulAccumulator<E: Engine> {
pub struct AllocatedScalarMulAccumulator<E: CurveCycleEquipped> {
deferred: Vec<AllocatedScalarMulInstance<E>>,
acc: AllocatedSecondaryRelaxedR1CSInstance<E>,
}

impl<E: Engine> AllocatedScalarMulAccumulator<E> {
pub fn new() -> Self {
Self { deferred: vec![] }
impl<E: CurveCycleEquipped> AllocatedScalarMulAccumulator<E> {
pub fn new(acc: AllocatedSecondaryRelaxedR1CSInstance<E>) -> Self {
Self {
deferred: vec![],
acc,
}
}

/// Compute the result `C <- A + x * B` by folding a proof over the secondary curve.
pub fn scalar_mul<CS>(
&mut self,
mut cs: CS,
A: AllocatedHashedCommitment<E>,
B: AllocatedHashedCommitment<E>,
x: AllocatedNum<E::Scalar>,
transcript: &mut AllocatedTranscript<E::Scalar>,
) -> Result<AllocatedHashedCommitment<E>, SynthesisError>
A: AllocatedPrimaryCommitment<E>,
B: AllocatedPrimaryCommitment<E>,
x_bits: Vec<Boolean>,
transcript: &mut AllocatedTranscript<E>,
) -> Result<AllocatedPrimaryCommitment<E>, SynthesisError>
where
CS: ConstraintSystem<E::Scalar>,
{
let A_value = A.value;
let B_value = B.value;
let x_value = x.get_value().ok_or(SynthesisError::AssignmentMissing)?;
let C_value = A_value + B_value * x_value;
let C = AllocatedHashedCommitment::alloc_transcript(
cs.namespace(|| "alloc output"),
C_value,
transcript,
);
let C = transcript.read_commitment_primary(cs.namespace(|| "transcript C"))?;

self.deferred.push(AllocatedScalarMulInstance {
A,
B,
x,
x_bits,
C: C.clone(),
});

Ok(C)
}

/// Merges another existing [AllocatedScalarMulAccumulator] into `self`
pub fn merge(mut self_L: Self, mut self_R: Self) -> Self {
self_L.deferred.append(&mut self_R.deferred);
self_L
}
}

impl<E: CurveCycleEquipped> AllocatedScalarMulAccumulator<E> {
pub fn finalize<CS>(
self,
mut self,
mut cs: CS,
mut acc_cf: AllocatedSecondaryRelaxedR1CSInstance<E>,
proofs: impl IntoIterator<Item = FoldProof<E::Secondary>>,
transcript: &mut AllocatedTranscript<E::Scalar>,
transcript: &mut AllocatedTranscript<E>,
) -> Result<AllocatedSecondaryRelaxedR1CSInstance<E>, SynthesisError>
where
CS: ConstraintSystem<E::Scalar>,
{
for (instance, proof) in zip_eq(self.deferred, proofs) {
let AllocatedScalarMulInstance { A, B, x, C } = instance;
let _X_tmp: Vec<_> = chain![A.as_preimage(), B.as_preimage(), [x], C.as_preimage()].collect();
for instance in self.deferred.drain(..) {
let X = instance.to_io(CS::one());

// TODO: In order to avoid computing unnecessary proofs, we can check
// - x = 0 => C = A

// Convert the elements in the instance to a bignum modulo E1::Base.
// Since |E1::Scalar| < |E1::Base|, we can create the limbs without an initial bound-check
// We should check here that the limbs are of the right size, but not-necessarily bound check them.
// X = [A.as_bignum(), B.as_bignum(), x.as_bignum(), C.as_bignum()]
let X = vec![];
acc_cf.fold(cs.namespace(|| "fold cf instance"), X, proof, transcript)?;
self
.acc
.fold(cs.namespace(|| "fold cf instance"), X, transcript)?;
}

Ok(acc_cf)
Ok(self.acc)
}

pub fn is_finalized(&self) -> bool {
self.deferred.is_empty()
}
}

#[derive(Debug, Clone)]
pub struct AllocatedScalarMulInstance<E: Engine> {
A: AllocatedHashedCommitment<E>,
B: AllocatedHashedCommitment<E>,
x: AllocatedNum<E::Scalar>,
C: AllocatedHashedCommitment<E>,
pub struct AllocatedScalarMulInstance<E: CurveCycleEquipped> {
A: AllocatedPrimaryCommitment<E>,
B: AllocatedPrimaryCommitment<E>,
x_bits: Vec<Boolean>,
C: AllocatedPrimaryCommitment<E>,
}

impl<E: Engine> AllocatedScalarMulInstance<E> {
pub fn as_preimage(&self) -> impl IntoIterator<Item = AllocatedNum<E::Scalar>> + '_ {
chain![
self.A.as_preimage(),
self.B.as_preimage(),
[self.x.clone()],
self.C.as_preimage()
]
impl<E: CurveCycleEquipped> AllocatedScalarMulInstance<E> {
fn to_io(self, one: Variable) -> [AllocatedBase<E>; NUM_IO_SECONDARY] {
let Self { A, B, x_bits, C } = self;

// Convert the elements in the instance to a bignum modulo E1::Base.
// Since |E1::Scalar| < |E1::Base|, we can create the limbs without an initial bound-check
// We should check here that the limbs are of the right size, but not-necessarily bound check them.
let x = AllocatedBase::from_bits(one, &x_bits);
[A.hash, B.hash, x, C.hash]
}
}
Loading

0 comments on commit 79bb090

Please sign in to comment.