From 7b37f07c062a39be1f1956e66f2aecb801cba754 Mon Sep 17 00:00:00 2001 From: shreyas-londhe Date: Fri, 3 May 2024 18:03:00 +0530 Subject: [PATCH] feat: stealth drop circuit impl --- .gitignore | 2 + circuit/Cargo.toml | 9 ++++ circuit/src/lib.rs | 101 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 112 insertions(+) create mode 100644 .gitignore create mode 100644 circuit/Cargo.toml create mode 100644 circuit/src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..972b0c4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**/target +**/Cargo.lock diff --git a/circuit/Cargo.toml b/circuit/Cargo.toml new file mode 100644 index 0000000..f2bac0c --- /dev/null +++ b/circuit/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "circuit" +version = "0.1.0" +edition = "2021" + +[dependencies] +halo2-base = { git = "https://github.com/shreyas-londhe/halo2-lib.git", branch = "feat/secp256k1-hash2curve-poseidon", default-features = false, features = ["halo2-axiom", "test-utils"] } +halo2-ecc = { git = "https://github.com/shreyas-londhe/halo2-lib.git", branch = "feat/secp256k1-hash2curve-poseidon", default-features = false, features = ["halo2-axiom"] } +plume-halo2 = { git = "https://github.com/shreyas-londhe/zk-nullifier-sig.git", branch = "feat/plume-halo2" } \ No newline at end of file diff --git a/circuit/src/lib.rs b/circuit/src/lib.rs new file mode 100644 index 0000000..bad3718 --- /dev/null +++ b/circuit/src/lib.rs @@ -0,0 +1,101 @@ +use halo2_base::{ + gates::{ GateChip, GateInstructions }, + poseidon::hasher::PoseidonHasher, + utils::BigPrimeField, + AssignedValue, + Context, +}; +use halo2_ecc::{ bigint::ProperCrtUint, ecc::EcPoint, fields::FieldChip, secp256k1::Secp256k1Chip }; +use plume_halo2::plume::{ verify_plume, PlumeInput }; + +pub struct StealthDropInput { + // Public + pub merkle_root: AssignedValue, + pub nullifier: EcPoint>, + pub s: ProperCrtUint, + + // Private + pub merkle_proof: Vec>, + pub merkle_proof_path: Vec>, + pub c: ProperCrtUint, + pub message: Vec>, + pub public_key: EcPoint>, +} + +pub fn dual_mux( + ctx: &mut Context, + gate: &GateChip, + a: &AssignedValue, + b: &AssignedValue, + switch: &AssignedValue +) -> [AssignedValue; 2] { + gate.assert_bit(ctx, *switch); + + let a_sub_b = gate.sub(ctx, *a, *b); + let b_sub_a = gate.sub(ctx, *b, *a); + + let left = gate.mul_add(ctx, a_sub_b, *switch, *b); // left = (a-b)*s + b; + let right = gate.mul_add(ctx, b_sub_a, *switch, *a); // right = (b-a)*s + a; + + [left, right] +} + +pub fn verify_membership_proof( + ctx: &mut Context, + gate: &GateChip, + hasher: &PoseidonHasher, + root: &AssignedValue, + leaf: &AssignedValue, + proof: &[AssignedValue], + helper: &[AssignedValue] +) { + let mut computed_hash = ctx.load_witness(*leaf.value()); + + for (proof_element, helper) in proof.iter().zip(helper.iter()) { + let inp = dual_mux(ctx, gate, &computed_hash, proof_element, helper); + computed_hash = hasher.hash_fix_len_array(ctx, gate, &inp); + } + ctx.constrain_equal(&computed_hash, root); +} + +pub fn prove_stealth_drop( + ctx: &mut Context, + secp256k1_chip: &Secp256k1Chip<'_, F>, + poseidon_hasher: &PoseidonHasher, + fixed_window_bits: usize, + var_window_bits: usize, + input: StealthDropInput +) { + let base_chip = secp256k1_chip.field_chip(); + let gate = base_chip.gate(); + + let leaf_preimage = [input.public_key.x().limbs(), input.public_key.y().limbs()].concat(); + let leaf = poseidon_hasher.hash_fix_len_array(ctx, gate, &leaf_preimage[..]); + + verify_membership_proof( + ctx, + gate, + &poseidon_hasher, + &input.merkle_root, + &leaf, + &input.merkle_proof, + &input.merkle_proof_path + ); + + let plume_input = PlumeInput { + nullifier: input.nullifier, + s: input.s, + c: input.c, + pk: input.public_key, + m: input.message, + }; + + verify_plume( + ctx, + secp256k1_chip, + poseidon_hasher, + fixed_window_bits, + var_window_bits, + plume_input + ) +}