1use ark_crypto_primitives::{Error, SNARK};
2use ark_ec::PairingEngine;
3use ark_ff::fields::PrimeField;
4use ark_groth16::{Groth16, Proof, ProvingKey, VerifyingKey};
5use ark_relations::r1cs::ConstraintSynthesizer;
6use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
7use ark_std::{
8 collections::BTreeMap,
9 rand::{CryptoRng, RngCore},
10 vec::Vec,
11};
12use arkworks_native_gadgets::{
13 merkle_tree::{Path, SparseMerkleTree},
14 poseidon::{sbox::PoseidonSbox, FieldHasher, PoseidonParameters},
15};
16use arkworks_utils::{
17 bytes_matrix_to_f, bytes_vec_to_f, poseidon_params::setup_poseidon_params, Curve,
18};
19use tiny_keccak::{Hasher, Keccak};
20
21pub struct VAnchorLeaf {
22 pub chain_id_bytes: Vec<u8>,
23 pub amount: u128,
24 pub public_key_bytes: Vec<u8>,
25 pub blinding_bytes: Vec<u8>,
26 pub index: u32,
27 pub private_key_bytes: Vec<u8>,
28 pub nullifier_bytes: Vec<u8>,
29 pub leaf_bytes: Vec<u8>,
30 pub nullifier_hash_bytes: Vec<u8>,
31}
32
33pub struct Leaf {
34 pub chain_id_bytes: Option<Vec<u8>>,
35 pub secret_bytes: Vec<u8>,
36 pub nullifier_bytes: Vec<u8>,
37 pub leaf_bytes: Vec<u8>,
38 pub nullifier_hash_bytes: Vec<u8>,
39}
40
41pub struct VAnchorProof {
42 pub proof: Vec<u8>,
43 pub public_inputs_raw: Vec<Vec<u8>>,
44}
45
46pub struct AnchorProof {
47 pub proof: Vec<u8>,
48 pub leaf_raw: Vec<u8>,
49 pub nullifier_hash_raw: Vec<u8>,
50 pub roots_raw: Vec<Vec<u8>>,
51 pub public_inputs_raw: Vec<Vec<u8>>,
52}
53
54pub struct MixerProof {
55 pub proof: Vec<u8>,
56 pub leaf_raw: Vec<u8>,
57 pub nullifier_hash_raw: Vec<u8>,
58 pub root_raw: Vec<u8>,
59 pub public_inputs_raw: Vec<Vec<u8>>,
60}
61
62pub struct Keys {
63 pub pk: Vec<u8>,
64 pub vk: Vec<u8>,
65}
66
67pub fn setup_keys<E: PairingEngine, R: RngCore + CryptoRng, C: ConstraintSynthesizer<E::Fr>>(
68 circuit: C,
69 rng: &mut R,
70) -> Result<(Vec<u8>, Vec<u8>), Error> {
71 let (pk, vk) = Groth16::<E>::circuit_specific_setup(circuit, rng)?;
72
73 let mut pk_bytes = Vec::new();
74 let mut vk_bytes = Vec::new();
75 pk.serialize(&mut pk_bytes)?;
76 vk.serialize(&mut vk_bytes)?;
77 Ok((pk_bytes, vk_bytes))
78}
79
80pub fn setup_keys_unchecked<
81 E: PairingEngine,
82 R: RngCore + CryptoRng,
83 C: ConstraintSynthesizer<E::Fr>,
84>(
85 circuit: C,
86 rng: &mut R,
87) -> Result<(Vec<u8>, Vec<u8>), Error> {
88 let (pk, vk) = Groth16::<E>::circuit_specific_setup(circuit, rng)?;
89
90 let mut pk_bytes = Vec::new();
91 let mut vk_bytes = Vec::new();
92 pk.serialize_unchecked(&mut pk_bytes)?;
93 vk.serialize_unchecked(&mut vk_bytes)?;
94 Ok((pk_bytes, vk_bytes))
95}
96
97pub fn prove<E: PairingEngine, R: RngCore + CryptoRng, C: ConstraintSynthesizer<E::Fr>>(
98 circuit: C,
99 pk_bytes: &[u8],
100 rng: &mut R,
101) -> Result<Vec<u8>, Error> {
102 let pk = ProvingKey::<E>::deserialize(pk_bytes)?;
103
104 let proof = Groth16::prove(&pk, circuit, rng)?;
105 let mut proof_bytes = Vec::new();
106 proof.serialize(&mut proof_bytes)?;
107 Ok(proof_bytes)
108}
109
110pub fn prove_unchecked<
111 E: PairingEngine,
112 R: RngCore + CryptoRng,
113 C: ConstraintSynthesizer<E::Fr>,
114>(
115 circuit: C,
116 pk_unchecked_bytes: &[u8],
117 rng: &mut R,
118) -> Result<Vec<u8>, Error> {
119 let pk = ProvingKey::<E>::deserialize_unchecked(pk_unchecked_bytes)?;
120
121 let proof = Groth16::prove(&pk, circuit, rng)?;
122 let mut proof_bytes = Vec::new();
123 proof.serialize(&mut proof_bytes)?;
124 Ok(proof_bytes)
125}
126
127pub fn verify<E: PairingEngine>(
128 public_inputs: &[E::Fr],
129 vk_bytes: &[u8],
130 proof: &[u8],
131) -> Result<bool, Error> {
132 let vk = VerifyingKey::<E>::deserialize(vk_bytes)?;
133 let proof = Proof::<E>::deserialize(proof)?;
134 verify_groth16(&vk, &public_inputs, &proof)
135}
136
137pub fn verify_unchecked<E: PairingEngine>(
138 public_inputs: &[E::Fr],
139 vk_unchecked_bytes: &[u8],
140 proof: &[u8],
141) -> Result<bool, Error> {
142 let vk = VerifyingKey::<E>::deserialize_unchecked(vk_unchecked_bytes)?;
143 let proof = Proof::<E>::deserialize(proof)?;
144 verify_groth16(&vk, &public_inputs, &proof)
145}
146
147pub fn verify_unchecked_raw<E: PairingEngine>(
148 public_inputs: &[Vec<u8>],
149 vk_unchecked_bytes: &[u8],
150 proof: &[u8],
151) -> Result<bool, Error> {
152 let pub_ins: Vec<E::Fr> = public_inputs
153 .iter()
154 .map(|x| E::Fr::from_be_bytes_mod_order(&x))
155 .collect();
156 let vk = VerifyingKey::<E>::deserialize_unchecked(vk_unchecked_bytes)?;
157 let proof = Proof::<E>::deserialize(proof)?;
158 verify_groth16(&vk, &pub_ins, &proof)
159}
160
161pub fn verify_groth16<E: PairingEngine>(
162 vk: &VerifyingKey<E>,
163 public_inputs: &[E::Fr],
164 proof: &Proof<E>,
165) -> Result<bool, Error> {
166 let res = Groth16::<E>::verify(vk, public_inputs, proof)?;
167 Ok(res)
168}
169
170pub fn keccak_256(input: &[u8]) -> Vec<u8> {
171 let mut keccak = Keccak::v256();
172 keccak.update(&input);
173
174 let mut output = [0u8; 32];
175 keccak.finalize(&mut output);
176 output.to_vec()
177}
178
179pub type SMT<F, H, const HEIGHT: usize> = SparseMerkleTree<F, H, HEIGHT>;
180
181pub fn create_merkle_tree<F: PrimeField, H: FieldHasher<F>, const N: usize>(
182 hasher: &H,
183 leaves: &[F],
184 default_leaf: &[u8],
185) -> SparseMerkleTree<F, H, N> {
186 let pairs: BTreeMap<u32, F> = leaves
187 .iter()
188 .enumerate()
189 .map(|(i, l)| (i as u32, *l))
190 .collect();
191 let smt = SparseMerkleTree::<F, H, N>::new(&pairs, hasher, default_leaf).unwrap();
192
193 smt
194}
195
196pub fn setup_tree_and_create_path<F: PrimeField, H: FieldHasher<F>, const HEIGHT: usize>(
197 hasher: &H,
198 leaves: &[F],
199 index: u64,
200 default_leaf: &[u8],
201) -> Result<(SMT<F, H, HEIGHT>, Path<F, H, HEIGHT>), Error> {
202 let smt = create_merkle_tree::<F, H, HEIGHT>(hasher, leaves, default_leaf);
204 let path = smt.generate_membership_proof(index);
206 Ok((smt, path))
207}
208
209pub fn setup_params<F: PrimeField>(curve: Curve, exp: i8, width: u8) -> PoseidonParameters<F> {
210 let pos_data = setup_poseidon_params(curve, exp, width).unwrap();
211
212 let mds_f = bytes_matrix_to_f(&pos_data.mds);
213 let rounds_f = bytes_vec_to_f(&pos_data.rounds);
214
215 let pos = PoseidonParameters {
216 mds_matrix: mds_f,
217 round_keys: rounds_f,
218 full_rounds: pos_data.full_rounds,
219 partial_rounds: pos_data.partial_rounds,
220 sbox: PoseidonSbox(pos_data.exp),
221 width: pos_data.width,
222 };
223
224 pos
225}