demo.rs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  1. #![allow(unused)]
  2. use halo2_gadgets::poseidon::primitives as poseidon;
  3. use halo2_proofs::circuit::Value;
  4. use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
  5. use log::debug;
  6. use pasta_curves::{
  7. arithmetic::CurveAffine,
  8. group::{ff::Field, Curve},
  9. pallas,
  10. };
  11. use rand::rngs::OsRng;
  12. use std::{
  13. any::{Any, TypeId},
  14. collections::HashMap,
  15. time::Instant,
  16. };
  17. use crate::money;
  18. use darkfi::{
  19. crypto::{
  20. constants::MERKLE_DEPTH,
  21. keypair::{Keypair, PublicKey, SecretKey},
  22. merkle_node::MerkleNode,
  23. note::{EncryptedNote, Note},
  24. nullifier::Nullifier,
  25. proof::{ProvingKey, VerifyingKey},
  26. token_id::generate_id,
  27. types::DrkCircuitField,
  28. OwnCoin, OwnCoins, Proof,
  29. },
  30. node::state::{state_transition, ProgramState, StateUpdate},
  31. tx::builder::{
  32. TransactionBuilder, TransactionBuilderClearInputInfo, TransactionBuilderInputInfo,
  33. TransactionBuilderOutputInfo,
  34. },
  35. util::NetworkName,
  36. zk::{
  37. circuit::{BurnContract, MintContract},
  38. vm::{Witness, ZkCircuit},
  39. vm_stack::empty_witnesses,
  40. },
  41. zkas::decoder::ZkBinary,
  42. };
  43. /// The state machine, held in memory.
  44. struct MemoryState {
  45. /// The entire Merkle tree state
  46. tree: BridgeTree<MerkleNode, MERKLE_DEPTH>,
  47. /// List of all previous and the current Merkle roots.
  48. /// This is the hashed value of all the children.
  49. merkle_roots: Vec<MerkleNode>,
  50. /// Nullifiers prevent double spending
  51. nullifiers: Vec<Nullifier>,
  52. /// Verifying key for the mint zk circuit.
  53. mint_vk: VerifyingKey,
  54. /// Verifying key for the burn zk circuit.
  55. burn_vk: VerifyingKey,
  56. /// Public key of the cashier
  57. cashier_signature_public: PublicKey,
  58. /// Public key of the faucet
  59. faucet_signature_public: PublicKey,
  60. }
  61. impl ProgramState for MemoryState {
  62. fn is_valid_cashier_public_key(&self, public: &PublicKey) -> bool {
  63. public == &self.cashier_signature_public
  64. }
  65. fn is_valid_faucet_public_key(&self, public: &PublicKey) -> bool {
  66. public == &self.faucet_signature_public
  67. }
  68. fn is_valid_merkle(&self, merkle_root: &MerkleNode) -> bool {
  69. self.merkle_roots.iter().any(|m| m == merkle_root)
  70. }
  71. fn nullifier_exists(&self, nullifier: &Nullifier) -> bool {
  72. self.nullifiers.iter().any(|n| n == nullifier)
  73. }
  74. fn mint_vk(&self) -> &VerifyingKey {
  75. &self.mint_vk
  76. }
  77. fn burn_vk(&self) -> &VerifyingKey {
  78. &self.burn_vk
  79. }
  80. }
  81. impl MemoryState {
  82. fn apply(&mut self, mut update: StateUpdate) {
  83. // Extend our list of nullifiers with the ones from the update
  84. self.nullifiers.append(&mut update.nullifiers);
  85. // Update merkle tree and witnesses
  86. for (coin, enc_note) in update.coins.into_iter().zip(update.enc_notes.into_iter()) {
  87. // Add the new coins to the Merkle tree
  88. let node = MerkleNode(coin.0);
  89. self.tree.append(&node);
  90. // Keep track of all Merkle roots that have existed
  91. self.merkle_roots.push(self.tree.root(0).unwrap());
  92. }
  93. }
  94. }
  95. type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
  96. pub struct ZkContractInfo {
  97. pub k_param: u32,
  98. pub bincode: ZkBinary,
  99. pub proving_key: ProvingKey,
  100. pub verifying_key: VerifyingKey,
  101. }
  102. pub struct ZkBinaryTable {
  103. // Key will be a hash of zk binary contract on chain
  104. table: HashMap<String, ZkContractInfo>,
  105. }
  106. impl ZkBinaryTable {
  107. fn new() -> Self {
  108. Self { table: HashMap::new() }
  109. }
  110. fn add_contract(&mut self, key: String, bincode: ZkBinary, k_param: u32) {
  111. let witnesses = empty_witnesses(&bincode);
  112. let circuit = ZkCircuit::new(witnesses, bincode.clone());
  113. let proving_key = ProvingKey::build(k_param, &circuit);
  114. let verifying_key = VerifyingKey::build(k_param, &circuit);
  115. let info = ZkContractInfo { k_param, bincode, proving_key, verifying_key };
  116. self.table.insert(key, info);
  117. }
  118. pub fn lookup(&self, key: &String) -> Option<&ZkContractInfo> {
  119. self.table.get(key)
  120. }
  121. }
  122. mod dao_contract {
  123. use pasta_curves::pallas;
  124. use std::any::Any;
  125. #[derive(Clone)]
  126. pub struct DaoBulla(pub pallas::Base);
  127. /// This DAO state is for all DAOs on the network. There should only be a single instance.
  128. pub struct State {
  129. dao_bullas: Vec<DaoBulla>,
  130. }
  131. impl State {
  132. pub fn new() -> Box<dyn Any> {
  133. Box::new(Self { dao_bullas: Vec::new() })
  134. }
  135. pub fn add_bulla(&mut self, bulla: DaoBulla) {
  136. self.dao_bullas.push(bulla);
  137. }
  138. }
  139. /// This is an anonymous contract function that mutates the internal DAO state.
  140. ///
  141. /// Corresponds to `mint(proposer_limit, quorum, approval_ratio, dao_pubkey, dao_blind)`
  142. ///
  143. /// The prover creates a `Builder`, which then constructs the `Tx` that the verifier can
  144. /// check using `state_transition()`.
  145. ///
  146. /// # Arguments
  147. ///
  148. /// * `proposer_limit` - Number of governance tokens that holder must possess in order to
  149. /// propose a new vote.
  150. /// * `quorum` - Number of minimum votes that must be met for a proposal to pass.
  151. /// * `approval_ratio` - Ratio of winning to total votes for a proposal to pass.
  152. /// * `dao_pubkey` - Public key of the DAO for permissioned access. This can also be
  153. /// shared publicly if you want a full decentralized DAO.
  154. /// * `dao_blind` - Blinding factor for the DAO bulla.
  155. ///
  156. /// # Example
  157. ///
  158. /// ```rust
  159. /// let dao_proposer_limit = 110;
  160. /// let dao_quorum = 110;
  161. /// let dao_approval_ratio = 2;
  162. ///
  163. /// let builder = dao_contract::Mint::Builder(
  164. /// dao_proposer_limit,
  165. /// dao_quorum,
  166. /// dao_approval_ratio,
  167. /// gov_token_id,
  168. /// dao_pubkey,
  169. /// dao_blind
  170. /// );
  171. /// let tx = builder.build();
  172. /// ```
  173. pub mod mint {
  174. use darkfi::{
  175. crypto::{keypair::PublicKey, proof::ProvingKey, types::DrkCircuitField, Proof},
  176. zk::vm::{Witness, ZkCircuit},
  177. };
  178. use halo2_gadgets::poseidon::primitives as poseidon;
  179. use halo2_proofs::circuit::Value;
  180. use log::debug;
  181. use pasta_curves::{
  182. arithmetic::CurveAffine,
  183. group::{ff::Field, Curve},
  184. pallas,
  185. };
  186. use rand::rngs::OsRng;
  187. use std::{
  188. any::{Any, TypeId},
  189. time::Instant,
  190. };
  191. use super::{
  192. super::{CallDataBase, FuncCall, StateRegistry, Transaction, ZkBinaryTable},
  193. DaoBulla,
  194. };
  195. pub struct Builder {
  196. dao_proposer_limit: u64,
  197. dao_quorum: u64,
  198. dao_approval_ratio: u64,
  199. gov_token_id: pallas::Base,
  200. dao_pubkey: PublicKey,
  201. dao_bulla_blind: pallas::Base,
  202. }
  203. impl Builder {
  204. pub fn new(
  205. dao_proposer_limit: u64,
  206. dao_quorum: u64,
  207. dao_approval_ratio: u64,
  208. gov_token_id: pallas::Base,
  209. dao_pubkey: PublicKey,
  210. dao_bulla_blind: pallas::Base,
  211. ) -> Self {
  212. Self {
  213. dao_proposer_limit,
  214. dao_quorum,
  215. dao_approval_ratio,
  216. gov_token_id,
  217. dao_pubkey,
  218. dao_bulla_blind,
  219. }
  220. }
  221. /// Consumes self, and produces the function call
  222. pub fn build(self, zk_bins: &ZkBinaryTable) -> FuncCall {
  223. // Dao bulla
  224. let dao_proposer_limit = pallas::Base::from(self.dao_proposer_limit);
  225. let dao_quorum = pallas::Base::from(self.dao_quorum);
  226. let dao_approval_ratio = pallas::Base::from(self.dao_approval_ratio);
  227. let dao_pubkey_coords = self.dao_pubkey.0.to_affine().coordinates().unwrap();
  228. let dao_public_x = *dao_pubkey_coords.x();
  229. let dao_public_y = *dao_pubkey_coords.x();
  230. let messages = [
  231. dao_proposer_limit,
  232. dao_quorum,
  233. dao_approval_ratio,
  234. self.gov_token_id,
  235. dao_public_x,
  236. dao_public_y,
  237. self.dao_bulla_blind,
  238. // @tmp-workaround
  239. self.dao_bulla_blind,
  240. ];
  241. let dao_bulla = poseidon::Hash::<
  242. _,
  243. poseidon::P128Pow5T3,
  244. poseidon::ConstantLength<8>,
  245. 3,
  246. 2,
  247. >::init()
  248. .hash(messages);
  249. let dao_bulla = DaoBulla(dao_bulla);
  250. // Now create the mint proof
  251. let zk_info = zk_bins.lookup(&"dao-mint".to_string()).unwrap();
  252. let zk_bin = zk_info.bincode.clone();
  253. let prover_witnesses = vec![
  254. Witness::Base(Value::known(dao_proposer_limit)),
  255. Witness::Base(Value::known(dao_quorum)),
  256. Witness::Base(Value::known(dao_approval_ratio)),
  257. Witness::Base(Value::known(self.gov_token_id)),
  258. Witness::Base(Value::known(dao_public_x)),
  259. Witness::Base(Value::known(dao_public_y)),
  260. Witness::Base(Value::known(self.dao_bulla_blind)),
  261. ];
  262. let public_inputs = vec![dao_bulla.0];
  263. let circuit = ZkCircuit::new(prover_witnesses, zk_bin);
  264. let proving_key = &zk_info.proving_key;
  265. let mint_proof = Proof::create(proving_key, &[circuit], &public_inputs, &mut OsRng)
  266. .expect("DAO::mint() proving error!");
  267. // [x] 1. move proving key to zkbins table (and k value)
  268. // [x] 2. do verification of zk proofs in main code
  269. // [ ] 3. implement apply(update) function
  270. // Return call data
  271. let call_data = CallData { dao_bulla };
  272. FuncCall {
  273. contract_id: "DAO".to_string(),
  274. func_id: "DAO::mint()".to_string(),
  275. call_data: Box::new(call_data),
  276. proofs: vec![mint_proof],
  277. }
  278. }
  279. }
  280. pub struct CallData {
  281. dao_bulla: DaoBulla,
  282. }
  283. impl CallDataBase for CallData {
  284. fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>> {
  285. vec![vec![self.dao_bulla.0]]
  286. }
  287. fn zk_proof_addrs(&self) -> Vec<String> {
  288. vec!["dao-mint".to_string()]
  289. }
  290. fn as_any(&self) -> &dyn Any {
  291. self
  292. }
  293. }
  294. #[derive(Debug, Clone, thiserror::Error)]
  295. pub enum Error {
  296. #[error("Malformed packet")]
  297. MalformedPacket,
  298. }
  299. type Result<T> = std::result::Result<T, Error>;
  300. pub fn state_transition(
  301. states: &StateRegistry,
  302. func_call_index: usize,
  303. parent_tx: &Transaction,
  304. ) -> Result<Update> {
  305. let func_call = &parent_tx.func_calls[func_call_index];
  306. let call_data = func_call.call_data.as_any();
  307. assert_eq!((&*call_data).type_id(), TypeId::of::<CallData>());
  308. let call_data = call_data.downcast_ref::<CallData>();
  309. // This will be inside wasm so unwrap is fine.
  310. let call_data = call_data.unwrap();
  311. // Code goes here
  312. Ok(Update { dao_bulla: call_data.dao_bulla.clone() })
  313. }
  314. pub struct Update {
  315. dao_bulla: DaoBulla,
  316. }
  317. pub fn apply(states: &mut StateRegistry, update: Update) {
  318. // Lookup dao_contract state from registry
  319. let state = states.lookup::<super::State>(&"dao_contract".to_string()).unwrap();
  320. // Add dao_bulla to state.dao_bullas
  321. state.add_bulla(update.dao_bulla);
  322. }
  323. }
  324. }
  325. macro_rules! zip {
  326. ($x: expr) => ($x);
  327. ($x: expr, $($y: expr), +) => (
  328. $x.iter().zip(
  329. zip!($($y), +))
  330. )
  331. }
  332. pub struct Transaction {
  333. func_calls: Vec<FuncCall>,
  334. }
  335. impl Transaction {
  336. /// TODO: what should this return? plonk error?
  337. /// Verify ZK contracts for the entire tx
  338. /// In real code, we could parallelize this for loop
  339. fn zk_verify(&self, zk_bins: &ZkBinaryTable) {
  340. for func_call in &self.func_calls {
  341. let proofs_public_vals = &func_call.call_data.zk_public_values();
  342. let proofs_keys = &func_call.call_data.zk_proof_addrs();
  343. assert_eq!(proofs_public_vals.len(), proofs_keys.len());
  344. assert_eq!(proofs_keys.len(), func_call.proofs.len());
  345. for (key, (proof, public_vals)) in
  346. zip!(proofs_keys, &func_call.proofs, proofs_public_vals)
  347. {
  348. let zk_info = zk_bins.lookup(key).unwrap();
  349. let verifying_key = &zk_info.verifying_key;
  350. proof.verify(&verifying_key, public_vals).expect("verify DAO::mint() failed!");
  351. debug!("zk_verify({}) passed", key);
  352. }
  353. }
  354. }
  355. }
  356. // These would normally be a hash or sth
  357. type ContractId = String;
  358. type FuncId = String;
  359. pub struct FuncCall {
  360. contract_id: ContractId,
  361. func_id: FuncId,
  362. call_data: Box<dyn CallDataBase>,
  363. proofs: Vec<Proof>,
  364. }
  365. pub trait CallDataBase {
  366. // Public values for verifying the proofs
  367. // Needed so we can convert internal types so they can be used in Proof::verify()
  368. fn zk_public_values(&self) -> Vec<Vec<DrkCircuitField>>;
  369. // The zk contract ID needed to lookup in the table
  370. fn zk_proof_addrs(&self) -> Vec<String>;
  371. // For upcasting to CallData itself so it can be read in state_transition()
  372. fn as_any(&self) -> &dyn Any;
  373. }
  374. type GenericContractState = Box<dyn Any>;
  375. pub struct StateRegistry {
  376. pub states: HashMap<ContractId, GenericContractState>,
  377. }
  378. impl StateRegistry {
  379. fn new() -> Self {
  380. Self { states: HashMap::new() }
  381. }
  382. fn register(&mut self, contract_id: ContractId, state: GenericContractState) {
  383. self.states.insert(contract_id, state);
  384. }
  385. fn lookup<'a, S: 'static>(&'a mut self, contract_id: &ContractId) -> Option<&'a mut S> {
  386. self.states.get_mut(contract_id).and_then(|state| state.downcast_mut())
  387. }
  388. }
  389. pub async fn demo() -> Result<()> {
  390. // Money parameters
  391. let xdrk_supply = 1_000_000;
  392. let xdrk_token_id = pallas::Base::random(&mut OsRng);
  393. // Governance token parameters
  394. let gdrk_supply = 1_000_000;
  395. let gdrk_token_id = pallas::Base::random(&mut OsRng);
  396. // DAO parameters
  397. let dao_proposer_limit = 110;
  398. let dao_quorum = 110;
  399. let dao_approval_ratio = 2;
  400. // Lookup table for smart contract states
  401. let mut states = StateRegistry::new();
  402. // Initialize ZK binary table
  403. let mut zk_bins = ZkBinaryTable::new();
  404. let zk_dao_mint_bincode = include_bytes!("../proof/dao-mint.zk.bin");
  405. let zk_dao_mint_bin = ZkBinary::decode(zk_dao_mint_bincode)?;
  406. zk_bins.add_contract("dao-mint".to_string(), zk_dao_mint_bin, 13);
  407. /////////////////////////////////////////////////
  408. /*
  409. // State for money contracts
  410. let cashier_signature_secret = SecretKey::random(&mut OsRng);
  411. let cashier_signature_public = PublicKey::from_secret(cashier_signature_secret);
  412. let faucet_signature_secret = SecretKey::random(&mut OsRng);
  413. let faucet_signature_public = PublicKey::from_secret(faucet_signature_secret);
  414. let start = Instant::now();
  415. let mint_vk = VerifyingKey::build(11, &MintContract::default());
  416. debug!("Mint VK: [{:?}]", start.elapsed());
  417. let start = Instant::now();
  418. let burn_vk = VerifyingKey::build(11, &BurnContract::default());
  419. debug!("Burn VK: [{:?}]", start.elapsed());
  420. let money_state = Box::new(MemoryState {
  421. tree: BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(100),
  422. merkle_roots: vec![],
  423. nullifiers: vec![],
  424. mint_vk,
  425. burn_vk,
  426. cashier_signature_public,
  427. faucet_signature_public,
  428. });
  429. states.register("money_contract".to_string(), money_state);
  430. */
  431. /////////////////////////////////////////////////
  432. let dao_state = dao_contract::State::new();
  433. states.register("dao_contract".to_string(), dao_state);
  434. // For this demo lets create 10 random preexisting DAO bullas
  435. for _ in 0..10 {
  436. let bulla = pallas::Base::random(&mut OsRng);
  437. }
  438. /////////////////////////////////////////////////
  439. // Create the DAO bulla
  440. /////////////////////////////////////////////////
  441. // Setup the DAO
  442. let dao_keypair = Keypair::random(&mut OsRng);
  443. let dao_bulla_blind = pallas::Base::random(&mut OsRng);
  444. // Create DAO mint tx
  445. let builder = dao_contract::mint::Builder::new(
  446. dao_proposer_limit,
  447. dao_quorum,
  448. dao_approval_ratio,
  449. gdrk_token_id,
  450. dao_keypair.public,
  451. dao_bulla_blind,
  452. );
  453. let func_call = builder.build(&zk_bins);
  454. let tx = Transaction { func_calls: vec![func_call] };
  455. for (idx, func_call) in tx.func_calls.iter().enumerate() {
  456. // So then the verifier will lookup the corresponding state_transition and apply
  457. // functions based off the func_id
  458. if func_call.func_id == "DAO::mint()" {
  459. debug!("dao_contract::mint::state_transition()");
  460. let update = dao_contract::mint::state_transition(&states, idx, &tx).unwrap();
  461. dao_contract::mint::apply(&mut states, update);
  462. }
  463. }
  464. tx.zk_verify(&zk_bins);
  465. /////////////////////////////////////////////////
  466. /*
  467. let token_id = pallas::Base::random(&mut OsRng);
  468. let builder = TransactionBuilder {
  469. clear_inputs: vec![TransactionBuilderClearInputInfo {
  470. value: 110,
  471. token_id,
  472. signature_secret: cashier_signature_secret,
  473. }],
  474. inputs: vec![],
  475. outputs: vec![TransactionBuilderOutputInfo {
  476. value: 110,
  477. token_id,
  478. public: keypair.public,
  479. }],
  480. };
  481. let start = Instant::now();
  482. let mint_pk = ProvingKey::build(11, &MintContract::default());
  483. debug!("Mint PK: [{:?}]", start.elapsed());
  484. let start = Instant::now();
  485. let burn_pk = ProvingKey::build(11, &BurnContract::default());
  486. debug!("Burn PK: [{:?}]", start.elapsed());
  487. let tx = builder.build(&mint_pk, &burn_pk)?;
  488. tx.verify(&money_state.mint_vk, &money_state.burn_vk)?;
  489. let _note = tx.outputs[0].enc_note.decrypt(&keypair.secret)?;
  490. let update = state_transition(&money_state, tx)?;
  491. money_state.apply(update);
  492. // Now spend
  493. let owncoin = &money_state.own_coins[0];
  494. let note = &owncoin.note;
  495. let leaf_position = owncoin.leaf_position;
  496. let root = money_state.tree.root(0).unwrap();
  497. let merkle_path = money_state.tree.authentication_path(leaf_position, &root).unwrap();
  498. let builder = TransactionBuilder {
  499. clear_inputs: vec![],
  500. inputs: vec![TransactionBuilderInputInfo {
  501. leaf_position,
  502. merkle_path,
  503. secret: keypair.secret,
  504. note: note.clone(),
  505. }],
  506. outputs: vec![TransactionBuilderOutputInfo {
  507. value: 110,
  508. token_id,
  509. public: keypair.public,
  510. }],
  511. };
  512. let tx = builder.build(&mint_pk, &burn_pk)?;
  513. let update = state_transition(&money_state, tx)?;
  514. money_state.apply(update);
  515. */
  516. Ok(())
  517. }