epoch.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. use halo2_proofs::{arithmetic::Field, dev::MockProver, circuit::Value};
  2. use incrementalmerkletree::{bridgetree::BridgeTree, Tree};
  3. use halo2_gadgets::{
  4. poseidon::{primitives as poseidon},
  5. };
  6. use pasta_curves::{
  7. arithmetic::CurveAffine,
  8. group::{ff::PrimeField, Curve},
  9. pallas,
  10. };
  11. use rand::{thread_rng, Rng};
  12. use crate::{
  13. crypto::{
  14. constants::MERKLE_DEPTH_ORCHARD,
  15. leadcoin::LeadCoin,
  16. lead_proof,
  17. proof::{Proof, ProvingKey, VerifyingKey},
  18. merkle_node::MerkleNode,
  19. util::{mod_r_p, pedersen_commitment_base, pedersen_commitment_u64},
  20. types::DrkValueBlind,
  21. },
  22. };
  23. const PRF_NULLIFIER_PREFIX : u64 = 0;
  24. const MERKLE_DEPTH: u8 = MERKLE_DEPTH_ORCHARD as u8;
  25. #[derive(Copy,Debug,Default,Clone)]
  26. pub struct EpochItem {
  27. pub value: u64, // the stake value is static during the epoch.
  28. }
  29. /// epoch configuration
  30. /// this struct need be a singleton,
  31. /// should be populated from configuration file.
  32. #[derive(Copy,Debug,Default,Clone)]
  33. pub struct EpochConsensus {
  34. pub sl_len : u64, /// number of slots per epoch
  35. pub e_len : u64,
  36. pub tick_len: u64,
  37. pub reward: u64,
  38. }
  39. impl EpochConsensus{
  40. pub fn new(sl_len: Option<u64>, e_len: Option<u64>, tick_len: Option<u64>, reward: Option<u64>) -> Self {
  41. Self {
  42. sl_len: sl_len.unwrap_or(22),
  43. e_len: e_len.unwrap_or(3),
  44. tick_len: tick_len.unwrap_or(22),
  45. reward: reward.unwrap_or(1)
  46. }
  47. }
  48. /// TODO how is the reward derived?
  49. pub fn get_reward(&self) -> u64{
  50. self.reward
  51. }
  52. pub fn get_slot_len(&self) -> u64{
  53. self.sl_len
  54. }
  55. pub fn get_epoch_len(&self) -> u64 {
  56. self.e_len
  57. }
  58. pub fn get_tick_len(&self) -> u64 {
  59. self.tick_len
  60. }
  61. }
  62. #[derive(Debug,Default,Clone)]
  63. pub struct Epoch {
  64. // TODO this need to emulate epoch
  65. // should have ep, slot, current block, etc.
  66. //epoch metadata
  67. pub len: Option<usize>, // number of slots in the epoch
  68. //epoch item
  69. pub item: Option<EpochItem>,
  70. pub eta: pallas::Base, // CRS for the leader selection.
  71. pub coins: Vec<LeadCoin>, // competing coins
  72. }
  73. impl Epoch {
  74. pub fn new(consensus: EpochConsensus, true_random:pallas::Base) -> Self
  75. {
  76. Self {len: Some(consensus.get_slot_len() as usize),
  77. item: Some(EpochItem {value: consensus.reward}),
  78. eta: true_random,
  79. coins:vec!(),
  80. }
  81. }
  82. fn create_coins_election_seeds(&self, sl: pallas::Base) -> (pallas::Base, pallas::Base) {
  83. let ELECTION_SEED_NONCE : pallas::Base = pallas::Base::from(3);
  84. let ELECTION_SEED_LEAD : pallas::Base = pallas::Base::from(22);
  85. // mu_rho
  86. let nonce_mu_msg = [
  87. ELECTION_SEED_NONCE,
  88. self.eta,
  89. sl,
  90. ];
  91. let nonce_mu : pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<3>, 3, 2>::init().hash(nonce_mu_msg);
  92. // mu_y
  93. let lead_mu_msg = [
  94. ELECTION_SEED_LEAD,
  95. self.eta,
  96. sl,
  97. ];
  98. let lead_mu : pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<3>, 3, 2>::init().hash(lead_mu_msg);
  99. (lead_mu, nonce_mu)
  100. }
  101. fn create_coins_sks(&self) -> (Vec<MerkleNode>, Vec<[MerkleNode; MERKLE_DEPTH_ORCHARD]>) {
  102. /*
  103. at the onset of an epoch, the first slot's coin's secret key
  104. is sampled at random, and the rest of the secret keys are derived,
  105. for sk (secret key) at time i+1 is derived from secret key at time i.
  106. */
  107. let mut rng = thread_rng();
  108. let mut tree = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(self.len.unwrap() as usize);
  109. let mut root_sks: Vec<MerkleNode> = vec![];
  110. let mut path_sks: Vec<[MerkleNode; MERKLE_DEPTH_ORCHARD]> = vec![];
  111. let mut prev_sk_base : pallas::Base = pallas::Base::one();
  112. for _i in 0..self.len.unwrap() {
  113. let sk_bytes = if _i ==0 {
  114. let base = pedersen_commitment_u64(1, pallas::Scalar::random(&mut rng));
  115. let coord = base.to_affine().coordinates().unwrap();
  116. let sk_base = coord.x() * coord.y();
  117. prev_sk_base = sk_base;
  118. sk_base.to_repr()
  119. } else {
  120. let base = pedersen_commitment_u64(1, mod_r_p(prev_sk_base));
  121. let coord = base.to_affine().coordinates().unwrap();
  122. let sk_base = coord.x() * coord.y();
  123. prev_sk_base = sk_base;
  124. sk_base.to_repr()
  125. };
  126. let node = MerkleNode::from_bytes(&sk_bytes).unwrap();
  127. //let serialized = serde_json::to_string(&node).unwrap();
  128. //println!("serialized: {}", serialized);
  129. tree.append(&node.clone());
  130. let leaf_position = tree.witness();
  131. let root = tree.root(0).unwrap();
  132. //let (leaf_pos, path) = tree.authentication_path(leaf_position.unwrap()).unwrap();
  133. let path = tree.authentication_path(leaf_position.unwrap(), &root).unwrap();
  134. //note root sk is at tree.root()
  135. //root_sks.push(node);
  136. root_sks.push(root);
  137. path_sks.push(path.as_slice().try_into().unwrap());
  138. }
  139. (root_sks, path_sks)
  140. }
  141. //note! the strategy here is single competing coin per slot.
  142. pub fn create_coins(& mut self) -> Vec<LeadCoin> {
  143. let mut rng = thread_rng();
  144. let mut seeds: Vec<u64> = vec![];
  145. for _i in 0..self.len.unwrap() {
  146. let rho: u64 = rng.gen();
  147. seeds.push(rho);
  148. }
  149. let (root_sks, path_sks) = self.create_coins_sks();
  150. let cm1_val: u64 = rng.gen();
  151. //random commitment blinding values
  152. let c_cm1_blind: DrkValueBlind = pallas::Scalar::random(&mut rng);
  153. let c_cm2_blind: DrkValueBlind = pallas::Scalar::random(&mut rng);
  154. let mut tree_cm = BridgeTree::<MerkleNode, MERKLE_DEPTH>::new(self.len.unwrap() as usize);
  155. let mut coins: Vec<LeadCoin> = vec![];
  156. for i in 0..self.len.unwrap() {
  157. let c_v = pallas::Base::from(self.item.unwrap().value);
  158. //random sampling of the same size of prf,
  159. //pseudo random sampling that is the size of pederson commitment
  160. // coin slot number
  161. //TODO this has to be absolute path
  162. let c_sl = pallas::Base::from(u64::try_from(i).unwrap());
  163. //
  164. //let's assume it's sl for simplicity
  165. let c_tau = pallas::Base::from(u64::try_from(i).unwrap());
  166. //
  167. let c_root_sk: MerkleNode = root_sks[i];
  168. let coin_pk_msg = [
  169. c_tau,
  170. c_root_sk.inner(),
  171. ];
  172. let c_pk : pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init().hash(coin_pk_msg);
  173. let c_seed = pallas::Base::from(seeds[i]);
  174. let sn_msg = [
  175. c_seed,
  176. c_root_sk.inner(),
  177. ];
  178. let c_sn : pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init().hash(sn_msg);
  179. let coin_commit_msg_input = [
  180. pallas::Base::from(PRF_NULLIFIER_PREFIX),
  181. c_pk,
  182. c_v,
  183. c_seed
  184. ];
  185. let coin_commit_msg : pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<4>, 3, 2>::init().hash(coin_commit_msg_input);
  186. let c_cm: pallas::Point = pedersen_commitment_base(coin_commit_msg, c_cm1_blind);
  187. let c_cm_coordinates = c_cm.to_affine().coordinates().unwrap();
  188. let c_cm_base: pallas::Base = c_cm_coordinates.x() * c_cm_coordinates.y();
  189. let c_cm_node = MerkleNode(c_cm_base);
  190. tree_cm.append(&c_cm_node.clone());
  191. let leaf_position = tree_cm.witness();
  192. let c_root_cm = tree_cm.root(0).unwrap();
  193. let c_cm_path = tree_cm.authentication_path(leaf_position.unwrap(), &c_root_cm).unwrap();
  194. let coin_nonce2_msg = [
  195. c_seed,
  196. c_root_sk.inner()
  197. ];
  198. let c_seed2 : pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>, 3, 2>::init().hash(coin_nonce2_msg);
  199. let coin2_commit_msg_input = [
  200. pallas::Base::from(PRF_NULLIFIER_PREFIX),
  201. c_pk,
  202. c_v,
  203. c_seed2,
  204. ];
  205. let coin2_commit_msg : pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<4>, 3, 2>::init().hash(coin2_commit_msg_input);
  206. let c_cm2 = pedersen_commitment_base(coin2_commit_msg, c_cm2_blind);
  207. let c_root_sk = root_sks[i];
  208. let c_path_sk = path_sks[i];
  209. // election seeds
  210. let (y_mu, rho_mu) = self.create_coins_election_seeds(c_sl);
  211. let coin = LeadCoin {
  212. value: Some(c_v),
  213. cm: Some(c_cm),
  214. cm2: Some(c_cm2),
  215. idx: u32::try_from(i).unwrap(),
  216. sl: Some(c_sl),
  217. tau: Some(c_tau),
  218. nonce: Some(c_seed),
  219. nonce_cm: Some(c_seed2),
  220. sn: Some(c_sn),
  221. pk: Some(c_pk),
  222. root_cm: Some(mod_r_p(c_root_cm.inner())),
  223. root_sk: Some(c_root_sk.inner()),
  224. path: Some(c_cm_path.as_slice().try_into().unwrap()),
  225. path_sk: Some(c_path_sk),
  226. c1_blind: Some(c_cm1_blind),
  227. c2_blind: Some(c_cm2_blind),
  228. y_mu: Some(y_mu),
  229. rho_mu: Some(rho_mu),
  230. };
  231. coins.push(coin);
  232. }
  233. self.coins = coins.clone();
  234. coins
  235. }
  236. /// retrive leadership lottary coins of static stake,
  237. /// retrived for for commitment in the genesis data
  238. pub fn get_coins(&self) -> Vec<LeadCoin> {
  239. return self.coins.clone()
  240. }
  241. /// see if the participant stakeholder of this epoch is
  242. /// winning the lottery, in case of success return True
  243. pub fn is_leader(&self, sl: u64) -> bool {
  244. let slusize = sl as usize;
  245. println!("slot: {}, coin len: {}", sl, self.coins.len());
  246. assert!(slusize < self.coins.len() && sl>=0);
  247. let coin = self.coins[sl as usize];
  248. let y_exp = [
  249. coin.root_sk.unwrap(),
  250. coin.nonce.unwrap(),
  251. ];
  252. let y_exp_hash : pallas::Base = poseidon::Hash::<_, poseidon::P128Pow5T3, poseidon::ConstantLength<2>,3,2>::init().hash(y_exp);
  253. // pick x coordiante of y for comparison
  254. let y_x : pallas::Base = *pedersen_commitment_base(coin.y_mu.unwrap(), mod_r_p(y_exp_hash)).to_affine().coordinates().unwrap().x();
  255. let ord = pallas::Base::from(10241024); //TODO fine tune this scalar.
  256. let target = ord*coin.value.unwrap();
  257. println!("y_x: {:?}, target: {:?}", y_x, target);
  258. //reversed for testing
  259. target < y_x
  260. }
  261. pub fn get_proof(&self, sl: u64, pk: &ProvingKey) -> Proof {
  262. let coin = self.coins[sl as usize];
  263. lead_proof::create_lead_proof(pk, coin).unwrap()
  264. }
  265. }
  266. #[derive(Debug,Default,Clone)]
  267. pub struct LifeTime {
  268. //lifetime metadata
  269. //...
  270. //lifetime epochs
  271. pub epochs : Vec<Epoch>,
  272. }