vm_burn.rs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. use std::iter;
  2. use halo2::dev::MockProver;
  3. use halo2_gadgets::{
  4. ecc::FixedPoints,
  5. primitives,
  6. primitives::{
  7. poseidon::{ConstantLength, P128Pow5T3},
  8. sinsemilla::S_PERSONALIZATION,
  9. },
  10. };
  11. use pasta_curves::{
  12. arithmetic::{CurveAffine, Field},
  13. group::{ff::PrimeFieldBits, Curve},
  14. pallas,
  15. };
  16. use rand::rngs::OsRng;
  17. use std::{collections::HashMap, fs::File, time::Instant};
  18. use darkfi::{
  19. crypto::{
  20. constants::{
  21. sinsemilla::{i2lebsp, MERKLE_CRH_PERSONALIZATION},
  22. OrchardFixedBases,
  23. },
  24. proof::{Proof, ProvingKey, VerifyingKey},
  25. util::pedersen_commitment_u64,
  26. },
  27. util::serial::Decodable,
  28. zk::vm,
  29. Error,
  30. };
  31. fn root(path: [pallas::Base; 32], leaf_pos: u32, leaf: pallas::Base) -> pallas::Base {
  32. let domain = primitives::sinsemilla::HashDomain::new(MERKLE_CRH_PERSONALIZATION);
  33. let pos_bool = i2lebsp::<32>(leaf_pos as u64);
  34. let mut node = leaf;
  35. for (l, (sibling, pos)) in path.iter().zip(pos_bool.iter()).enumerate() {
  36. let (left, right) = if *pos { (*sibling, node) } else { (node, *sibling) };
  37. let l_star = i2lebsp::<10>(l as u64);
  38. let left: Vec<_> = left.to_le_bits().iter().by_val().take(255).collect();
  39. let right: Vec<_> = right.to_le_bits().iter().by_val().take(255).collect();
  40. let mut message = l_star.to_vec();
  41. message.extend_from_slice(&left);
  42. message.extend_from_slice(&right);
  43. node = domain.hash(message.into_iter()).unwrap();
  44. }
  45. node
  46. }
  47. fn main() -> std::result::Result<(), Error> {
  48. // The number of rows in our circuit cannot exceed 2^k
  49. let k: u32 = 11;
  50. let start = Instant::now();
  51. let file = File::open("../proof/burn.zk.bin")?;
  52. let zkbin = vm::ZkBinary::decode(file)?;
  53. for contract_name in zkbin.contracts.keys() {
  54. println!("Loaded '{}' contract.", contract_name);
  55. }
  56. println!("Load time: [{:?}]", start.elapsed());
  57. let contract = &zkbin.contracts["Burn"];
  58. //contract.witness_base(...);
  59. //contract.witness_base(...);
  60. //contract.witness_base(...);
  61. let secret = pallas::Scalar::random(&mut OsRng);
  62. let serial = pallas::Base::random(&mut OsRng);
  63. let value = 110;
  64. let asset = 1;
  65. // Nullifier = poseidon(sinsemilla(secret_key), serial)
  66. let domain = primitives::sinsemilla::HashDomain::new(S_PERSONALIZATION);
  67. let bits_secretkey: Vec<bool> = secret.to_le_bits().iter().by_val().collect();
  68. let hashed_secret_key = domain.hash(iter::empty().chain(bits_secretkey)).unwrap();
  69. let nullifier = [hashed_secret_key, serial];
  70. let nullifier =
  71. primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(nullifier);
  72. // Public key derivation
  73. let public_key = OrchardFixedBases::SpendAuthG.generator() * secret;
  74. let coords = public_key.to_affine().coordinates().unwrap();
  75. // Construct Coin
  76. let mut coin = pallas::Base::zero();
  77. let coin_blind = pallas::Base::random(&mut OsRng);
  78. let messages = [
  79. [*coords.x(), *coords.y()],
  80. [pallas::Base::from(value), pallas::Base::from(asset)],
  81. [serial, coin_blind],
  82. ];
  83. for msg in messages.iter() {
  84. let hash = primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<2>).hash(*msg);
  85. coin += hash;
  86. }
  87. // Merkle root
  88. let leaf = pallas::Base::random(&mut OsRng);
  89. let leaf_pos = rand::random::<u32>();
  90. let path: Vec<_> = (0..32).map(|_| pallas::Base::random(&mut OsRng)).collect();
  91. let merkle_root = root(path.clone().try_into().unwrap(), leaf_pos, leaf);
  92. // Value and asset commitments
  93. let value_blind = pallas::Scalar::random(&mut OsRng);
  94. let asset_blind = pallas::Scalar::random(&mut OsRng);
  95. let value_commit = pedersen_commitment_u64(value, value_blind);
  96. let asset_commit = pedersen_commitment_u64(asset, asset_blind);
  97. let value_coords = value_commit.to_affine().coordinates().unwrap();
  98. let asset_coords = asset_commit.to_affine().coordinates().unwrap();
  99. // Derive signature public key from signature secret key
  100. let sig_secret = pallas::Scalar::random(&mut OsRng);
  101. let sig_pubkey = OrchardFixedBases::SpendAuthG.generator() * sig_secret;
  102. let sig_coords = sig_pubkey.to_affine().coordinates().unwrap();
  103. let public_inputs = vec![
  104. nullifier,
  105. merkle_root,
  106. *value_coords.x(),
  107. *value_coords.y(),
  108. *asset_coords.x(),
  109. *asset_coords.y(),
  110. *sig_coords.x(),
  111. *sig_coords.y(),
  112. ];
  113. //
  114. let mut const_fixed_points = HashMap::new();
  115. const_fixed_points.insert("VALUE_COMMIT_VALUE".to_string(), OrchardFixedBases::ValueCommitV);
  116. const_fixed_points.insert("VALUE_COMMIT_RANDOM".to_string(), OrchardFixedBases::ValueCommitR);
  117. const_fixed_points.insert("SPEND_AUTH_G".to_string(), OrchardFixedBases::SpendAuthG);
  118. let mut circuit = vm::ZkCircuit::new(const_fixed_points, &zkbin.constants, contract);
  119. let empty_circuit = circuit.clone();
  120. circuit.witness_base("secret", hashed_secret_key)?;
  121. circuit.witness_base("serial", serial)?;
  122. circuit.witness_merkle_path("path", leaf_pos, path.try_into().unwrap())?;
  123. circuit.witness_base("leaf", leaf)?;
  124. circuit.witness_base("value", pallas::Base::from(value))?;
  125. circuit.witness_base("asset", pallas::Base::from(asset))?;
  126. circuit.witness_scalar("value_blind", value_blind)?;
  127. circuit.witness_scalar("asset_blind", asset_blind)?;
  128. circuit.witness_scalar("sig_secret", sig_secret)?;
  129. // Valid MockProver
  130. let prover = MockProver::run(k, &circuit, vec![public_inputs.clone()]).unwrap();
  131. assert_eq!(prover.verify(), Ok(()));
  132. // Actual ZK proof
  133. let start = Instant::now();
  134. let vk = VerifyingKey::build(k, empty_circuit.clone());
  135. let pk = ProvingKey::build(k, empty_circuit.clone());
  136. println!("\nSetup: [{:?}]", start.elapsed());
  137. let start = Instant::now();
  138. let proof = Proof::create(&pk, &[circuit], &public_inputs).unwrap();
  139. println!("Prove: [{:?}]", start.elapsed());
  140. let start = Instant::now();
  141. assert!(proof.verify(&vk, &public_inputs).is_ok());
  142. println!("Verify: [{:?}]", start.elapsed());
  143. Ok(())
  144. }