Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Protostar without IVC #23

Merged
merged 21 commits into from
Jul 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b5d82ff
feat: duplicate sangria into protostar
han0110 Jun 12, 2023
9b06118
feat: implement `Protostar` in the way Appendix A describes
han0110 Jun 20, 2023
23d3120
fix: just compute powers of challenge on verifier side and track them
han0110 Jun 20, 2023
6be81f8
refactor: simplify sangria structures and refactor `HadamardEvaluator`
han0110 Jun 22, 2023
828277a
refactor: use same `HadamardEvaluator` from sangria
han0110 Jun 22, 2023
1d75def
feat: hardcoded `power_of_zeta` cross term computation (1x faster due…
han0110 Jun 22, 2023
73d8c8c
tmp: protostar folding verifier circuit proof of concept
han0110 Jun 29, 2023
1fe5e17
refactor: simplify `PlonkishBackend` api
han0110 Jul 7, 2023
55d89b4
feat: introduce `FoldingScheme` and unify `sangria` and `protostar`
han0110 Jul 9, 2023
fe863d2
feat: update module `ivc` with skeleton
han0110 Jul 11, 2023
ca97c55
feat: allow generic `AssignedCell`
han0110 Jul 13, 2023
473306c
feat: add a strawman impl of `Chips`
han0110 Jul 17, 2023
e3ef6be
chore: add timer
han0110 Jul 21, 2023
9a0034e
refactor: Replace `CurveCycle` with `TwoChainCurve`
han0110 Jul 23, 2023
49ecfc0
chore: rename mod `folding` to `accumulation`
han0110 Jul 23, 2023
8332aa4
feat: rename to `Gemini` and take optimization from Aztec
han0110 Jul 23, 2023
5a4888b
feat: refactor `MultilinearKzg` and implement `Zeromorph` without zer…
han0110 Jul 24, 2023
80a8320
chore: remove extra field of kzg param and rename fn
han0110 Jul 24, 2023
182e6ef
refactor
han0110 Jul 28, 2023
abbe05a
chore: staged for later PR
han0110 Jul 28, 2023
2180ac7
doc: add source of `Gemini`
han0110 Jul 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions benchmark/benches/proof_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ fn bench_hyperplonk<C: CircuitExt<Fr>>(k: usize) {

let circuit = C::rand(k, std_rng());
let circuit = Halo2Circuit::new::<HyperPlonk>(k, circuit);
let instances = circuit.instance_slices();
let circuit_info = circuit.circuit_info().unwrap();
let instances = circuit.instances();

let timer = start_timer(|| format!("hyperplonk_setup-{k}"));
let param = HyperPlonk::setup(&circuit_info, std_rng()).unwrap();
Expand All @@ -64,14 +64,14 @@ fn bench_hyperplonk<C: CircuitExt<Fr>>(k: usize) {
let proof = sample(System::HyperPlonk, k, || {
let _timer = start_timer(|| format!("hyperplonk_prove-{k}"));
let mut transcript = Keccak256Transcript::default();
HyperPlonk::prove(&pp, (), &instances, &circuit, &mut transcript, std_rng()).unwrap();
HyperPlonk::prove(&pp, &circuit, &mut transcript, std_rng()).unwrap();
transcript.into_proof()
});

let _timer = start_timer(|| format!("hyperplonk_verify-{k}"));
let accept = {
let mut transcript = Keccak256Transcript::from_proof(proof.as_slice());
HyperPlonk::verify(&vp, (), &instances, &mut transcript, std_rng()).is_ok()
let mut transcript = Keccak256Transcript::from_proof((), proof.as_slice());
HyperPlonk::verify(&vp, instances, &mut transcript, std_rng()).is_ok()
};
assert!(accept);
}
Expand Down
4 changes: 4 additions & 0 deletions benchmark/src/bin/plotter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -339,6 +339,10 @@ impl Log {
let mut stack = Vec::new();
logs.iter().fold(Vec::new(), |mut logs, log| {
let (indent, log) = log.rsplit_once('·').unwrap_or(("", log));
if log.len() < 9 {
return logs;
}

let (prefix, log) = log.split_at(9);
let depth = (indent.len() + 2) / 4;
if depth == stack.len() && prefix.starts_with("Start:") {
Expand Down
8 changes: 0 additions & 8 deletions benchmark/src/halo2/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -380,10 +380,6 @@ mod aggregation {
}
}

fn num_instances() -> Vec<usize> {
vec![4 * LIMBS]
}

fn instances(&self) -> Vec<Vec<M::Scalar>> {
vec![self.instances.clone()]
}
Expand Down Expand Up @@ -476,10 +472,6 @@ mod sha256 {
Self { input_size }
}

fn num_instances() -> Vec<usize> {
Vec::new()
}

fn instances(&self) -> Vec<Vec<Fr>> {
Vec::new()
}
Expand Down
8 changes: 7 additions & 1 deletion plonkish_backend/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@ version = "0.1.0"
edition = "2021"

[dependencies]
halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.3", package = "halo2curves" }
halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.3", package = "halo2curves", features = ["derive_serde"] }
pasta_curves = { version = "0.5.0", features = ["serde"] }
generic-array = { version = "0.14.7", features = ["serde"] }
bitvec = "1.0.1"
itertools = "0.10.5"
num-bigint = "0.4.3"
num-integer = "0.1.45"
rand = "0.8"
serde = { version = "1.0", features = ["derive"] }
bincode = "1.3.3"
sha3 = "0.10.6"
poseidon = { git = "https://github.com/han0110/poseidon", branch = "feature/with-spec" }

# timer
ark-std = { version = "^0.4.0", default-features = false, optional = true }
Expand Down
262 changes: 262 additions & 0 deletions plonkish_backend/src/accumulation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
use crate::{
backend::{PlonkishCircuit, PlonkishCircuitInfo},
pcs::{CommitmentChunk, PolynomialCommitmentScheme},
util::{
arithmetic::Field,
transcript::{TranscriptRead, TranscriptWrite},
DeserializeOwned, Serialize,
},
Error,
};
use rand::RngCore;
use std::{borrow::BorrowMut, fmt::Debug};

pub mod protostar;
pub mod sangria;

pub trait AccumulationScheme<F: Field>: Clone + Debug {
type Pcs: PolynomialCommitmentScheme<F>;
type ProverParam: Debug + Serialize + DeserializeOwned;
type VerifierParam: Debug + Serialize + DeserializeOwned;
type Accumulator: Debug + AsRef<Self::AccumulatorInstance>;
type AccumulatorInstance: Clone + Debug + Serialize + DeserializeOwned;

fn setup(
circuit_info: &PlonkishCircuitInfo<F>,
rng: impl RngCore,
) -> Result<<Self::Pcs as PolynomialCommitmentScheme<F>>::Param, Error>;

fn preprocess(
param: &<Self::Pcs as PolynomialCommitmentScheme<F>>::Param,
circuit_info: &PlonkishCircuitInfo<F>,
) -> Result<(Self::ProverParam, Self::VerifierParam), Error>;

fn init_accumulator(pp: &Self::ProverParam) -> Result<Self::Accumulator, Error>;

fn init_accumulator_from_nark(
pp: &Self::ProverParam,
nark: PlonkishNark<F, Self::Pcs>,
) -> Result<Self::Accumulator, Error>;

fn prove_nark(
pp: &Self::ProverParam,
circuit: &impl PlonkishCircuit<F>,
transcript: &mut impl TranscriptWrite<CommitmentChunk<F, Self::Pcs>, F>,
rng: impl RngCore,
) -> Result<PlonkishNark<F, Self::Pcs>, Error>;

fn prove_accumulation<const IS_INCOMING_ABSORBED: bool>(
pp: &Self::ProverParam,
accumulator: impl BorrowMut<Self::Accumulator>,
incoming: &Self::Accumulator,
transcript: &mut impl TranscriptWrite<CommitmentChunk<F, Self::Pcs>, F>,
rng: impl RngCore,
) -> Result<(), Error>;

fn prove_accumulation_from_nark(
pp: &Self::ProverParam,
accumulator: impl BorrowMut<Self::Accumulator>,
circuit: &impl PlonkishCircuit<F>,
transcript: &mut impl TranscriptWrite<CommitmentChunk<F, Self::Pcs>, F>,
mut rng: impl RngCore,
) -> Result<(), Error> {
let nark = Self::prove_nark(pp, circuit, transcript, &mut rng)?;
let incoming = Self::init_accumulator_from_nark(pp, nark)?;
Self::prove_accumulation::<true>(pp, accumulator, &incoming, transcript, &mut rng)?;
Ok(())
}

fn verify_accumulation_from_nark(
vp: &Self::VerifierParam,
accumulator: impl BorrowMut<Self::AccumulatorInstance>,
instances: &[Vec<F>],
transcript: &mut impl TranscriptRead<CommitmentChunk<F, Self::Pcs>, F>,
rng: impl RngCore,
) -> Result<(), Error>;

fn prove_decider(
pp: &Self::ProverParam,
accumulator: &Self::Accumulator,
transcript: &mut impl TranscriptWrite<CommitmentChunk<F, Self::Pcs>, F>,
rng: impl RngCore,
) -> Result<(), Error>;

fn prove_decider_with_last_nark(
pp: &Self::ProverParam,
mut accumulator: impl BorrowMut<Self::Accumulator>,
circuit: &impl PlonkishCircuit<F>,
transcript: &mut impl TranscriptWrite<CommitmentChunk<F, Self::Pcs>, F>,
mut rng: impl RngCore,
) -> Result<(), Error> {
Self::prove_accumulation_from_nark(
pp,
accumulator.borrow_mut(),
circuit,
transcript,
&mut rng,
)?;
Self::prove_decider(pp, accumulator.borrow(), transcript, &mut rng)?;
Ok(())
}

fn verify_decider(
vp: &Self::VerifierParam,
accumulator: &Self::AccumulatorInstance,
transcript: &mut impl TranscriptRead<CommitmentChunk<F, Self::Pcs>, F>,
rng: impl RngCore,
) -> Result<(), Error>;

fn verify_decider_with_last_nark(
vp: &Self::VerifierParam,
mut accumulator: impl BorrowMut<Self::AccumulatorInstance>,
instances: &[Vec<F>],
transcript: &mut impl TranscriptRead<CommitmentChunk<F, Self::Pcs>, F>,
mut rng: impl RngCore,
) -> Result<(), Error> {
Self::verify_accumulation_from_nark(
vp,
accumulator.borrow_mut(),
instances,
transcript,
&mut rng,
)?;
Self::verify_decider(vp, accumulator.borrow(), transcript, &mut rng)?;
Ok(())
}
}

#[derive(Clone, Debug)]
pub struct PlonkishNark<F, Pcs>
where
F: Field,
Pcs: PolynomialCommitmentScheme<F>,
{
instance: PlonkishNarkInstance<F, Pcs::Commitment>,
witness_polys: Vec<Pcs::Polynomial>,
}

impl<F, Pcs> PlonkishNark<F, Pcs>
where
F: Field,
Pcs: PolynomialCommitmentScheme<F>,
{
fn new(
instances: Vec<Vec<F>>,
challenges: Vec<F>,
witness_comms: Vec<Pcs::Commitment>,
witness_polys: Vec<Pcs::Polynomial>,
) -> Self {
Self {
instance: PlonkishNarkInstance::new(instances, challenges, witness_comms),
witness_polys,
}
}
}

#[derive(Clone, Debug)]
pub struct PlonkishNarkInstance<F, C> {
instances: Vec<Vec<F>>,
challenges: Vec<F>,
witness_comms: Vec<C>,
}

impl<F, C> PlonkishNarkInstance<F, C> {
fn new(instances: Vec<Vec<F>>, challenges: Vec<F>, witness_comms: Vec<C>) -> Self {
Self {
instances,
challenges,
witness_comms,
}
}
}

#[cfg(test)]
pub(crate) mod test {
use crate::{
accumulation::AccumulationScheme,
backend::{PlonkishCircuit, PlonkishCircuitInfo},
pcs::PolynomialCommitmentScheme,
util::{
arithmetic::PrimeField,
end_timer, start_timer,
test::seeded_std_rng,
transcript::{InMemoryTranscript, TranscriptRead, TranscriptWrite},
DeserializeOwned, Serialize,
},
};
use std::{hash::Hash, ops::Range};

pub(crate) fn run_accumulation_scheme<F, Fs, T, C>(
num_vars_range: Range<usize>,
circuit_fn: impl Fn(usize) -> (PlonkishCircuitInfo<F>, Vec<C>),
) where
F: PrimeField + Hash + Serialize + DeserializeOwned,
Fs: AccumulationScheme<F>,
T: TranscriptRead<<Fs::Pcs as PolynomialCommitmentScheme<F>>::CommitmentChunk, F>
+ TranscriptWrite<<Fs::Pcs as PolynomialCommitmentScheme<F>>::CommitmentChunk, F>
+ InMemoryTranscript<Param = ()>,
C: PlonkishCircuit<F>,
{
for num_vars in num_vars_range {
let (circuit_info, circuits) = circuit_fn(num_vars);
let last_circuit = circuits.last().unwrap();

let timer = start_timer(|| format!("setup-{num_vars}"));
let param = Fs::setup(&circuit_info, seeded_std_rng()).unwrap();
end_timer(timer);

let timer = start_timer(|| format!("preprocess-{num_vars}"));
let (pp, vp) = Fs::preprocess(&param, &circuit_info).unwrap();
end_timer(timer);

let (accumulator_before_last, proof) = {
let mut accumulator = Fs::init_accumulator(&pp).unwrap();
for circuit in circuits[..circuits.len() - 1].iter() {
let timer = start_timer(|| format!("prove_accumulation_from_nark-{num_vars}"));
Fs::prove_accumulation_from_nark(
&pp,
&mut accumulator,
circuit,
&mut T::new(()),
seeded_std_rng(),
)
.unwrap();
end_timer(timer);
}

let accumulator_before_last = accumulator.as_ref().clone();

let timer = start_timer(|| format!("prove_decider_with_last_nark-{num_vars}"));
let proof = {
let mut transcript = T::new(());
Fs::prove_decider_with_last_nark(
&pp,
&mut accumulator,
last_circuit,
&mut transcript,
seeded_std_rng(),
)
.unwrap();
transcript.into_proof()
};
end_timer(timer);

(accumulator_before_last, proof)
};

let timer = start_timer(|| format!("verify_decider_with_last_nark-{num_vars}"));
let result = {
let mut transcript = T::from_proof((), proof.as_slice());
Fs::verify_decider_with_last_nark(
&vp,
accumulator_before_last,
last_circuit.instances(),
&mut transcript,
seeded_std_rng(),
)
};
assert!(matches!(result, Ok(_)));
end_timer(timer);
}
}
}
Loading
Loading