main.rs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. //! <https://darkrenaissance.github.io/darkfi/crypto/rln.html>
  19. use std::{collections::HashMap, time::Instant};
  20. use darkfi::{
  21. zk::{empty_witnesses, halo2::Value, Proof, ProvingKey, VerifyingKey, Witness, ZkCircuit},
  22. zkas::ZkBinary,
  23. };
  24. use darkfi_sdk::{
  25. crypto::{pasta_prelude::*, poseidon_hash, MerkleNode, MerkleTree},
  26. incrementalmerkletree::Tree,
  27. pasta::{Ep, Fp},
  28. };
  29. use lazy_static::lazy_static;
  30. use rand::rngs::OsRng;
  31. // These should be unique constants per application.
  32. lazy_static! {
  33. static ref RLN_IDENTIFIER: Fp = Fp::from(42);
  34. static ref IDENTITY_DERIVATION_PATH: Fp = Fp::from(11);
  35. static ref NULLIFIER_DERIVATION_PATH: Fp = Fp::from(12);
  36. }
  37. fn hash_message(message: &[u8]) -> Fp {
  38. let hasher = Ep::hash_to_curve("rln-domain:demoapp");
  39. let message_point = hasher(message);
  40. let message_coords = message_point.to_affine().coordinates().unwrap();
  41. poseidon_hash([*message_coords.x(), *message_coords.y()])
  42. }
  43. fn sss_recover(shares: &[(Fp, Fp)]) -> Fp {
  44. let mut secret = Fp::zero();
  45. for (j, share_j) in shares.iter().enumerate() {
  46. let mut prod = Fp::one();
  47. for (i, share_i) in shares.iter().enumerate() {
  48. if i != j {
  49. prod *= share_i.0 * (share_i.0 - share_j.0).invert().unwrap();
  50. }
  51. }
  52. prod *= share_j.1;
  53. secret += prod;
  54. }
  55. secret
  56. }
  57. fn main() {
  58. let epoch = Fp::from(1674509414);
  59. let external_nullifier = poseidon_hash([epoch, *RLN_IDENTIFIER]);
  60. // The identity commitment should be something that cannot be
  61. // precalculated for usage in the future, and possibly also has
  62. // to be some kind of puzzle that is costly to (pre)calculate.
  63. // Alternatively, it could be economic stake of funds which could
  64. // then be lost if spam is detected and acted upon.
  65. let secret_key = Fp::random(&mut OsRng);
  66. let identity_commitment = poseidon_hash([*IDENTITY_DERIVATION_PATH, secret_key]);
  67. // ============
  68. // Registration
  69. // ============
  70. let mut membership_tree = MerkleTree::new(100);
  71. let mut identity_roots: Vec<MerkleNode> = vec![];
  72. let mut banned_roots: Vec<MerkleNode> = vec![];
  73. let mut identities = HashMap::new();
  74. // Everyone needs to maintain the leaf positions, because to slash, we
  75. // need to provide a valid authentication path. Therefore, the easiest
  76. // way is to store a hashmap.
  77. assert!(!identities.contains_key(&identity_commitment.to_repr()));
  78. membership_tree.append(&MerkleNode::from(identity_commitment));
  79. let leaf_pos = membership_tree.witness().unwrap();
  80. identities.insert(identity_commitment.to_repr(), leaf_pos);
  81. identity_roots.push(membership_tree.root(0).unwrap());
  82. // ==========
  83. // Signalling
  84. // ==========
  85. let a_1 = poseidon_hash([secret_key, external_nullifier]);
  86. // Construct share
  87. let x = hash_message(b"hello i wanna spam");
  88. let y = a_1 * x + secret_key;
  89. // Construct internal nullifier
  90. let internal_nullifier = poseidon_hash([*NULLIFIER_DERIVATION_PATH, a_1]);
  91. let identity_root = membership_tree.root(0).unwrap();
  92. let identity_path = membership_tree.authentication_path(leaf_pos, &identity_root);
  93. let identity_path = identity_path.unwrap();
  94. // zkSNARK things
  95. let signal_zkbin = include_bytes!("../signal.zk.bin");
  96. let rln_zkbin = ZkBinary::decode(signal_zkbin).unwrap();
  97. let rln_empty_circuit = ZkCircuit::new(empty_witnesses(&rln_zkbin), rln_zkbin.clone());
  98. print!("[Interaction] Building Proving key... ");
  99. let now = Instant::now();
  100. let rln_pk = ProvingKey::build(13, &rln_empty_circuit);
  101. println!("[{:?}]", now.elapsed());
  102. print!("[Interaction] Building Verifying key... ");
  103. let now = Instant::now();
  104. let rln_vk = VerifyingKey::build(13, &rln_empty_circuit);
  105. println!("[{:?}]", now.elapsed());
  106. // Prover's witnesses and public inputs
  107. let witnesses = vec![
  108. Witness::Base(Value::known(secret_key)),
  109. Witness::MerklePath(Value::known(identity_path.clone().try_into().unwrap())),
  110. Witness::Uint32(Value::known(u64::from(leaf_pos).try_into().unwrap())),
  111. Witness::Base(Value::known(x)),
  112. Witness::Base(Value::known(epoch)),
  113. Witness::Base(Value::known(*RLN_IDENTIFIER)),
  114. ];
  115. let public_inputs = vec![
  116. epoch,
  117. *RLN_IDENTIFIER,
  118. x, // <-- Message hash
  119. identity_root.inner(),
  120. internal_nullifier,
  121. y,
  122. ];
  123. // Build a circuit with these witnesses
  124. print!("[Interaction] Creating ZK proof... ");
  125. let now = Instant::now();
  126. let rln_circuit = ZkCircuit::new(witnesses, rln_zkbin.clone());
  127. let proof = Proof::create(&rln_pk, &[rln_circuit], &public_inputs, &mut OsRng).unwrap();
  128. println!("[{:?}]", now.elapsed());
  129. // ============
  130. // Verification
  131. // ============
  132. print!("[Interaction] Verifying ZK proof... ");
  133. let now = Instant::now();
  134. assert!(proof.verify(&rln_vk, &public_inputs).is_ok());
  135. assert!(!banned_roots.contains(&MerkleNode::from(public_inputs[3])));
  136. assert!(identity_roots.contains(&MerkleNode::from(public_inputs[3])));
  137. println!("[{:?}]", now.elapsed());
  138. // NOTE: These shares should actually be tracked through the internal nullifier.
  139. let mut shares = vec![(public_inputs[2], public_inputs[5])];
  140. // Now if another message is sent in the same epoch, we should be able to
  141. // recover the secret key and ban the sender.
  142. let x = hash_message(b"hello i'm spamming");
  143. let y = a_1 * x + secret_key;
  144. // Same epoch and account, different message
  145. let witnesses = vec![
  146. Witness::Base(Value::known(secret_key)),
  147. Witness::MerklePath(Value::known(identity_path.try_into().unwrap())),
  148. Witness::Uint32(Value::known(u64::from(leaf_pos).try_into().unwrap())),
  149. Witness::Base(Value::known(x)),
  150. Witness::Base(Value::known(epoch)),
  151. Witness::Base(Value::known(*RLN_IDENTIFIER)),
  152. ];
  153. let public_inputs = vec![
  154. epoch,
  155. *RLN_IDENTIFIER,
  156. x, // <-- Message hash
  157. identity_root.inner(),
  158. internal_nullifier,
  159. y,
  160. ];
  161. // Build a circuit with these witnesses
  162. print!("[Interaction] Creating ZK proof... ");
  163. let now = Instant::now();
  164. let rln_circuit = ZkCircuit::new(witnesses, rln_zkbin);
  165. let proof = Proof::create(&rln_pk, &[rln_circuit], &public_inputs, &mut OsRng).unwrap();
  166. println!("[{:?}]", now.elapsed());
  167. print!("[Interaction] Verifying ZK proof... ");
  168. let now = Instant::now();
  169. assert!(proof.verify(&rln_vk, &public_inputs).is_ok());
  170. assert!(!banned_roots.contains(&MerkleNode::from(public_inputs[3])));
  171. assert!(identity_roots.contains(&MerkleNode::from(public_inputs[3])));
  172. println!("[{:?}]", now.elapsed());
  173. // NOTE: These shares should actually be tracked through the internal nullifier.
  174. shares.push((public_inputs[2], public_inputs[5]));
  175. // ========
  176. // Slashing
  177. // ========
  178. // We should be able to retrieve the secret key because two messages were
  179. // sent in the same epoch.
  180. let recovered_secret = sss_recover(&shares);
  181. assert_eq!(recovered_secret, secret_key);
  182. // Create a slash proof
  183. let slash_zkbin = include_bytes!("../slash.zk.bin");
  184. let slash_zkbin = ZkBinary::decode(slash_zkbin).unwrap();
  185. let slash_empty_circuit = ZkCircuit::new(empty_witnesses(&slash_zkbin), slash_zkbin.clone());
  186. print!("[Slash] Building Proving key... ");
  187. let now = Instant::now();
  188. let slash_pk = ProvingKey::build(13, &slash_empty_circuit);
  189. println!("[{:?}]", now.elapsed());
  190. print!("[Slash] Building Verifying key... ");
  191. let now = Instant::now();
  192. let slash_vk = VerifyingKey::build(13, &slash_empty_circuit);
  193. println!("[{:?}]", now.elapsed());
  194. // Find the leaf position in the hashmap of identity commitments
  195. let identity_commitment = poseidon_hash([*IDENTITY_DERIVATION_PATH, recovered_secret]);
  196. let leaf_pos = identities.get(&identity_commitment.to_repr()).unwrap();
  197. let identity_root = membership_tree.root(0).unwrap();
  198. let identity_path = membership_tree.authentication_path(*leaf_pos, &identity_root);
  199. let identity_path = identity_path.unwrap();
  200. // Witnesses & public inputs
  201. let witnesses = vec![
  202. Witness::Base(Value::known(recovered_secret)),
  203. Witness::MerklePath(Value::known(identity_path.try_into().unwrap())),
  204. Witness::Uint32(Value::known(u64::from(*leaf_pos).try_into().unwrap())),
  205. ];
  206. let public_inputs = vec![identity_root.inner()];
  207. print!("[Slash] Creating ZK proof... ");
  208. let now = Instant::now();
  209. let slash_circuit = ZkCircuit::new(witnesses, slash_zkbin);
  210. let proof = Proof::create(&slash_pk, &[slash_circuit], &public_inputs, &mut OsRng).unwrap();
  211. println!("[{:?}]", now.elapsed());
  212. print!("[Slash] Verifying ZK proof... ");
  213. let now = Instant::now();
  214. assert!(!banned_roots.contains(&MerkleNode::from(public_inputs[0])));
  215. assert!(identity_roots.contains(&MerkleNode::from(public_inputs[0]))); // <- Will this be true?
  216. assert!(proof.verify(&slash_vk, &public_inputs).is_ok());
  217. println!("[{:?}]", now.elapsed());
  218. banned_roots.push(MerkleNode::from(public_inputs[0]));
  219. println!("boi u banned");
  220. }