lead_coin.rs 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2024 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. use darkfi_sdk::{
  19. crypto::{
  20. pedersen::{pedersen_commitment_base, pedersen_commitment_u64},
  21. poseidon_hash,
  22. util::fp_mod_fv,
  23. MerkleNode, MerkleTree, SecretKey,
  24. },
  25. pasta::{arithmetic::CurveAffine, group::Curve, pallas},
  26. };
  27. use darkfi_serial::{async_trait, SerialDecodable, SerialEncodable};
  28. use halo2_proofs::{arithmetic::Field, circuit::Value};
  29. use log::info;
  30. use rand::rngs::OsRng;
  31. use super::constants::EPOCH_LENGTH;
  32. use crate::{
  33. consensus::{constants, utils::fbig2base, Float10, TransferStx, TxRcpt},
  34. zk::{
  35. proof::{Proof, ProvingKey},
  36. vm::ZkCircuit,
  37. vm_heap::Witness,
  38. },
  39. zkas::ZkBinary,
  40. Result,
  41. };
  42. use std::{
  43. fs::File,
  44. io::{prelude::*, BufWriter},
  45. };
  46. pub const MERKLE_DEPTH_LEAD_COIN: usize = 32;
  47. pub const MERKLE_DEPTH: u8 = 32;
  48. pub const ZERO: pallas::Base = pallas::Base::zero();
  49. pub const ONE: pallas::Base = pallas::Base::one();
  50. pub const PREFIX_EVL: u64 = 2;
  51. pub const PREFIX_SEED: u64 = 3;
  52. pub const PREFIX_CM: u64 = 4;
  53. pub const PREFIX_PK: u64 = 5;
  54. pub const PREFIX_SN: u64 = 6;
  55. // TODO: Unify item names with the names in the ZK proof (those are more descriptive)
  56. /// Structure representing the consensus leader coin
  57. #[derive(Debug, Clone, SerialDecodable, SerialEncodable)]
  58. pub struct LeadCoin {
  59. /// Coin's stake value
  60. pub value: u64,
  61. /// Coin creation slot.
  62. pub slot: u64,
  63. /// Coin nonce
  64. pub nonce: pallas::Base,
  65. /// Commitment for coin1
  66. pub coin1_commitment: pallas::Point,
  67. /// Merkle root of coin1 commitment
  68. pub coin1_commitment_root: MerkleNode,
  69. /// Coin commitment position
  70. pub coin1_commitment_pos: u32,
  71. /// Merkle path to the coin1's commitment
  72. pub coin1_commitment_merkle_path: Vec<MerkleNode>,
  73. /// coin1 sk
  74. pub coin1_sk: pallas::Base,
  75. /// Merkle root of the `coin1` secret key
  76. pub coin1_sk_root: MerkleNode,
  77. /// coin1 sk position in merkle tree
  78. pub coin1_sk_pos: u32,
  79. /// Merkle path to the secret key of `coin1`
  80. pub coin1_sk_merkle_path: Vec<MerkleNode>,
  81. /// coin1 commitment blinding factor
  82. pub coin1_blind: pallas::Scalar,
  83. }
  84. impl LeadCoin {
  85. /// Create a new `LeadCoin` object using given parameters.
  86. #[allow(clippy::too_many_arguments)]
  87. pub fn new(
  88. // emulation of global random oracle output from previous epoch randomness.
  89. //eta: pallas::Base,
  90. // Stake value
  91. value: u64,
  92. // Slot absolute index
  93. slot: u64,
  94. // coin1 sk
  95. coin1_sk: pallas::Base,
  96. // Merkle root of the `coin_1` secret key in the Merkle tree of secret keys
  97. coin1_sk_root: MerkleNode,
  98. // sk pos
  99. coin1_sk_pos: usize,
  100. // Merkle path to the secret key of `coin_1` in the Merkle tree of secret keys
  101. coin1_sk_merkle_path: Vec<MerkleNode>,
  102. // coin1 nonce
  103. seed: pallas::Base,
  104. // Merkle tree of coin commitments
  105. coin_commitment_tree: &mut MerkleTree,
  106. ) -> Self {
  107. // Generate random blinding values for commitments:
  108. let coin1_blind = pallas::Scalar::random(&mut OsRng);
  109. //let coin2_blind = pallas::Scalar::random(&mut OsRng);
  110. // pk
  111. let pk = Self::util_pk(coin1_sk_root, slot);
  112. let coin1_commitment = Self::commitment(pk, pallas::Base::from(value), seed, coin1_blind);
  113. // Hash its coordinates to get a base field element
  114. let c1_cm_coords = coin1_commitment.to_affine().coordinates().unwrap();
  115. let c1_base_msg = [*c1_cm_coords.x(), *c1_cm_coords.y()];
  116. let coin1_commitment_base = poseidon_hash(c1_base_msg);
  117. // Append the element to the Merkle tree
  118. coin_commitment_tree.append(MerkleNode::from(coin1_commitment_base));
  119. let coin1_commitment_pos = coin_commitment_tree.mark().unwrap();
  120. let coin1_commitment_root = coin_commitment_tree.root(0).unwrap();
  121. let coin1_commitment_merkle_path =
  122. coin_commitment_tree.witness(coin1_commitment_pos, 0).unwrap();
  123. Self {
  124. value,
  125. slot,
  126. nonce: seed,
  127. coin1_commitment,
  128. coin1_commitment_root,
  129. coin1_commitment_pos: u32::try_from(u64::from(coin1_commitment_pos)).unwrap(),
  130. coin1_commitment_merkle_path,
  131. coin1_sk,
  132. coin1_sk_root,
  133. coin1_sk_pos: u32::try_from(coin1_sk_pos).unwrap(),
  134. coin1_sk_merkle_path,
  135. coin1_blind,
  136. }
  137. }
  138. pub fn sn(&self) -> pallas::Base {
  139. let sn_msg = [pallas::Base::from(PREFIX_SN), self.coin1_sk_root.inner(), self.nonce, ZERO];
  140. poseidon_hash(sn_msg)
  141. }
  142. pub fn election_seeds_u64(eta: pallas::Base, slotu64: u64) -> (pallas::Base, pallas::Base) {
  143. Self::election_seeds(eta, pallas::Base::from(slotu64))
  144. }
  145. /// Derive election seeds from given parameters
  146. pub fn election_seeds(eta: pallas::Base, slot: pallas::Base) -> (pallas::Base, pallas::Base) {
  147. info!(target: "consensus::leadcoin", "election_seeds: eta: {:?}, slot: {:?}", eta, slot);
  148. let election_seed_nonce = pallas::Base::from(3);
  149. let election_seed_lead = pallas::Base::from(22);
  150. // mu_y
  151. let lead_msg = [election_seed_lead, eta, slot];
  152. let lead_mu = poseidon_hash(lead_msg);
  153. // mu_rho
  154. let nonce_msg = [election_seed_nonce, eta, slot];
  155. let nonce_mu = poseidon_hash(nonce_msg);
  156. (lead_mu, nonce_mu)
  157. }
  158. /// Create a vector of `pallas::Base` elements from the `LeadCoin` to be
  159. /// used as public inputs for the ZK proof.
  160. pub fn public_inputs(
  161. &self,
  162. sigma1: pallas::Base,
  163. sigma2: pallas::Base,
  164. current_eta: pallas::Base,
  165. current_slot: pallas::Base,
  166. derived_blind: pallas::Scalar,
  167. ) -> Vec<pallas::Base> {
  168. // pk
  169. let pk = self.pk();
  170. // coin 1-2 cm/commitment
  171. let c1_cm_coord = self.coin1_commitment.to_affine().coordinates().unwrap();
  172. let c2_cm_coord = self.derived_commitment(derived_blind).to_affine().coordinates().unwrap();
  173. // lottery seed
  174. let seed_msg =
  175. [pallas::Base::from(PREFIX_SEED), self.coin1_sk_root.inner(), self.nonce, ZERO];
  176. let seed = poseidon_hash(seed_msg);
  177. // y
  178. let (y_mu, rho_mu) = Self::election_seeds(current_eta, current_slot);
  179. let y_msg = [seed, y_mu];
  180. let y = poseidon_hash(y_msg);
  181. // rho
  182. let rho_msg = [seed, rho_mu];
  183. let rho = poseidon_hash(rho_msg);
  184. let public_inputs = vec![
  185. pk,
  186. *c1_cm_coord.x(),
  187. *c1_cm_coord.y(),
  188. *c2_cm_coord.x(),
  189. *c2_cm_coord.y(),
  190. self.coin1_commitment_root.inner(),
  191. self.coin1_sk_root.inner(),
  192. self.sn(),
  193. y_mu,
  194. y,
  195. rho_mu,
  196. rho,
  197. sigma1,
  198. sigma2,
  199. ];
  200. public_inputs
  201. }
  202. fn util_pk(sk_root: MerkleNode, slot: u64) -> pallas::Base {
  203. let pk_msg =
  204. [pallas::Base::from(PREFIX_PK), sk_root.inner(), pallas::Base::from(slot), ZERO];
  205. poseidon_hash(pk_msg)
  206. }
  207. /// calculate coin public key: hash of root coin secret key
  208. /// and creation slot.
  209. pub fn pk(&self) -> pallas::Base {
  210. Self::util_pk(self.coin1_sk_root, self.slot)
  211. }
  212. fn util_derived_rho(sk_root: MerkleNode, nonce: pallas::Base) -> pallas::Base {
  213. let rho_msg = [pallas::Base::from(PREFIX_EVL), sk_root.inner(), nonce, ZERO];
  214. poseidon_hash(rho_msg)
  215. }
  216. /// calculate derived coin nonce: hash of root coin secret key
  217. /// and old nonce
  218. pub fn derived_rho(&self) -> pallas::Base {
  219. Self::util_derived_rho(self.coin1_sk_root, self.nonce)
  220. }
  221. pub fn headstart() -> pallas::Base {
  222. let headstart = constants::MIN_F.clone() * Float10::try_from(constants::P).unwrap();
  223. fbig2base(headstart)
  224. }
  225. pub fn is_leader(
  226. &self,
  227. sigma1: pallas::Base,
  228. sigma2: pallas::Base,
  229. current_eta: pallas::Base,
  230. current_slot: pallas::Base,
  231. ) -> bool {
  232. let y_seed =
  233. [pallas::Base::from(PREFIX_SEED), self.coin1_sk_root.inner(), self.nonce, ZERO];
  234. let y_seed_hash = poseidon_hash(y_seed);
  235. let (y_mu, _) = Self::election_seeds(current_eta, current_slot);
  236. let y_msg = [y_seed_hash, y_mu];
  237. let y = poseidon_hash(y_msg);
  238. let value = pallas::Base::from(self.value);
  239. let headstart = Self::headstart();
  240. let target = sigma1 * value + sigma2 * value * value + headstart;
  241. let y_t_str = format!("{:?},{:?}\n", y, target);
  242. let f =
  243. File::options().append(true).create(true).open(constants::LOTTERY_HISTORY_LOG).unwrap();
  244. {
  245. let mut writer = BufWriter::new(f);
  246. let _ = writer.write(&y_t_str.into_bytes()).unwrap();
  247. }
  248. info!(target: "consensus::leadcoin", "is_leader(): y = {:?}", y);
  249. info!(target: "consensus::leadcoin", "is_leader(): T = {:?}", target);
  250. y < target
  251. }
  252. fn commitment(
  253. pk: pallas::Base,
  254. value: pallas::Base,
  255. seed: pallas::Base,
  256. blind: pallas::Scalar,
  257. ) -> pallas::Point {
  258. let commit_msg = [pallas::Base::from(PREFIX_CM), pk, value, seed];
  259. // Create commitment to coin
  260. let commit_v = poseidon_hash(commit_msg);
  261. pedersen_commitment_base(commit_v, blind)
  262. }
  263. /// calculated derived coin commitment
  264. pub fn derived_commitment(&self, blind: pallas::Scalar) -> pallas::Point {
  265. let pk = self.pk();
  266. let rho = self.derived_rho();
  267. Self::commitment(pk, pallas::Base::from(self.value + constants::REWARD), rho, blind)
  268. }
  269. /// the new coin to be minted after the current coin is spent
  270. /// in lottery.
  271. pub fn derive_coin(
  272. &self,
  273. coin_commitment_tree: &mut MerkleTree,
  274. derived_blind: pallas::Scalar,
  275. ) -> LeadCoin {
  276. info!(target: "consensus::leadcoin", "derive_coin(): Deriving new coin!");
  277. let derived_c1_rho = self.derived_rho();
  278. let derived_c1_cm = self.derived_commitment(derived_blind);
  279. let derived_c1_cm_coord = derived_c1_cm.to_affine().coordinates().unwrap();
  280. let derived_c1_cm_msg = [*derived_c1_cm_coord.x(), *derived_c1_cm_coord.y()];
  281. let derived_c1_cm_base = poseidon_hash(derived_c1_cm_msg);
  282. coin_commitment_tree.append(MerkleNode::from(derived_c1_cm_base));
  283. let leaf_pos = coin_commitment_tree.mark().unwrap();
  284. let commitment_root = coin_commitment_tree.root(0).unwrap();
  285. let commitment_merkle_path = coin_commitment_tree.witness(leaf_pos, 0).unwrap();
  286. LeadCoin {
  287. value: self.value + constants::REWARD,
  288. slot: self.slot,
  289. nonce: derived_c1_rho,
  290. coin1_commitment: derived_c1_cm,
  291. coin1_commitment_root: commitment_root,
  292. coin1_commitment_pos: u32::try_from(u64::from(leaf_pos)).unwrap(),
  293. coin1_commitment_merkle_path: commitment_merkle_path,
  294. coin1_sk: self.coin1_sk,
  295. coin1_sk_root: self.coin1_sk_root,
  296. coin1_sk_pos: self.coin1_sk_pos,
  297. coin1_sk_merkle_path: self.coin1_sk_merkle_path.clone(),
  298. coin1_blind: derived_blind,
  299. }
  300. }
  301. /// Try to create a ZK proof of consensus leadership
  302. pub fn create_lead_proof(
  303. &self,
  304. sigma1: pallas::Base,
  305. sigma2: pallas::Base,
  306. eta: pallas::Base,
  307. slot: pallas::Base, //current slot index.
  308. pk: &ProvingKey,
  309. derived_blind: pallas::Scalar,
  310. ) -> (Result<Proof>, Vec<pallas::Base>) {
  311. let (y_mu, rho_mu) = Self::election_seeds(eta, slot);
  312. let bincode = include_bytes!("../../proof/lead.zk.bin");
  313. let zkbin = ZkBinary::decode(bincode).unwrap();
  314. let headstart = Self::headstart();
  315. let coin1_commitment_merkle_path: [MerkleNode; MERKLE_DEPTH_LEAD_COIN] =
  316. self.coin1_commitment_merkle_path.clone().try_into().unwrap();
  317. let coin1_sk_merkle_path: [MerkleNode; MERKLE_DEPTH_LEAD_COIN] =
  318. self.coin1_sk_merkle_path.clone().try_into().unwrap();
  319. let witnesses = vec![
  320. Witness::MerklePath(Value::known(coin1_commitment_merkle_path)),
  321. Witness::Uint32(Value::known(self.coin1_commitment_pos)),
  322. Witness::Uint32(Value::known(self.coin1_sk_pos)),
  323. Witness::Base(Value::known(self.coin1_sk)),
  324. Witness::Base(Value::known(self.coin1_sk_root.inner())),
  325. Witness::MerklePath(Value::known(coin1_sk_merkle_path)),
  326. Witness::Base(Value::known(pallas::Base::from(self.slot))),
  327. Witness::Base(Value::known(self.nonce)),
  328. Witness::Scalar(Value::known(self.coin1_blind)),
  329. Witness::Base(Value::known(pallas::Base::from(self.value))),
  330. Witness::Scalar(Value::known(derived_blind)),
  331. Witness::Base(Value::known(rho_mu)),
  332. Witness::Base(Value::known(y_mu)),
  333. Witness::Base(Value::known(sigma1)),
  334. Witness::Base(Value::known(sigma2)),
  335. Witness::Base(Value::known(headstart)),
  336. ];
  337. let circuit = ZkCircuit::new(witnesses, &zkbin);
  338. let public_inputs = self.public_inputs(sigma1, sigma2, eta, slot, derived_blind);
  339. (Ok(Proof::create(pk, &[circuit], &public_inputs, &mut OsRng).unwrap()), public_inputs)
  340. }
  341. #[allow(clippy::too_many_arguments)]
  342. pub fn create_xfer_proof(
  343. &self,
  344. pk: &ProvingKey,
  345. change_coin: TxRcpt,
  346. change_pk: pallas::Base, //change coin public key
  347. transfered_coin: TxRcpt,
  348. transfered_pk: pallas::Base, // recipient coin's public key
  349. sigma1: pallas::Base,
  350. sigma2: pallas::Base,
  351. current_eta: pallas::Base,
  352. current_slot: pallas::Base,
  353. derived_blind: pallas::Scalar,
  354. ) -> Result<TransferStx> {
  355. assert!(change_coin.value + transfered_coin.value == self.value && self.value > 0);
  356. let bincode = include_bytes!("../../proof/tx.zk.bin");
  357. let zkbin = ZkBinary::decode(bincode)?;
  358. let retval = pallas::Base::from(change_coin.value);
  359. let xferval = pallas::Base::from(transfered_coin.value);
  360. let pos: u32 = self.coin1_commitment_pos;
  361. let value = pallas::Base::from(self.value);
  362. let coin1_sk_merkle_path: [MerkleNode; MERKLE_DEPTH_LEAD_COIN] =
  363. self.coin1_sk_merkle_path.clone().try_into().unwrap();
  364. let coin1_commitment_merkle_path: [MerkleNode; MERKLE_DEPTH_LEAD_COIN] =
  365. self.coin1_commitment_merkle_path.clone().try_into().unwrap();
  366. let witnesses = vec![
  367. // coin (1) burned coin
  368. Witness::Base(Value::known(self.coin1_commitment_root.inner())),
  369. Witness::Base(Value::known(self.coin1_sk_root.inner())),
  370. Witness::Base(Value::known(self.coin1_sk)),
  371. Witness::MerklePath(Value::known(coin1_sk_merkle_path)),
  372. Witness::Uint32(Value::known(self.coin1_sk_pos)),
  373. Witness::Base(Value::known(self.nonce)),
  374. Witness::Scalar(Value::known(self.coin1_blind)),
  375. Witness::Base(Value::known(value)),
  376. Witness::MerklePath(Value::known(coin1_commitment_merkle_path)),
  377. Witness::Uint32(Value::known(pos)),
  378. Witness::Base(Value::known(self.sn())),
  379. // coin (3)
  380. Witness::Base(Value::known(change_pk)),
  381. Witness::Base(Value::known(change_coin.rho)),
  382. Witness::Scalar(Value::known(change_coin.opening)),
  383. Witness::Base(Value::known(retval)),
  384. // coin (4)
  385. Witness::Base(Value::known(transfered_pk)),
  386. Witness::Base(Value::known(transfered_coin.rho)),
  387. Witness::Scalar(Value::known(transfered_coin.opening)),
  388. Witness::Base(Value::known(xferval)),
  389. ];
  390. let circuit = ZkCircuit::new(witnesses, &zkbin);
  391. let proof = Proof::create(
  392. pk,
  393. &[circuit],
  394. &self.public_inputs(sigma1, sigma2, current_eta, current_slot, derived_blind),
  395. &mut OsRng,
  396. )?;
  397. let cm3_msg_in = [
  398. pallas::Base::from(PREFIX_CM),
  399. change_pk,
  400. pallas::Base::from(change_coin.value),
  401. change_coin.rho,
  402. ];
  403. let cm3_msg = poseidon_hash(cm3_msg_in);
  404. let cm3 = pedersen_commitment_base(cm3_msg, change_coin.opening);
  405. let cm4_msg_in = [
  406. pallas::Base::from(PREFIX_CM),
  407. transfered_pk,
  408. pallas::Base::from(transfered_coin.value),
  409. transfered_coin.rho,
  410. ];
  411. let cm4_msg = poseidon_hash(cm4_msg_in);
  412. let cm4 = pedersen_commitment_base(cm4_msg, transfered_coin.opening);
  413. let tx = TransferStx {
  414. coin_commitment: self.coin1_commitment,
  415. coin_pk: self.pk(),
  416. coin_root_sk: self.coin1_sk_root,
  417. change_coin_commitment: cm3,
  418. transfered_coin_commitment: cm4,
  419. nullifier: self.sn(),
  420. slot: pallas::Base::from(self.slot),
  421. root: self.coin1_commitment_root,
  422. proof,
  423. };
  424. Ok(tx)
  425. }
  426. }
  427. /// This struct holds the secrets for creating LeadCoins during one epoch.
  428. pub struct LeadCoinSecrets {
  429. pub secret_keys: Vec<SecretKey>,
  430. pub merkle_roots: Vec<MerkleNode>,
  431. pub merkle_paths: Vec<Vec<MerkleNode>>,
  432. }
  433. impl LeadCoinSecrets {
  434. /// Generate epoch coins secret keys.
  435. /// First clot coin secret key is sampled at random, while the secret keys of the
  436. /// remaining slots derive from the previous slot secret.
  437. /// Clarification:
  438. /// ```plaintext
  439. /// sk[0] -> random,
  440. /// sk[1] -> derive_function(sk[0]),
  441. /// ...
  442. /// sk[n] -> derive_function(sk[n-1]),
  443. /// ```
  444. pub fn generate() -> Self {
  445. let mut tree = MerkleTree::new(EPOCH_LENGTH);
  446. let mut sks = Vec::with_capacity(EPOCH_LENGTH);
  447. let mut root_sks = Vec::with_capacity(EPOCH_LENGTH);
  448. let mut path_sks = Vec::with_capacity(EPOCH_LENGTH);
  449. let mut prev_sk = SecretKey::from(pallas::Base::one());
  450. for i in 0..EPOCH_LENGTH {
  451. let secret = if i == 0 {
  452. pedersen_commitment_u64(1, pallas::Scalar::random(&mut OsRng))
  453. } else {
  454. pedersen_commitment_u64(1, fp_mod_fv(prev_sk.inner()))
  455. };
  456. let secret_coords = secret.to_affine().coordinates().unwrap();
  457. let secret_msg = [*secret_coords.x(), *secret_coords.y()];
  458. let secret_key = SecretKey::from(poseidon_hash(secret_msg));
  459. sks.push(secret_key);
  460. prev_sk = secret_key;
  461. let node = MerkleNode::from(secret_key.inner());
  462. tree.append(node);
  463. let leaf_pos = tree.mark().unwrap();
  464. let root = tree.root(0).unwrap();
  465. let path = tree.witness(leaf_pos, 0).unwrap();
  466. root_sks.push(root);
  467. path_sks.push(path);
  468. }
  469. Self { secret_keys: sks, merkle_roots: root_sks, merkle_paths: path_sks }
  470. }
  471. }