arnaucube
arnaucube/plonky2-semaphorePublic Self-hosted repository
plonky2-semaphore/src/circuit.rs
src/circuit.rsRaw
  1use anyhow::Result;
  2use plonky2::field::types::Field;
  3use plonky2::hash::hash_types::HashOutTarget;
  4use plonky2::hash::merkle_proofs::MerkleProofTarget;
  5use plonky2::hash::poseidon::PoseidonHash;
  6use plonky2::iop::target::Target;
  7use plonky2::iop::witness::{PartialWitness, WitnessWrite};
  8use plonky2::plonk::circuit_builder::CircuitBuilder;
  9
 10use crate::access_set::AccessSet;
 11use crate::signal::{Digest, F};
 12
 13pub struct SemaphoreTargets {
 14    merkle_root: HashOutTarget,
 15    topic: [Target; 4],
 16    merkle_proof: MerkleProofTarget,
 17    private_key: [Target; 4],
 18    public_key_index: Target,
 19}
 20
 21impl AccessSet {
 22    pub fn tree_height(&self) -> usize {
 23        self.0.leaves.len().trailing_zeros() as usize
 24    }
 25
 26    pub fn semaphore_circuit(&self, builder: &mut CircuitBuilder<F, 2>) -> SemaphoreTargets {
 27        // Register public inputs.
 28        let merkle_root = builder.add_virtual_hash();
 29        builder.register_public_inputs(&merkle_root.elements);
 30        let nullifier = builder.add_virtual_hash();
 31        builder.register_public_inputs(&nullifier.elements);
 32        let topic: [Target; 4] = builder.add_virtual_targets(4).try_into().unwrap();
 33        builder.register_public_inputs(&topic);
 34
 35        // Merkle proof
 36        let merkle_proof = MerkleProofTarget {
 37            siblings: builder.add_virtual_hashes(self.tree_height()),
 38        };
 39
 40        // Verify public key Merkle proof.
 41        let private_key: [Target; 4] = builder.add_virtual_targets(4).try_into().unwrap();
 42        let public_key_index = builder.add_virtual_target();
 43        let public_key_index_bits = builder.split_le(public_key_index, self.tree_height());
 44        let zero = builder.zero();
 45        builder.verify_merkle_proof::<PoseidonHash>(
 46            [private_key, [zero; 4]].concat(),
 47            &public_key_index_bits,
 48            merkle_root,
 49            &merkle_proof,
 50        );
 51
 52        // Check nullifier.
 53        let should_be_nullifier =
 54            builder.hash_n_to_hash_no_pad::<PoseidonHash>([private_key, topic].concat());
 55        for i in 0..4 {
 56            builder.connect(nullifier.elements[i], should_be_nullifier.elements[i]);
 57        }
 58
 59        SemaphoreTargets {
 60            merkle_root,
 61            topic,
 62            merkle_proof,
 63            private_key,
 64            public_key_index,
 65        }
 66    }
 67
 68    pub fn fill_semaphore_targets(
 69        &self,
 70        pw: &mut PartialWitness<F>,
 71        private_key: Digest,
 72        topic: Digest,
 73        public_key_index: usize,
 74        targets: SemaphoreTargets,
 75    ) -> Result<()> {
 76        let SemaphoreTargets {
 77            merkle_root,
 78            topic: topic_target,
 79            merkle_proof: merkle_proof_target,
 80            private_key: private_key_target,
 81            public_key_index: public_key_index_target,
 82        } = targets;
 83
 84        pw.set_hash_target(merkle_root, self.0.cap.0[0])?;
 85        pw.set_target_arr(&private_key_target, &private_key)?;
 86        pw.set_target_arr(&topic_target, &topic)?;
 87        pw.set_target(
 88            public_key_index_target,
 89            F::from_canonical_usize(public_key_index),
 90        )?;
 91
 92        let merkle_proof = self.0.prove(public_key_index);
 93        for (ht, h) in merkle_proof_target
 94            .siblings
 95            .into_iter()
 96            .zip(merkle_proof.siblings)
 97        {
 98            pw.set_hash_target(ht, h)?;
 99        }
100        Ok(())
101    }
102}