vm2_burn.rs 6.9 KB

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