lead.rs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
  2. use halo2_gadgets::primitives::{
  3. poseidon,
  4. poseidon::{ConstantLength, P128Pow5T3},
  5. };
  6. use halo2_proofs::dev::MockProver;
  7. use rand::{thread_rng, Rng};
  8. use pasta_curves::{pallas, Fp};
  9. use darkfi::{
  10. crypto::{
  11. constants::{
  12. NullifierK, OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV,
  13. MERKLE_DEPTH_ORCHARD,
  14. },
  15. keypair::{Keypair, PublicKey, SecretKey},
  16. merkle_node::MerkleNode,
  17. nullifier::Nullifier,
  18. proof::{Proof, ProvingKey, VerifyingKey},
  19. types::*,
  20. util::{mod_r_p, pedersen_commitment_scalar, pedersen_commitment_u64},
  21. },
  22. zk::circuit::lead_contract::LeadContract,
  23. };
  24. use incrementalmerkletree::Hashable;
  25. use pasta_curves::{
  26. arithmetic::CurveAffine,
  27. group::{ff::PrimeField, Curve, GroupEncoding},
  28. };
  29. //use halo2_proofs::arithmetic::CurveAffine;
  30. #[derive(Debug, Default, Clone, Copy)]
  31. pub struct Coin {
  32. value: Option<pallas::Base>, //stake
  33. cm: Option<pallas::Point>,
  34. cm2: Option<pallas::Point>,
  35. idx: u32,
  36. sl: Option<pallas::Base>, //slot id
  37. tau: Option<pallas::Base>,
  38. nonce: Option<pallas::Base>,
  39. nonce_cm: Option<pallas::Point>,
  40. sn: Option<pallas::Point>, // coin's serial number
  41. //sk : Option<SecretKey>,
  42. pk: Option<pallas::Point>,
  43. pk_x: Option<pallas::Base>,
  44. pk_y: Option<pallas::Base>,
  45. root_cm: Option<pallas::Scalar>,
  46. root_sk: Option<pallas::Base>,
  47. path: Option<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,
  48. path_sk: Option<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,
  49. opening1: Option<pallas::Base>,
  50. opening2: Option<pallas::Base>,
  51. }
  52. fn create_coins_sks(len : usize) ->
  53. (Vec<MerkleNode>, Vec<[MerkleNode; MERKLE_DEPTH_ORCHARD]>)
  54. {
  55. /*
  56. at the onset of an epoch, the first slot's coin's secret key
  57. is sampled at random, and the reset of the secret keys are derived,
  58. for sk (secret key) at time i+1 is derived from secret key at time i.
  59. */
  60. let mut rng = thread_rng();
  61. let sk: u64 = rng.gen();
  62. let mut tree = BridgeTree::<MerkleNode, 32>::new(len);
  63. let mut root_sks: Vec<MerkleNode> = vec![];
  64. let mut path_sks: Vec<[MerkleNode; MERKLE_DEPTH_ORCHARD]> = vec![];
  65. for i in 0..len {
  66. //TODO (research) why the conversion between point and base is panicing?
  67. // is the endianess different?
  68. let base = pedersen_commitment_scalar(pallas::Scalar::one(), pallas::Scalar::from(sk));
  69. let coord = base.to_affine().coordinates().unwrap();
  70. let coord_prod = coord.x() * coord.y();
  71. let node = MerkleNode(coord_prod);
  72. tree.append(&node.clone());
  73. let leaf_position = tree.witness();
  74. //let (leaf_pos, path) = tree.authentication_path(leaf_position.unwrap()).unwrap();
  75. let path = tree.authentication_path(leaf_position.unwrap()).unwrap();
  76. root_sks.push(tree.root().clone());
  77. path_sks.push(path.as_slice().try_into().unwrap());
  78. }
  79. (root_sks, path_sks)
  80. }
  81. fn create_coins(root_sks : Vec<MerkleNode>,
  82. path_sks : Vec<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,
  83. values : Vec<u64>,
  84. len : usize) -> Vec<Coin>
  85. {
  86. let mut rng = thread_rng();
  87. let mut seeds: Vec<u64> = vec![];
  88. for i in 0..len {
  89. let rho: u64 = rng.gen();
  90. seeds.push(rho.clone());
  91. }
  92. let mut tree_cm = BridgeTree::<MerkleNode, 32>::new(len);
  93. let mut coins: Vec<Coin> = vec![];
  94. for i in 0..len {
  95. let c_v = pallas::Base::from(values[i]);
  96. //random sampling of the same size of prf,
  97. //pseudo random sampling that is the size of pederson commitment
  98. // coin slot number
  99. let c_sl = pallas::Base::from(u64::try_from(i).unwrap());
  100. //
  101. let c_tau = pallas::Base::from(u64::try_from(i).unwrap()); // let's assume it's sl for simplicity
  102. //
  103. let c_root_sk: MerkleNode = root_sks[i];
  104. let c_pk = pedersen_commitment_scalar(mod_r_p(c_tau), mod_r_p(c_root_sk.inner()));
  105. let c_seed = pallas::Base::from(seeds[i]);
  106. let c_sn = pedersen_commitment_scalar(mod_r_p(c_seed), mod_r_p(c_root_sk.inner()));
  107. let c_pk_pt = c_pk.to_affine().coordinates().unwrap();
  108. let c_pk_pt_x: pallas::Base = *c_pk_pt.x();
  109. let c_pk_pt_y: pallas::Base = *c_pk_pt.y();
  110. let c_cm_v = c_v.clone() * c_seed.clone() * c_pk_pt_x * c_pk_pt_y;
  111. let c_cm1_blind = pallas::Base::from(1); //tmp val
  112. let c_cm2_blind = pallas::Base::from(1); //tmp val
  113. let c_cm: pallas::Point = pedersen_commitment_scalar(mod_r_p(c_cm_v), mod_r_p(c_cm1_blind));
  114. let c_cm_coordinates = c_cm.to_affine().coordinates().unwrap();
  115. let c_cm_base: pallas::Base = c_cm_coordinates.x() * c_cm_coordinates.y();
  116. let c_cm_node = MerkleNode(c_cm_base);
  117. tree_cm.append(&c_cm_node.clone());
  118. let leaf_position = tree_cm.witness();
  119. let c_cm_path = tree_cm.authentication_path(leaf_position.unwrap()).unwrap();
  120. let c_root_cm = tree_cm.root();
  121. // lead coin commitment
  122. let c_seed2 = pedersen_commitment_scalar(mod_r_p(c_seed), mod_r_p(c_root_sk.inner()));
  123. let c_seed2_pt = c_seed2.to_affine().coordinates().unwrap();
  124. /*
  125. let lead_coin_msg = [c_pk_pt_y.clone(),
  126. c_pk_pt_x.clone(),
  127. c_v,
  128. *c_seed2_pt.x(),
  129. *c_seed2_pt.y()
  130. ];
  131. let lead_coin_msg_hash =
  132. poseidon::Hash::<_, P128Pow5T3, ConstantLength<5>, 3, 2>::init().hash(lead_coin_msg);
  133. */
  134. let lead_coin_msg =
  135. c_pk_pt_y.clone() * c_pk_pt_x.clone() * c_v * *c_seed2_pt.x() * *c_seed2_pt.y();
  136. let c_cm2 = pedersen_commitment_scalar(mod_r_p(lead_coin_msg), mod_r_p(c_cm2_blind));
  137. let c_root_sk = root_sks[i];
  138. let c_root_sk_bytes: [u8; 32] = c_root_sk.inner().to_repr();
  139. let mut c_root_sk_base_bytes: [u8; 32] = [0; 32];
  140. for i in 0..23 {
  141. c_root_sk_base_bytes[i] = c_root_sk_bytes[i];
  142. }
  143. let c_root_sk_base = pallas::Base::from_repr(c_root_sk_base_bytes);
  144. let c_path_sk = path_sks[i];
  145. let coin = Coin {
  146. value: Some(c_v),
  147. cm: Some(c_cm),
  148. cm2: Some(c_cm2),
  149. idx: u32::try_from(i).unwrap(),
  150. sl: Some(c_sl),
  151. tau: Some(c_tau),
  152. nonce: Some(c_seed),
  153. nonce_cm: Some(c_seed2),
  154. sn: Some(c_sn),
  155. pk: Some(c_pk),
  156. pk_x: Some(c_pk_pt_x),
  157. pk_y: Some(c_pk_pt_y),
  158. root_cm: Some(mod_r_p(c_root_cm.inner())),
  159. root_sk: Some(c_root_sk.inner()),
  160. path: Some(c_cm_path.as_slice().try_into().unwrap()),
  161. path_sk: Some(c_path_sk),
  162. opening1: Some(c_cm1_blind),
  163. opening2: Some(c_cm2_blind),
  164. };
  165. coins.push(coin);
  166. }
  167. coins
  168. }
  169. fn create_lead_coin_public_inputs(coin: Coin) -> Vec<pallas::Base>
  170. {
  171. let po_nonce = coin.nonce_cm.unwrap().to_affine().coordinates().unwrap();
  172. let po_tau = pedersen_commitment_scalar(mod_r_p(coin.tau.unwrap()), coin.root_cm.unwrap())
  173. .to_affine()
  174. .coordinates()
  175. .unwrap();
  176. let po_cm = coin.cm.unwrap().to_affine().coordinates().unwrap();
  177. let po_cm2 = coin.cm2.unwrap().to_affine().coordinates().unwrap();
  178. let po_pk = coin.pk.unwrap().to_affine().coordinates().unwrap();
  179. let po_sn = coin.sn.unwrap().to_affine().coordinates().unwrap();
  180. let po_cmp = pallas::Base::from(0);
  181. let zero = pallas::Base::from(0);
  182. // ===============
  183. let cm_pos = coin.idx;
  184. let cm_root = {
  185. let pos: u32 = cm_pos;
  186. let c_cm_coordinates = coin.cm.unwrap().to_affine().coordinates().unwrap();
  187. let c_cm_base: pallas::Base = c_cm_coordinates.x() * c_cm_coordinates.y();
  188. let mut current = MerkleNode(c_cm_base);
  189. for (level, sibling) in coin.path.unwrap().iter().enumerate() {
  190. let level = level as u8;
  191. current = if pos & (1 << level) == 0 {
  192. MerkleNode::combine(level.into(), &current, sibling)
  193. } else {
  194. MerkleNode::combine(level.into(), sibling, &current)
  195. };
  196. }
  197. current
  198. };
  199. let mut public_inputs: Vec<pallas::Base> = vec![
  200. *po_nonce.x(),
  201. *po_nonce.y(),
  202. *po_pk.x(),
  203. *po_pk.y(),
  204. *po_sn.x(),
  205. *po_sn.y(),
  206. *po_cm.x(),
  207. *po_cm.y(),
  208. *po_cm2.x(),
  209. *po_cm2.y(),
  210. cm_root.0,
  211. po_cmp,
  212. ];
  213. public_inputs
  214. }
  215. fn main() {
  216. let k = 13;
  217. //
  218. const LEN: usize = 10;
  219. let mut rng = thread_rng();
  220. let mut root_sks: Vec<MerkleNode> = vec![];
  221. let mut path_sks: Vec<[MerkleNode; MERKLE_DEPTH_ORCHARD]> = vec![];
  222. let mut values : Vec<u64> = vec![];
  223. for i in 0..LEN {
  224. values.push(u64::try_from(i*2).unwrap());
  225. }
  226. (root_sks, path_sks) = create_coins_sks(LEN);
  227. let mut coins: Vec<Coin> = create_coins(root_sks.clone(),
  228. path_sks.clone(),
  229. values,
  230. LEN);
  231. //
  232. let yu64: u64 = rng.gen();
  233. let rhou64: u64 = rng.gen();
  234. let mau_y: pallas::Base = pallas::Base::from(yu64);
  235. let mau_rho: pallas::Base = pallas::Base::from(rhou64);
  236. let coin_idx = 0;
  237. let coin = coins[coin_idx];
  238. let contract = LeadContract {
  239. path: coin.path,
  240. coin_pk_x: coin.pk_x,
  241. coin_pk_y: coin.pk_y,
  242. root_sk: coin.root_sk,
  243. path_sk: coin.path_sk,
  244. coin_timestamp: coin.tau, //
  245. coin_nonce: coin.nonce,
  246. coin_opening_1: Some(mod_r_p(coin.opening1.unwrap())),
  247. value: coin.value,
  248. coin_opening_2: Some(mod_r_p(coin.opening2.unwrap())),
  249. cm_pos: Some(coin.idx),
  250. //sn_c1: Some(coin.sn.unwrap()),
  251. slot: Some(coin.sl.unwrap()),
  252. mau_rho: Some(mau_rho.clone()),
  253. mau_y: Some(mau_y.clone()),
  254. root_cm: Some(coin.root_cm.unwrap()),
  255. };
  256. // calculate public inputs
  257. let public_inputs = create_lead_coin_public_inputs(coin.clone());
  258. let prover = MockProver::run(k, &contract, vec![public_inputs]).unwrap();
  259. //
  260. assert_eq!(prover.verify(), Ok(()));
  261. //
  262. }