| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244 |
- use bellman::gadgets::multipack;
- use bellman::groth16;
- use bitvec::{order::Lsb0, view::AsBits};
- use blake2s_simd::Params as Blake2sParams;
- use bls12_381::Bls12;
- use ff::{Field, PrimeField};
- use group::{Curve, GroupEncoding};
- use sapvi::circuit::spend_contract::SpendContract;
- // This thing is nasty lol
- pub fn merkle_hash(
- depth: usize,
- lhs: &bls12_381::Scalar,
- rhs: &bls12_381::Scalar,
- ) -> bls12_381::Scalar {
- let lhs = {
- let mut tmp = [false; 256];
- for (a, b) in tmp.iter_mut().zip(lhs.to_repr().as_bits::<Lsb0>()) {
- *a = *b;
- }
- tmp
- };
- let rhs = {
- let mut tmp = [false; 256];
- for (a, b) in tmp.iter_mut().zip(rhs.to_repr().as_bits::<Lsb0>()) {
- *a = *b;
- }
- tmp
- };
- jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
- zcash_primitives::pedersen_hash::Personalization::MerkleTree(depth),
- lhs.iter()
- .copied()
- .take(bls12_381::Scalar::NUM_BITS as usize)
- .chain(
- rhs.iter()
- .copied()
- .take(bls12_381::Scalar::NUM_BITS as usize),
- ),
- ))
- .to_affine()
- .get_u()
- }
- struct SpendRevealedValues {
- value_commit: jubjub::SubgroupPoint,
- nullifier: [u8; 32],
- // This should not be here, we just have it for debugging
- //coin: [u8; 32],
- merkle_root: bls12_381::Scalar,
- }
- impl SpendRevealedValues {
- fn compute(
- value: u64,
- randomness_value: &jubjub::Fr,
- serial: &jubjub::Fr,
- randomness_coin: &jubjub::Fr,
- secret: &jubjub::Fr,
- merkle_path: &[(bls12_381::Scalar, bool)],
- ) -> Self {
- let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
- * jubjub::Fr::from(value))
- + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
- * randomness_value);
- let mut nullifier = [0; 32];
- nullifier.copy_from_slice(
- Blake2sParams::new()
- .hash_length(32)
- .personal(zcash_primitives::constants::PRF_NF_PERSONALIZATION)
- .to_state()
- .update(&secret.to_bytes())
- .update(&serial.to_bytes())
- .finalize()
- .as_bytes(),
- );
- let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
- let mut coin = [0; 32];
- coin.copy_from_slice(
- Blake2sParams::new()
- .hash_length(32)
- .personal(zcash_primitives::constants::CRH_IVK_PERSONALIZATION)
- .to_state()
- .update(&public.to_bytes())
- .update(&value.to_le_bytes())
- .update(&serial.to_bytes())
- .update(&randomness_coin.to_bytes())
- .finalize()
- .as_bytes(),
- );
- let merkle_root =
- jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
- zcash_primitives::pedersen_hash::Personalization::NoteCommitment,
- multipack::bytes_to_bits_le(&coin),
- ));
- let affine = merkle_root.to_affine();
- let mut merkle_root = affine.get_u();
- for (i, (right, is_right)) in merkle_path.iter().enumerate() {
- if *is_right {
- merkle_root = merkle_hash(i, &right, &merkle_root);
- } else {
- merkle_root = merkle_hash(i, &merkle_root, &right);
- }
- }
- SpendRevealedValues {
- value_commit,
- nullifier,
- merkle_root,
- }
- }
- fn make_outputs(&self) -> [bls12_381::Scalar; 5] {
- let mut public_input = [bls12_381::Scalar::zero(); 5];
- // CV
- {
- let result = jubjub::ExtendedPoint::from(self.value_commit);
- let affine = result.to_affine();
- //let (u, v) = (affine.get_u(), affine.get_v());
- let u = affine.get_u();
- let v = affine.get_v();
- public_input[0] = u;
- public_input[1] = v;
- }
- // NF
- {
- // Pack the hash as inputs for proof verification.
- let hash = multipack::bytes_to_bits_le(&self.nullifier);
- let hash = multipack::compute_multipacking(&hash);
- // There are 2 chunks for a blake hash
- assert_eq!(hash.len(), 2);
- public_input[2] = hash[0];
- public_input[3] = hash[1];
- }
- // Not revealed. We leave this code here for debug
- // Coin
- /*{
- // Pack the hash as inputs for proof verification.
- let hash = multipack::bytes_to_bits_le(&self.coin);
- let hash = multipack::compute_multipacking(&hash);
- // There are 2 chunks for a blake hash
- assert_eq!(hash.len(), 2);
- public_input[4] = hash[0];
- public_input[5] = hash[1];
- }*/
- public_input[4] = self.merkle_root;
- public_input
- }
- }
- fn main() {
- use rand::rngs::OsRng;
- use std::time::Instant;
- let value = 110;
- let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
- let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
- let randomness_coin: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
- let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
- let merkle_path = [
- (bls12_381::Scalar::random(&mut OsRng), true),
- (bls12_381::Scalar::random(&mut OsRng), false),
- (bls12_381::Scalar::random(&mut OsRng), true),
- (bls12_381::Scalar::random(&mut OsRng), true),
- ];
- let revealed = SpendRevealedValues::compute(
- value,
- &randomness_value,
- &serial,
- &randomness_coin,
- &secret,
- &merkle_path,
- );
- let start = Instant::now();
- let params = {
- let c = SpendContract {
- value: None,
- randomness_value: None,
- serial: None,
- randomness_coin: None,
- secret: None,
- branch_0: None,
- is_right_0: None,
- branch_1: None,
- is_right_1: None,
- branch_2: None,
- is_right_2: None,
- branch_3: None,
- is_right_3: None,
- };
- groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
- };
- let pvk = groth16::prepare_verifying_key(¶ms.vk);
- println!("Setup: [{:?}]", start.elapsed());
- let c = SpendContract {
- value: Some(value),
- randomness_value: Some(randomness_value),
- serial: Some(serial),
- randomness_coin: Some(randomness_coin),
- secret: Some(secret),
- branch_0: Some(merkle_path[0].0),
- is_right_0: Some(merkle_path[0].1),
- branch_1: Some(merkle_path[1].0),
- is_right_1: Some(merkle_path[1].1),
- branch_2: Some(merkle_path[2].0),
- is_right_2: Some(merkle_path[2].1),
- branch_3: Some(merkle_path[3].0),
- is_right_3: Some(merkle_path[3].1),
- };
- let start = Instant::now();
- let proof = groth16::create_random_proof(c, ¶ms, &mut OsRng).unwrap();
- println!("Prove: [{:?}]", start.elapsed());
- let public_input = revealed.make_outputs();
- let start = Instant::now();
- assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
- println!("Verify: [{:?}]", start.elapsed());
- }
|