arnaucube
arnaucube/plonky2-semaphorePublic Self-hosted repository
Add inline comments describing the usage of methods

and update the Semaphore link to the current one.
arnaucube git@arnaucube.com
Fri, 27 Sep 2024 07:53:11 +0200
commit

80994f96b790afbf1bfe617cb2b84122c47653b5

parent

dc9c32c93e5076e833ac8876afd3a75c511d6ada

5 files changed, 28 insertions(+), 11 deletions(-)

jump to
M README.md → README.md

@@ -1,4 +1,4 @@

-# Plonky2 implementation of the [Semaphore protocol](http://semaphore.appliedzkp.org/) +# Plonky2 implementation of the [Semaphore protocol](https://semaphore.pse.dev) Used as an example in the ZKHack Plonky2 presentation.

@@ -6,4 +6,4 @@ ## Compilation

```bash rustup override set nightly # Requires nightly Rust cargo test --release -```+```
M src/access_set.rs → src/access_set.rs

@@ -12,6 +12,7 @@

pub struct AccessSet(pub MerkleTree<F, PoseidonHash>); impl AccessSet { + // Verify the plonky2 proof of the given nullifier (in the signal structure) and topic. pub fn verify_signal( &self, topic: Digest,

@@ -34,6 +35,7 @@ public_inputs,

}) } + // Generate the plonky2 proof for the given key pair and topic. pub fn make_signal( &self, private_key: Digest,
M src/circuit.rs → src/circuit.rs

@@ -24,6 +24,19 @@ self.0.leaves.len().trailing_zeros() as usize

} pub fn semaphore_circuit(&self, builder: &mut CircuitBuilder<F, 2>) -> SemaphoreTargets { + // To create the circuit 'values', we call the `add_virtual_target` and it's variants (ie. + // `add_virtual_target_arr`, or `add_virtual_hash` which internally calls it for the 4 + // field values that conform the hash. + // The method `add_virtual_target` keeps an incremental index for each new virtual target + // created, and returns a new `VirtualTarget`, used for intermediate values in witness + // generation (which when needed can be copied to specific witness location (Wire)). + // + // The `register_public_input` and it's variants, append to the CircuitBuilder's + // `public_inputs` vector the given Target (either VirtualTarget or Wire). + // + // Notice that when created, the targets are not given any value, and they will be set later + // at the method `fill_semaphore_targets`. + // Register public inputs. let merkle_root = builder.add_virtual_hash(); builder.register_public_inputs(&merkle_root.elements);

@@ -65,6 +78,8 @@ public_key_index,

} } + // Fill the semaphore targets that we defined at the method `semaphore_circuit` with the given + // values. pub fn fill_semaphore_targets( &self, pw: &mut PartialWitness<F>,
M src/recursion.rs → src/recursion.rs

@@ -39,8 +39,13 @@ .chain(signal1.nullifier)

.chain(topic1) .collect(); + // `add_virtual_proof_with_pis` is an extended version of the `add_virtual_target`, but + // that takes care of adding all the values of the proof and the public inputs (pis). let proof_target0 = builder.add_virtual_proof_with_pis(&verifier_data.common); + // set the public inputs builder.register_public_inputs(&proof_target0.public_inputs); + // `set_proof_with_pis_target` is an extended version of the `set_target`, but that takes + // care of adding all the values of the proof and the public inputs. pw.set_proof_with_pis_target( &proof_target0, &ProofWithPublicInputs {

@@ -48,10 +53,12 @@ proof: signal0.proof,

public_inputs: public_inputs0, }, )?; + // add & set the verifier data let vd_target = builder.add_virtual_verifier_data(verifier_data.common.config.fri_config.cap_height); pw.set_verifier_data_target(&vd_target, &verifier_data.verifier_only)?; + // now, the same as we did with the proof0, with the proof1 related values: let proof_target1 = builder.add_virtual_proof_with_pis(&verifier_data.common); builder.register_public_inputs(&proof_target1.public_inputs); pw.set_proof_with_pis_target(

@@ -95,7 +102,6 @@ use plonky2::hash::merkle_tree::MerkleTree;

use plonky2::hash::poseidon::PoseidonHash; use plonky2::plonk::config::Hasher; use plonky2::plonk::proof::ProofWithPublicInputs; - use std::time::Instant; use crate::access_set::AccessSet; use crate::signal::{Digest, F};

@@ -117,24 +123,18 @@

// first proof let i0 = 12; let topic0 = F::rand_array(); - let start = Instant::now(); let (signal0, vd0) = access_set.make_signal(private_keys[i0], topic0, i0)?; - println!("generate proof: {:?}", start.elapsed()); access_set.verify_signal(topic0, signal0.clone(), &vd0)?; // second proof let i1 = 42; let topic1 = F::rand_array(); - let start = Instant::now(); let (signal1, vd1) = access_set.make_signal(private_keys[i1], topic1, i1)?; - println!("generate proof: {:?}", start.elapsed()); access_set.verify_signal(topic1, signal1.clone(), &vd1)?; // generate recursive proof - let start = Instant::now(); let (nullifier0, nullifier1, recursive_proof, vd2) = access_set.aggregate_signals(topic0, signal0, topic1, signal1, &vd0)?; - println!("aggregate_signals (recursive prove): {:?}", start.elapsed()); // verify recursive proof let public_inputs: Vec<F> = access_set

@@ -150,12 +150,10 @@ .chain(nullifier1)

.chain(topic1) .collect(); - let start = Instant::now(); vd2.verify(ProofWithPublicInputs { proof: recursive_proof, public_inputs, })?; - println!("verify recursive proof: {:?}", start.elapsed()); Ok(()) } }
M src/signal.rs → src/signal.rs

@@ -41,7 +41,9 @@

let i = 12; let topic = F::rand_array(); + // generate the plonky2 proof for the given key let (signal, vd) = access_set.make_signal(private_keys[i], topic, i)?; + // verify the plonky2 proof (contained in `signal` access_set.verify_signal(topic, signal, &vd) } }