leadcoin.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 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, poseidon_hash, util::mod_r_p, MerkleNode, PublicKey,
  21. SecretKey,
  22. },
  23. pasta::{arithmetic::CurveAffine, group::Curve, pallas},
  24. };
  25. use halo2_proofs::{arithmetic::Field, circuit::Value};
  26. use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
  27. use log::debug;
  28. use rand::rngs::OsRng;
  29. use super::PRF_NULLIFIER_PREFIX;
  30. use crate::{
  31. crypto::{proof::ProvingKey, Proof},
  32. zk::circuit::LeadContract,
  33. Result,
  34. };
  35. pub const MERKLE_DEPTH_LEADCOIN: usize = 32;
  36. pub const MERKLE_DEPTH: u8 = 32;
  37. // TODO: Unify item names with the names in the ZK proof (those are more descriptive)
  38. /// Structure representing the consensus leader coin
  39. #[derive(Debug, Clone, Copy)]
  40. pub struct LeadCoin {
  41. /// Coin's stake value
  42. pub value: u64,
  43. /// Commitment for coin1
  44. pub coin1_commitment: pallas::Point,
  45. /// Commitment for coin2 (poured coin)
  46. pub coin2_commitment: pallas::Point,
  47. /// Coin index
  48. pub idx: u32,
  49. /// Coin slot ID,
  50. pub sl: pallas::Base,
  51. /// Coin timestamp
  52. pub tau: pallas::Base,
  53. /// Coin nonce
  54. pub nonce: pallas::Base,
  55. /// Coin nonce's commitment
  56. pub nonce_cm: pallas::Base,
  57. /// Coin's serial number
  58. pub sn: pallas::Base,
  59. /// Merkle root of coin1 commitment
  60. pub coin1_commitment_root: MerkleNode,
  61. /// Merkle root of the `coin1` secret key
  62. pub coin1_sk_root: MerkleNode,
  63. /// Merkle path to the coin1's commitment
  64. pub coin1_commitment_merkle_path: [MerkleNode; MERKLE_DEPTH_LEADCOIN],
  65. /// Merkle path to the secret key of `coin1`
  66. pub coin1_sk_merkle_path: [MerkleNode; MERKLE_DEPTH_LEADCOIN],
  67. /// coin1 commitment blinding factor
  68. pub coin1_blind: pallas::Scalar,
  69. /// coin2 commitment blinding factor
  70. pub coin2_blind: pallas::Scalar,
  71. /// Leader election nonce derived from eta at onset of epoch
  72. pub y_mu: pallas::Base,
  73. /// Leader election nonce derived from eta at onset of epoch
  74. pub rho_mu: pallas::Base,
  75. /// First coefficient in 1-term T (target function) approximation.
  76. /// NOTE: sigma1 and sigma2 are not the capital sigma from the paper, but
  77. /// the whole coefficient multiplied with absolute stake.
  78. pub sigma1: pallas::Base,
  79. /// Second coefficient in 2-term T (target function) approximation.
  80. pub sigma2: pallas::Base,
  81. /// Coin's secret key
  82. pub secret_key: SecretKey,
  83. }
  84. impl LeadCoin {
  85. /// Create a new `LeadCoin` object using given parameters.
  86. pub fn new(
  87. // wtf is eta and why is it not in the zk proof?
  88. eta: pallas::Base,
  89. // First coefficient in 1-term T (target function) approximation.
  90. sigma1: pallas::Base,
  91. // Second coefficient in 2-term T (target function) approximation.
  92. sigma2: pallas::Base,
  93. // Stake value
  94. value: u64,
  95. // Slot index in the epock
  96. slot_index: usize,
  97. // Merkle root of the `coin_1` secret key in the Merkle tree of secret keys
  98. coin1_sk_root: MerkleNode,
  99. // Merkle path to the secret key of `coin_1` in the Merkle tree of secret keys
  100. coin1_sk_merkle_path: [MerkleNode; MERKLE_DEPTH_LEADCOIN],
  101. // what's seed supposed to be?
  102. seed: u64,
  103. // what is this SecretKey representing?
  104. secret_key: SecretKey,
  105. // Merkle tree of coin commitments
  106. coin_commitment_tree: &mut BridgeTree<MerkleNode, MERKLE_DEPTH>,
  107. ) -> Self {
  108. // Generate random blinding values for commitments:
  109. let coin1_blind = pallas::Scalar::random(&mut OsRng);
  110. let coin2_blind = pallas::Scalar::random(&mut OsRng);
  111. // Derive a public key from the secret key
  112. let public_key = PublicKey::from_secret(secret_key);
  113. let (coin_pk_x, coin_pk_y) = public_key.xy();
  114. debug!("coin_pk[{}] x: {:?}", slot_index, coin_pk_x);
  115. debug!("coin_pk[{}] y: {:?}", slot_index, coin_pk_y);
  116. // Derive a nullifier
  117. let sn_msg = [
  118. pallas::Base::from(seed),
  119. coin1_sk_root.inner(),
  120. pallas::Base::zero(),
  121. pallas::Base::one(),
  122. ];
  123. let c_sn = poseidon_hash(sn_msg);
  124. // Derive input for the commitment of coin1
  125. let coin1_commit_msg = [
  126. pallas::Base::from(*PRF_NULLIFIER_PREFIX),
  127. coin_pk_x,
  128. coin_pk_y,
  129. pallas::Base::from(value),
  130. pallas::Base::from(seed),
  131. pallas::Base::one(),
  132. ];
  133. let coin1_commit_v = poseidon_hash(coin1_commit_msg);
  134. // Create commitment to coin1
  135. let coin1_commitment = pedersen_commitment_base(coin1_commit_v, coin1_blind);
  136. // Hash its coordinates to get a base field element
  137. let c1_cm_coords = coin1_commitment.to_affine().coordinates().unwrap();
  138. let c1_base_msg = [*c1_cm_coords.x(), *c1_cm_coords.y()];
  139. let coin1_commitment_base = poseidon_hash(c1_base_msg);
  140. // Append the element to the Merkle tree
  141. coin_commitment_tree.append(&MerkleNode::from(coin1_commitment_base));
  142. let leaf_pos = coin_commitment_tree.witness().unwrap();
  143. let coin1_commitment_root = coin_commitment_tree.root(0).unwrap();
  144. let coin1_commitment_merkle_path =
  145. coin_commitment_tree.authentication_path(leaf_pos, &coin1_commitment_root).unwrap();
  146. // Derive the nonce for coin2
  147. let coin2_nonce_msg = [
  148. pallas::Base::from(seed),
  149. coin1_sk_root.inner(),
  150. pallas::Base::one(),
  151. pallas::Base::one(),
  152. ];
  153. let coin2_seed = poseidon_hash(coin2_nonce_msg);
  154. debug!("coin2_seed[{}]: {:?}", slot_index, coin2_seed);
  155. // Derive input for the commitment of coin2
  156. let coin2_commit_msg = [
  157. pallas::Base::from(*PRF_NULLIFIER_PREFIX),
  158. coin_pk_x,
  159. coin_pk_y,
  160. pallas::Base::from(value),
  161. coin2_seed,
  162. pallas::Base::one(),
  163. ];
  164. let coin2_commit_v = poseidon_hash(coin2_commit_msg);
  165. // Create commitment to coin2
  166. let coin2_commitment = pedersen_commitment_base(coin2_commit_v, coin2_blind);
  167. // Derive election seeds
  168. let (y_mu, rho_mu) = Self::election_seeds(eta, pallas::Base::from(slot_index as u64));
  169. // Return the object
  170. Self {
  171. value,
  172. coin1_commitment,
  173. coin2_commitment,
  174. // TODO: Should be abs slot
  175. idx: u32::try_from(usize::from(leaf_pos)).unwrap(),
  176. sl: pallas::Base::from(slot_index as u64),
  177. // Assume tau is sl for simplicity
  178. tau: pallas::Base::from(slot_index as u64),
  179. nonce: pallas::Base::from(seed),
  180. nonce_cm: coin2_seed,
  181. sn: c_sn,
  182. coin1_commitment_root,
  183. coin1_sk_root,
  184. coin1_commitment_merkle_path: coin1_commitment_merkle_path.try_into().unwrap(),
  185. coin1_sk_merkle_path,
  186. coin1_blind,
  187. coin2_blind,
  188. y_mu,
  189. rho_mu,
  190. sigma1,
  191. sigma2,
  192. secret_key,
  193. }
  194. }
  195. /// Derive election seeds from given parameters
  196. fn election_seeds(eta: pallas::Base, slot: pallas::Base) -> (pallas::Base, pallas::Base) {
  197. let election_seed_nonce = pallas::Base::from(3);
  198. let election_seed_lead = pallas::Base::from(22);
  199. // mu_y
  200. let lead_msg = [election_seed_lead, eta, slot];
  201. let lead_mu = poseidon_hash(lead_msg);
  202. // mu_rho
  203. let nonce_msg = [election_seed_nonce, eta, slot];
  204. let nonce_mu = poseidon_hash(nonce_msg);
  205. (lead_mu, nonce_mu)
  206. }
  207. /// Create a vector of `pallas::Base` elements from the `LeadCoin` to be
  208. /// used as public inputs for the ZK proof.
  209. pub fn public_inputs(&self) -> Vec<pallas::Base> {
  210. let lottery_msg_input = [self.coin1_sk_root.inner(), self.nonce];
  211. let lottery_msg = poseidon_hash(lottery_msg_input);
  212. let y = pedersen_commitment_base(lottery_msg, mod_r_p(self.y_mu));
  213. let y_coords = y.to_affine().coordinates().unwrap();
  214. let y_coords = [*y_coords.x(), *y_coords.y()];
  215. let y = poseidon_hash(y_coords);
  216. let pubkey = PublicKey::from_secret(self.secret_key);
  217. let (pub_x, pub_y) = pubkey.xy();
  218. vec![self.nonce_cm, pub_x, pub_y, y]
  219. }
  220. /// Try to create a ZK proof of consensus leadership
  221. pub fn create_lead_proof(&self, pk: &ProvingKey) -> Result<Proof> {
  222. // Initialize circuit with witnesses
  223. let lottery_msg_input = [self.coin1_sk_root.inner(), self.nonce];
  224. let lottery_msg = poseidon_hash(lottery_msg_input);
  225. let rho = pedersen_commitment_base(lottery_msg, mod_r_p(self.rho_mu));
  226. let circuit = LeadContract {
  227. coin1_commit_merkle_path: Value::known(self.coin1_commitment_merkle_path),
  228. coin1_commit_root: Value::known(self.coin1_commitment_root.inner()),
  229. coin1_commit_leaf_pos: Value::known(self.idx),
  230. coin1_sk: Value::known(self.secret_key.inner()),
  231. coin1_sk_root: Value::known(self.coin1_sk_root.inner()),
  232. coin1_sk_merkle_path: Value::known(self.coin1_sk_merkle_path),
  233. coin1_timestamp: Value::known(self.tau),
  234. coin1_nonce: Value::known(self.nonce),
  235. coin1_blind: Value::known(self.coin1_blind),
  236. coin1_serial: Value::known(self.sn),
  237. coin1_value: Value::known(pallas::Base::from(self.value)),
  238. coin2_blind: Value::known(self.coin2_blind),
  239. coin2_commit: Value::known(self.coin2_commitment),
  240. rho_mu: Value::known(mod_r_p(self.rho_mu)),
  241. y_mu: Value::known(mod_r_p(self.y_mu)),
  242. sigma1: Value::known(self.sigma1),
  243. sigma2: Value::known(self.sigma2),
  244. rho: Value::known(rho),
  245. };
  246. let proof = Proof::create(pk, &[circuit], &self.public_inputs(), &mut OsRng)?;
  247. Ok(proof)
  248. }
  249. }