burn_proof.rs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. use halo2_proofs::circuit::Value;
  2. use incrementalmerkletree::Hashable;
  3. use log::debug;
  4. use pasta_curves::{arithmetic::CurveAffine, group::Curve};
  5. use rand::rngs::OsRng;
  6. use std::time::Instant;
  7. use super::{
  8. nullifier::Nullifier,
  9. proof::{Proof, ProvingKey, VerifyingKey},
  10. util::{pedersen_commitment_base, pedersen_commitment_u64},
  11. };
  12. use crate::{
  13. crypto::{
  14. keypair::{PublicKey, SecretKey},
  15. merkle_node::MerkleNode,
  16. types::{
  17. DrkCircuitField, DrkCoinBlind, DrkSerial, DrkSpendHook, DrkTokenId, DrkUserData,
  18. DrkUserDataBlind, DrkUserDataEnc, DrkValue, DrkValueBlind, DrkValueCommit,
  19. },
  20. util::poseidon_hash,
  21. },
  22. util::serial::{SerialDecodable, SerialEncodable},
  23. zk::circuit::burn_contract::BurnContract,
  24. Result,
  25. };
  26. #[derive(Debug, Clone, PartialEq, Eq, SerialEncodable, SerialDecodable)]
  27. pub struct BurnRevealedValues {
  28. pub value_commit: DrkValueCommit,
  29. pub token_commit: DrkValueCommit,
  30. pub nullifier: Nullifier,
  31. pub merkle_root: MerkleNode,
  32. pub spend_hook: DrkSpendHook,
  33. pub user_data_enc: DrkUserDataEnc,
  34. pub signature_public: PublicKey,
  35. }
  36. impl BurnRevealedValues {
  37. #[allow(clippy::too_many_arguments)]
  38. pub fn compute(
  39. value: u64,
  40. token_id: DrkTokenId,
  41. value_blind: DrkValueBlind,
  42. token_blind: DrkValueBlind,
  43. serial: DrkSerial,
  44. coin_blind: DrkCoinBlind,
  45. secret: SecretKey,
  46. leaf_position: incrementalmerkletree::Position,
  47. merkle_path: Vec<MerkleNode>,
  48. spend_hook: DrkSpendHook,
  49. user_data: DrkUserData,
  50. user_data_blind: DrkUserDataBlind,
  51. signature_secret: SecretKey,
  52. ) -> Self {
  53. let nullifier = poseidon_hash::<2>([secret.0, serial]);
  54. let public_key = PublicKey::from_secret(secret);
  55. let coords = public_key.0.to_affine().coordinates().unwrap();
  56. let coin = poseidon_hash::<8>([
  57. *coords.x(),
  58. *coords.y(),
  59. DrkValue::from(value),
  60. token_id,
  61. serial,
  62. spend_hook,
  63. user_data,
  64. coin_blind,
  65. ]);
  66. let merkle_root = {
  67. let position: u64 = leaf_position.into();
  68. let mut current = MerkleNode(coin);
  69. for (level, sibling) in merkle_path.iter().enumerate() {
  70. let level = level as u8;
  71. current = if position & (1 << level) == 0 {
  72. MerkleNode::combine(level.into(), &current, sibling)
  73. } else {
  74. MerkleNode::combine(level.into(), sibling, &current)
  75. };
  76. }
  77. current
  78. };
  79. let user_data_enc = poseidon_hash::<2>([user_data, user_data_blind]);
  80. let value_commit = pedersen_commitment_u64(value, value_blind);
  81. let token_commit = pedersen_commitment_base(token_id, token_blind);
  82. BurnRevealedValues {
  83. value_commit,
  84. token_commit,
  85. nullifier: Nullifier(nullifier),
  86. merkle_root,
  87. spend_hook,
  88. user_data_enc,
  89. signature_public: PublicKey::from_secret(signature_secret),
  90. }
  91. }
  92. pub fn make_outputs(&self) -> Vec<DrkCircuitField> {
  93. let value_coords = self.value_commit.to_affine().coordinates().unwrap();
  94. let token_coords = self.token_commit.to_affine().coordinates().unwrap();
  95. let merkle_root = self.merkle_root.0;
  96. let user_data_enc = self.user_data_enc;
  97. let sig_coords = self.signature_public.0.to_affine().coordinates().unwrap();
  98. vec![
  99. self.nullifier.inner(),
  100. *value_coords.x(),
  101. *value_coords.y(),
  102. *token_coords.x(),
  103. *token_coords.y(),
  104. merkle_root,
  105. user_data_enc,
  106. *sig_coords.x(),
  107. *sig_coords.y(),
  108. ]
  109. }
  110. }
  111. #[allow(clippy::too_many_arguments)]
  112. pub fn create_burn_proof(
  113. pk: &ProvingKey,
  114. value: u64,
  115. token_id: DrkTokenId,
  116. value_blind: DrkValueBlind,
  117. token_blind: DrkValueBlind,
  118. serial: DrkSerial,
  119. spend_hook: DrkSpendHook,
  120. user_data: DrkUserData,
  121. user_data_blind: DrkUserDataBlind,
  122. coin_blind: DrkCoinBlind,
  123. secret: SecretKey,
  124. leaf_position: incrementalmerkletree::Position,
  125. merkle_path: Vec<MerkleNode>,
  126. signature_secret: SecretKey,
  127. ) -> Result<(Proof, BurnRevealedValues)> {
  128. let revealed = BurnRevealedValues::compute(
  129. value,
  130. token_id,
  131. value_blind,
  132. token_blind,
  133. serial,
  134. coin_blind,
  135. secret,
  136. leaf_position,
  137. merkle_path.clone(),
  138. spend_hook,
  139. user_data,
  140. user_data_blind,
  141. signature_secret,
  142. );
  143. let leaf_position: u64 = leaf_position.into();
  144. let c = BurnContract {
  145. secret_key: Value::known(secret.0),
  146. serial: Value::known(serial),
  147. value: Value::known(DrkValue::from(value)),
  148. token: Value::known(token_id),
  149. coin_blind: Value::known(coin_blind),
  150. value_blind: Value::known(value_blind),
  151. token_blind: Value::known(token_blind),
  152. leaf_pos: Value::known(leaf_position as u32),
  153. merkle_path: Value::known(merkle_path.try_into().unwrap()),
  154. spend_hook: Value::known(spend_hook),
  155. user_data: Value::known(user_data),
  156. user_data_blind: Value::known(user_data_blind),
  157. sig_secret: Value::known(signature_secret.0),
  158. };
  159. let start = Instant::now();
  160. let public_inputs = revealed.make_outputs();
  161. let proof = Proof::create(pk, &[c], &public_inputs, &mut OsRng)?;
  162. debug!("Prove burn: [{:?}]", start.elapsed());
  163. Ok((proof, revealed))
  164. }
  165. pub fn verify_burn_proof(
  166. vk: &VerifyingKey,
  167. proof: &Proof,
  168. revealed: &BurnRevealedValues,
  169. ) -> Result<()> {
  170. let start = Instant::now();
  171. let public_inputs = revealed.make_outputs();
  172. proof.verify(vk, &public_inputs)?;
  173. debug!("Verify burn: [{:?}]", start.elapsed());
  174. Ok(())
  175. }