zec.rs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. use bellman::groth16::*;
  2. use bls12_381::Bls12;
  3. use ff::{Field, PrimeField};
  4. use rand::rngs::OsRng;
  5. use rand_core::RngCore;
  6. use std::fs::File;
  7. use std::time::Instant;
  8. use zcash_primitives::{
  9. merkle_tree::{CommitmentTree, IncrementalWitness},
  10. note_encryption::{Memo, SaplingNoteEncryption},
  11. primitives::{Diversifier, Note, ProofGenerationKey, Rseed, ValueCommitment},
  12. redjubjub::PrivateKey,
  13. sapling::{spend_sig, Node},
  14. transaction::components::{Amount, GROTH_PROOF_SIZE},
  15. zip32::{ChildIndex, ExtendedFullViewingKey, ExtendedSpendingKey},
  16. };
  17. use zcash_proofs::{
  18. circuit::sapling::{Output, Spend},
  19. sapling::{SaplingProvingContext, SaplingVerificationContext},
  20. };
  21. const TREE_DEPTH: usize = 32;
  22. type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
  23. fn generate_params() -> Result<()> {
  24. let mut rng = OsRng;
  25. println!("Creating spend parameters...");
  26. let start = Instant::now();
  27. let spend_params = generate_random_parameters::<Bls12, _, _>(
  28. Spend {
  29. value_commitment: None,
  30. proof_generation_key: None,
  31. payment_address: None,
  32. commitment_randomness: None,
  33. ar: None,
  34. auth_path: vec![None; TREE_DEPTH],
  35. anchor: None,
  36. },
  37. &mut rng,
  38. )
  39. .unwrap();
  40. let buffer = File::create("spend.params")?;
  41. spend_params.write(buffer)?;
  42. println!("Finished spend paramgen [{:?}]", start.elapsed());
  43. println!("Creating output parameters...");
  44. let start = Instant::now();
  45. let output_params = generate_random_parameters::<Bls12, _, _>(
  46. Output {
  47. value_commitment: None,
  48. payment_address: None,
  49. commitment_randomness: None,
  50. esk: None,
  51. },
  52. &mut rng,
  53. )
  54. .unwrap();
  55. let buffer = File::create("output.params")?;
  56. output_params.write(buffer)?;
  57. println!("Finished output paramgen [{:?}]", start.elapsed());
  58. Ok(())
  59. }
  60. fn main() -> Result<()> {
  61. //generate_params()?;
  62. let mut rng = OsRng;
  63. println!("Reading output parameters from file...");
  64. let start = Instant::now();
  65. let buffer = File::open("output.params")?;
  66. let output_params = Parameters::<Bls12>::read(buffer, false)?;
  67. let output_vk = prepare_verifying_key(&output_params.vk);
  68. println!("Finished load output params [{:?}]", start.elapsed());
  69. let mut ctx = SaplingProvingContext::new();
  70. let start = Instant::now();
  71. let seed = [0; 32];
  72. let xsk_m = ExtendedSpendingKey::master(&seed);
  73. //let xfvk_m = ExtendedFullViewingKey::from(&xsk_m);
  74. let i_5h = ChildIndex::Hardened(5);
  75. let secret_key = xsk_m.derive_child(i_5h);
  76. let viewing_key = ExtendedFullViewingKey::from(&secret_key);
  77. let (diversifier, payment_address) = viewing_key.default_address().unwrap();
  78. let ovk = viewing_key.fvk.ovk;
  79. let g_d = payment_address.g_d().expect("invalid address");
  80. let mut buffer = [0u8; 32];
  81. &rng.fill_bytes(&mut buffer);
  82. let rseed = Rseed::AfterZip212(buffer);
  83. let note = Note {
  84. g_d,
  85. pk_d: payment_address.pk_d().clone(),
  86. value: 10,
  87. rseed,
  88. };
  89. println!("Now we made the output [{:?}]", start.elapsed());
  90. // Ok(SaplingOutput {
  91. // ovk,
  92. // to,
  93. // note,
  94. // memo
  95. // })
  96. let start = Instant::now();
  97. let memo = Default::default();
  98. let encryptor =
  99. SaplingNoteEncryption::new(ovk, note.clone(), payment_address.clone(), memo, &mut rng);
  100. let esk = encryptor.esk().clone();
  101. let rcm = note.rcm();
  102. let value = note.value;
  103. let (proof_output, cv_output) =
  104. ctx.output_proof(esk, payment_address.clone(), rcm, value, &output_params);
  105. let mut zkproof = [0u8; GROTH_PROOF_SIZE];
  106. proof_output
  107. .write(&mut zkproof[..])
  108. .expect("should be able to serialize a proof");
  109. let cmu = note.cmu();
  110. let enc_ciphertext = encryptor.encrypt_note_plaintext();
  111. let out_ciphertext = encryptor.encrypt_outgoing_plaintext(&cv_output, &cmu);
  112. let ephemeral_key: jubjub::ExtendedPoint = encryptor.epk().clone().into();
  113. println!("Output description completed [{:?}]", start.elapsed());
  114. // OutputDescription {
  115. // cv,
  116. // cmu,
  117. // ephemeral_key,
  118. // enc_ciphertext,
  119. // out_ciphertext,
  120. // zkproof,
  121. // }
  122. println!("Reading spend parameters from file...");
  123. let start = Instant::now();
  124. let buffer = File::open("spend.params")?;
  125. let spend_params = Parameters::<Bls12>::read(buffer, false)?;
  126. let spend_vk = prepare_verifying_key(&spend_params.vk);
  127. println!("Finished spend paramgen [{:?}]", start.elapsed());
  128. let start = Instant::now();
  129. let cmu1 = Node::new(note.cmu().to_repr());
  130. let mut tree = CommitmentTree::new();
  131. tree.append(cmu1).unwrap();
  132. let witness = IncrementalWitness::from_tree(&tree);
  133. let alpha = jubjub::Fr::random(&mut rng);
  134. // Now we have the spend
  135. // SpendDescriptionInfo {
  136. // extsk,
  137. // diversifier,
  138. // note,
  139. // alpha,
  140. // merkle_path,
  141. // }
  142. // We will spend the address from above
  143. // Leaving these here for reference.
  144. //let extsk = ExtendedSpendingKey::master(&[]);
  145. //let extfvk = ExtendedFullViewingKey::from(&extsk);
  146. //let to_address = extfvk.default_address().unwrap().1;
  147. let proof_generation_key = secret_key.expsk.proof_generation_key();
  148. let merkle_path = witness.path().unwrap();
  149. let cmu = Node::new(note.cmu().into());
  150. let anchor = merkle_path.root(cmu).into();
  151. let mut nullifier = [0u8; 32];
  152. nullifier
  153. .copy_from_slice(&note.nf(&proof_generation_key.to_viewing_key(), merkle_path.position));
  154. let (proof_spend, cv_spend, rk) = ctx
  155. .spend_proof(
  156. proof_generation_key,
  157. payment_address.diversifier().clone(),
  158. rseed,
  159. alpha,
  160. value,
  161. anchor,
  162. merkle_path,
  163. &spend_params,
  164. &spend_vk,
  165. )
  166. .expect("Making proof failed");
  167. let mut zkproof = [0u8; GROTH_PROOF_SIZE];
  168. proof_spend
  169. .write(&mut zkproof[..])
  170. .expect("should be able to serialize a proof");
  171. // Now we have a shielded spend
  172. // SpendDescription {
  173. // cv,
  174. // anchor,
  175. // nullifier,
  176. // rk,
  177. // zkproof,
  178. // spend_auth_sig: None,
  179. // }
  180. // Now for each spend in the tx, we create a signature
  181. // spendAuthSig
  182. // Signature of the entire transaction
  183. // Transaction hash into sighash. Just like in Bitcoin
  184. // Contains our SpendDescriptions and OutputDescriptions
  185. let mut sighash = [0u8; 32];
  186. let spend_auth_sig = spend_sig(PrivateKey(secret_key.expsk.ask), alpha, &sighash, &mut rng);
  187. // And now use the sighash value (since it's signed by all inputs) to create a new key
  188. // which is used to sign the balance commitments.
  189. let amount = Amount::from_u64(0).unwrap();
  190. let binding_sig = ctx
  191. .binding_sig(amount, &sighash)
  192. .expect("sighash binding sig failed");
  193. ////////////////////////////////////////
  194. // Now lets verify the tx
  195. let mut ctx = SaplingVerificationContext::new();
  196. let success = ctx.check_output(
  197. cv_output,
  198. note.cmu(),
  199. ephemeral_key,
  200. proof_output,
  201. &output_vk,
  202. );
  203. assert!(success);
  204. let success = ctx.check_spend(
  205. cv_spend,
  206. anchor,
  207. &nullifier,
  208. rk,
  209. &sighash,
  210. spend_auth_sig,
  211. proof_spend,
  212. &spend_vk,
  213. );
  214. assert!(success);
  215. let success = ctx.final_check(amount, &sighash, binding_sig);
  216. assert!(success);
  217. // The anchor must be a valid merkle root from some past block header
  218. // The nullifier must not already exist
  219. // And the amount is the 'fee' for the block.
  220. Ok(())
  221. }