| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177 |
- use std::iter;
- use halo2::dev::MockProver;
- use halo2_gadgets::{
- ecc::FixedPoints,
- primitives,
- primitives::{
- poseidon::{ConstantLength, P128Pow5T3},
- sinsemilla::S_PERSONALIZATION,
- },
- };
- use pasta_curves::{
- arithmetic::{CurveAffine, Field},
- group::{ff::PrimeFieldBits, Curve},
- pallas,
- };
- use rand::rngs::OsRng;
- use std::{collections::HashMap, fs::File, time::Instant};
- use darkfi::{
- crypto::{
- constants::{
- sinsemilla::{i2lebsp, MERKLE_CRH_PERSONALIZATION},
- OrchardFixedBases,
- },
- proof::{Proof, ProvingKey, VerifyingKey},
- util::pedersen_commitment_u64,
- },
- util::serial::Decodable,
- zk::vm,
- Error,
- };
- fn root(path: [pallas::Base; 32], leaf_pos: u32, leaf: pallas::Base) -> pallas::Base {
- let domain = primitives::sinsemilla::HashDomain::new(MERKLE_CRH_PERSONALIZATION);
- let pos_bool = i2lebsp::<32>(leaf_pos as u64);
- let mut node = leaf;
- for (l, (sibling, pos)) in path.iter().zip(pos_bool.iter()).enumerate() {
- let (left, right) = if *pos { (*sibling, node) } else { (node, *sibling) };
- let l_star = i2lebsp::<10>(l as u64);
- let left: Vec<_> = left.to_le_bits().iter().by_val().take(255).collect();
- let right: Vec<_> = right.to_le_bits().iter().by_val().take(255).collect();
- let mut message = l_star.to_vec();
- message.extend_from_slice(&left);
- message.extend_from_slice(&right);
- node = domain.hash(message.into_iter()).unwrap();
- }
- node
- }
- fn main() -> std::result::Result<(), Error> {
- // The number of rows in our circuit cannot exceed 2^k
- let k: u32 = 11;
- let start = Instant::now();
- let file = File::open("../proof/burn.zk.bin")?;
- let zkbin = vm::ZkBinary::decode(file)?;
- for contract_name in zkbin.contracts.keys() {
- println!("Loaded '{}' contract.", contract_name);
- }
- println!("Load time: [{:?}]", start.elapsed());
- let contract = &zkbin.contracts["Burn"];
- //contract.witness_base(...);
- //contract.witness_base(...);
- //contract.witness_base(...);
- let secret = pallas::Scalar::random(&mut OsRng);
- let serial = pallas::Base::random(&mut OsRng);
- let value = 110;
- let asset = 1;
- // Nullifier = poseidon(sinsemilla(secret_key), serial)
- let domain = primitives::sinsemilla::HashDomain::new(S_PERSONALIZATION);
- let bits_secretkey: Vec<bool> = secret.to_le_bits().iter().by_val().collect();
- let hashed_secret_key = domain.hash(iter::empty().chain(bits_secretkey)).unwrap();
- let nullifier = [hashed_secret_key, serial];
- let nullifier =
- primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
- // Public key derivation
- let public_key = OrchardFixedBases::SpendAuthG.generator() * secret;
- let coords = public_key.to_affine().coordinates().unwrap();
- // Construct Coin
- let mut coin = pallas::Base::zero();
- let coin_blind = pallas::Base::random(&mut OsRng);
- let messages = [
- [*coords.x(), *coords.y()],
- [pallas::Base::from(value), pallas::Base::from(asset)],
- [serial, coin_blind],
- ];
- for msg in messages.iter() {
- let hash = primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(*msg);
- coin += hash;
- }
- // Merkle root
- let leaf = pallas::Base::random(&mut OsRng);
- let leaf_pos = rand::random::<u32>();
- let path: Vec<_> = (0..32).map(|_| pallas::Base::random(&mut OsRng)).collect();
- let merkle_root = root(path.clone().try_into().unwrap(), leaf_pos, leaf);
- // Value and asset commitments
- let value_blind = pallas::Scalar::random(&mut OsRng);
- let asset_blind = pallas::Scalar::random(&mut OsRng);
- let value_commit = pedersen_commitment_u64(value, value_blind);
- let asset_commit = pedersen_commitment_u64(asset, asset_blind);
- let value_coords = value_commit.to_affine().coordinates().unwrap();
- let asset_coords = asset_commit.to_affine().coordinates().unwrap();
- // Derive signature public key from signature secret key
- let sig_secret = pallas::Scalar::random(&mut OsRng);
- let sig_pubkey = OrchardFixedBases::SpendAuthG.generator() * sig_secret;
- let sig_coords = sig_pubkey.to_affine().coordinates().unwrap();
- let public_inputs = vec![
- nullifier,
- merkle_root,
- *value_coords.x(),
- *value_coords.y(),
- *asset_coords.x(),
- *asset_coords.y(),
- *sig_coords.x(),
- *sig_coords.y(),
- ];
- //
- let mut const_fixed_points = HashMap::new();
- const_fixed_points.insert("VALUE_COMMIT_VALUE".to_string(), OrchardFixedBases::ValueCommitV);
- const_fixed_points.insert("VALUE_COMMIT_RANDOM".to_string(), OrchardFixedBases::ValueCommitR);
- const_fixed_points.insert("SPEND_AUTH_G".to_string(), OrchardFixedBases::SpendAuthG);
- let mut circuit = vm::ZkCircuit::new(const_fixed_points, &zkbin.constants, contract);
- let empty_circuit = circuit.clone();
- circuit.witness_base("secret", hashed_secret_key)?;
- circuit.witness_base("serial", serial)?;
- circuit.witness_merkle_path("path", leaf_pos, path.try_into().unwrap())?;
- circuit.witness_base("leaf", leaf)?;
- circuit.witness_base("value", pallas::Base::from(value))?;
- circuit.witness_base("asset", pallas::Base::from(asset))?;
- circuit.witness_scalar("value_blind", value_blind)?;
- circuit.witness_scalar("asset_blind", asset_blind)?;
- circuit.witness_scalar("sig_secret", sig_secret)?;
- // Valid MockProver
- let prover = MockProver::run(k, &circuit, vec![public_inputs.clone()]).unwrap();
- assert_eq!(prover.verify(), Ok(()));
- // Actual ZK proof
- let start = Instant::now();
- let vk = VerifyingKey::build(k, empty_circuit.clone());
- let pk = ProvingKey::build(k, empty_circuit.clone());
- println!("\nSetup: [{:?}]", start.elapsed());
- let start = Instant::now();
- let proof = Proof::create(&pk, &[circuit], &public_inputs).unwrap();
- println!("Prove: [{:?}]", start.elapsed());
- let start = Instant::now();
- assert!(proof.verify(&vk, &public_inputs).is_ok());
- println!("Verify: [{:?}]", start.elapsed());
- Ok(())
- }
|