lead_contract.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. use crate::crypto::{
  2. constants::{
  3. sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
  4. util::gen_const_array,
  5. NullifierK, OrchardFixedBases, OrchardFixedBasesFull, MERKLE_DEPTH_ORCHARD,
  6. },
  7. merkle_node::MerkleNode,
  8. };
  9. use halo2_gadgets::{
  10. ecc::{
  11. chip::{EccChip, EccConfig},
  12. FixedPoint, FixedPointBaseField, ScalarFixed,
  13. },
  14. poseidon::{
  15. primitives as poseidon, Hash as PoseidonHash, Pow5Chip as PoseidonChip,
  16. Pow5Config as PoseidonConfig,
  17. },
  18. sinsemilla::{
  19. chip::{SinsemillaChip, SinsemillaConfig},
  20. merkle::{
  21. chip::{MerkleChip, MerkleConfig},
  22. MerklePath,
  23. },
  24. },
  25. utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
  26. };
  27. use halo2_proofs::{
  28. circuit::{AssignedCell, Layouter, SimpleFloorPlanner, Value},
  29. plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn},
  30. };
  31. use pasta_curves::{pallas, Fp};
  32. use crate::zk::gadget::{
  33. arithmetic::{ArithChip, ArithConfig, ArithInstruction},
  34. //even_bits::{EvenBitsChip, EvenBitsConfig, EvenBitsLookup},
  35. less_than::{LessThanChip, LessThanConfig},
  36. native_range_check::NativeRangeCheckChip,
  37. };
  38. const WINDOW_SIZE: usize = 3;
  39. const NUM_OF_BITS: usize = 254;
  40. const NUM_OF_WINDOWS: usize = 85;
  41. const PRF_NULLIFIER_PREFIX: u64 = 0;
  42. #[derive(Clone, Debug)]
  43. pub struct LeadConfig {
  44. primary: Column<InstanceColumn>,
  45. advices: [Column<Advice>; 10],
  46. ecc_config: EccConfig<OrchardFixedBases>,
  47. poseidon_config: PoseidonConfig<pallas::Base, 3, 2>,
  48. merkle_config_1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  49. merkle_config_2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  50. sinsemilla_config_1:
  51. SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  52. _sinsemilla_config_2:
  53. SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  54. lessthan_config: LessThanConfig<WINDOW_SIZE, NUM_OF_BITS, NUM_OF_WINDOWS>,
  55. arith_config: ArithConfig,
  56. }
  57. impl LeadConfig {
  58. fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
  59. EccChip::construct(self.ecc_config.clone())
  60. }
  61. fn poseidon_chip(&self) -> PoseidonChip<pallas::Base, 3, 2> {
  62. PoseidonChip::construct(self.poseidon_config.clone())
  63. }
  64. fn merkle_chip_1(
  65. &self,
  66. ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
  67. MerkleChip::construct(self.merkle_config_1.clone())
  68. }
  69. fn merkle_chip_2(
  70. &self,
  71. ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
  72. MerkleChip::construct(self.merkle_config_2.clone())
  73. }
  74. fn lessthan_chip(&self) -> LessThanChip<WINDOW_SIZE, NUM_OF_BITS, NUM_OF_WINDOWS> {
  75. LessThanChip::construct(self.lessthan_config.clone())
  76. }
  77. fn arith_chip(&self) -> ArithChip {
  78. ArithChip::construct(self.arith_config.clone())
  79. }
  80. }
  81. const LEAD_COIN_COMMIT_X_OFFSET: usize = 0;
  82. const LEAD_COIN_COMMIT_Y_OFFSET: usize = 1;
  83. const LEAD_COIN_COMMIT2_X_OFFSET: usize = 2;
  84. const LEAD_COIN_COMMIT2_Y_OFFSET: usize = 3;
  85. const LEAD_COIN_NONCE2_OFFSET: usize = 4;
  86. const LEAD_COIN_COMMIT_PATH_OFFSET: usize = 5;
  87. const LEAD_COIN_PK_X_OFFSET: usize = 6;
  88. const LEAD_COIN_PK_Y_OFFSET: usize = 7;
  89. const LEAD_COIN_SERIAL_NUMBER_OFFSET: usize = 8;
  90. const LEAD_Y_COMMIT_BASE_OFFSET: usize = 9;
  91. const LEAD_RHO_COMMIT_BASE_OFFSET: usize = 10;
  92. pub fn concat_u8(lhs: &[u8], rhs: &[u8]) -> Vec<u8> {
  93. [lhs, rhs].concat()
  94. }
  95. #[derive(Default, Debug)]
  96. pub struct LeadContract {
  97. // witness
  98. pub path: Value<[MerkleNode; MERKLE_DEPTH_ORCHARD]>,
  99. pub sk: Value<pallas::Base>,
  100. pub root_sk: Value<pallas::Base>, // coins merkle tree secret key of coin1
  101. pub path_sk: Value<[MerkleNode; MERKLE_DEPTH_ORCHARD]>, // path to the secret key root_sk
  102. pub coin_timestamp: Value<pallas::Base>,
  103. pub coin_nonce: Value<pallas::Base>,
  104. pub coin1_blind: Value<pallas::Scalar>,
  105. pub value: Value<pallas::Base>,
  106. pub coin2_blind: Value<pallas::Scalar>,
  107. // public advices
  108. pub cm_pos: Value<u32>,
  109. //
  110. //pub sn_c1 : Option<pallas::Base>,
  111. pub slot: Value<pallas::Base>,
  112. pub mau_rho: Value<pallas::Scalar>,
  113. pub mau_y: Value<pallas::Scalar>,
  114. pub root_cm: Value<pallas::Scalar>,
  115. pub sigma_scalar: Value<pallas::Base>,
  116. //pub eta : Option<u32>,
  117. //pub rho : Option<u32>,
  118. //pub h : Option<u32>, // hash of this data
  119. //pub ptr: Option<u32>, //hash of the previous block
  120. }
  121. impl UtilitiesInstructions<pallas::Base> for LeadContract {
  122. type Var = AssignedCell<Fp, Fp>;
  123. }
  124. impl Circuit<pallas::Base> for LeadContract {
  125. type Config = LeadConfig;
  126. type FloorPlanner = SimpleFloorPlanner;
  127. fn without_witnesses(&self) -> Self {
  128. Self::default()
  129. }
  130. fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
  131. let advices = [
  132. meta.advice_column(),
  133. meta.advice_column(),
  134. meta.advice_column(),
  135. meta.advice_column(),
  136. meta.advice_column(),
  137. meta.advice_column(),
  138. meta.advice_column(),
  139. meta.advice_column(),
  140. meta.advice_column(),
  141. meta.advice_column(),
  142. ];
  143. let table_idx = meta.lookup_table_column();
  144. let lookup = (table_idx, meta.lookup_table_column(), meta.lookup_table_column());
  145. let primary = meta.instance_column();
  146. meta.enable_equality(primary);
  147. for advice in advices.iter() {
  148. meta.enable_equality(*advice);
  149. }
  150. let lagrange_coeffs = [
  151. meta.fixed_column(),
  152. meta.fixed_column(),
  153. meta.fixed_column(),
  154. meta.fixed_column(),
  155. meta.fixed_column(),
  156. meta.fixed_column(),
  157. meta.fixed_column(),
  158. meta.fixed_column(),
  159. ];
  160. let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
  161. let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
  162. meta.enable_constant(lagrange_coeffs[0]);
  163. let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
  164. let ecc_config = EccChip::<OrchardFixedBases>::configure(
  165. meta,
  166. advices[0..10].try_into().expect("wrong slice size"),
  167. lagrange_coeffs,
  168. range_check,
  169. );
  170. let poseidon_config = PoseidonChip::configure::<poseidon::P128Pow5T3>(
  171. meta,
  172. advices[6..9].try_into().unwrap(),
  173. advices[5],
  174. rc_a,
  175. rc_b,
  176. );
  177. let (sinsemilla_config_1, merkle_config_1) = {
  178. let sinsemilla_config_1 = SinsemillaChip::configure(
  179. meta,
  180. advices[..5].try_into().unwrap(),
  181. advices[6],
  182. lagrange_coeffs[0],
  183. lookup,
  184. range_check,
  185. );
  186. let merkle_config_1 = MerkleChip::configure(meta, sinsemilla_config_1.clone());
  187. (sinsemilla_config_1, merkle_config_1)
  188. };
  189. let (sinsemilla_config_2, merkle_config_2) = {
  190. let sinsemilla_config_2 = SinsemillaChip::configure(
  191. meta,
  192. advices[5..10].try_into().unwrap(),
  193. advices[7],
  194. lagrange_coeffs[1],
  195. lookup,
  196. range_check,
  197. );
  198. let merkle_config_2 = MerkleChip::configure(meta, sinsemilla_config_2.clone());
  199. (sinsemilla_config_2, merkle_config_2)
  200. };
  201. let k_values_table = meta.lookup_table_column();
  202. let lessthan_config = {
  203. let a = meta.advice_column();
  204. let b = meta.advice_column();
  205. let a_offset = meta.advice_column();
  206. let constants = meta.fixed_column();
  207. meta.enable_constant(constants);
  208. LessThanChip::<WINDOW_SIZE, NUM_OF_BITS, NUM_OF_WINDOWS>::configure(
  209. meta,
  210. a,
  211. b,
  212. a_offset,
  213. k_values_table,
  214. )
  215. };
  216. let arith_config = ArithChip::configure(meta, advices[7], advices[8], advices[6]);
  217. LeadConfig {
  218. primary,
  219. advices,
  220. ecc_config,
  221. poseidon_config,
  222. merkle_config_1,
  223. merkle_config_2,
  224. sinsemilla_config_1,
  225. _sinsemilla_config_2: sinsemilla_config_2,
  226. lessthan_config,
  227. arith_config,
  228. }
  229. }
  230. fn synthesize(
  231. &self,
  232. config: Self::Config,
  233. mut layouter: impl Layouter<pallas::Base>,
  234. ) -> Result<(), Error> {
  235. let less_than_chip = config.lessthan_chip();
  236. NativeRangeCheckChip::<WINDOW_SIZE, NUM_OF_BITS, NUM_OF_WINDOWS>::load_k_table(
  237. &mut layouter,
  238. config.lessthan_config.k_values_table,
  239. )?;
  240. SinsemillaChip::load(config.sinsemilla_config_1.clone(), &mut layouter)?;
  241. let ecc_chip = config.ecc_chip();
  242. let ar_chip = config.arith_chip();
  243. let _ps_chip = config.poseidon_chip();
  244. // ===============
  245. // load witnesses
  246. // ===============
  247. // constant identity value 1
  248. let one = self.load_private(
  249. layouter.namespace(|| "one"),
  250. config.advices[0],
  251. Value::known(pallas::Base::one()),
  252. )?;
  253. // prefix to the pseudo-random-function that prefix input
  254. // to the nullifier poseidon hash
  255. let prf_nullifier_prefix_base = self.load_private(
  256. layouter.namespace(|| "PRF NULLIFIER PREFIX BASE"),
  257. config.advices[0],
  258. Value::known(pallas::Base::from(PRF_NULLIFIER_PREFIX)),
  259. )?;
  260. // staking coin timestamp
  261. /*
  262. let coin_timestamp = self.load_private(
  263. layouter.namespace(|| "load coin time stamp"),
  264. config.advices[0],
  265. self.coin_timestamp,
  266. )?;
  267. */
  268. // staking coin nonce
  269. let coin_nonce: AssignedCell<Fp, Fp> = self.load_private(
  270. layouter.namespace(|| "load coin nonce"),
  271. config.advices[0],
  272. self.coin_nonce,
  273. )?;
  274. // staking coin value
  275. let coin_value = self.load_private(
  276. layouter.namespace(|| "load coin value"),
  277. config.advices[0],
  278. self.value,
  279. )?;
  280. // staking coin secret key
  281. let _root_sk =
  282. self.load_private(layouter.namespace(|| "root sk"), config.advices[0], self.root_sk)?;
  283. // staking coin secret key
  284. let sk: AssignedCell<Fp, Fp> =
  285. self.load_private(layouter.namespace(|| "sk"), config.advices[0], self.sk).unwrap();
  286. // sigma scalar is 2^254/(total network stake + epsilon)
  287. let sigma_scalar = self.load_private(
  288. layouter.namespace(|| "load scalar "),
  289. config.advices[0],
  290. self.sigma_scalar,
  291. )?;
  292. // leadership coefficient used for fine-tunning leader election frequency
  293. let _c = self.load_private(
  294. layouter.namespace(|| ""),
  295. config.advices[0],
  296. Value::known(pallas::Base::one()), // note! this parameter to be tuned.
  297. )?;
  298. // the original crypsinous pk is as follows.
  299. // coin public key pk=PRF_{root_sk}(tau)
  300. // coin public key is pseudo random hash of concatenation of the following:
  301. // coin timestamp, and root of coin's secret key.
  302. //let coin_pk_commit: AssignedCell<Fp, Fp> = {
  303. // let poseidon_message = [coin_timestamp, _root_sk.clone()];
  304. // //let poseidon_hasher = PoseidonHash::<
  305. // _,
  306. // _,
  307. // poseidon::P128Pow5T3,
  308. // poseidon::ConstantLength<2>,
  309. // 3,
  310. // 2,
  311. // >::init(
  312. // config.poseidon_chip(), layouter.namespace(|| "Poseidon init")
  313. // )?;
  314. //
  315. // let poseidon_output =
  316. // poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
  317. // let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
  318. // poseidon_output
  319. //};
  320. // darkfi coin pk
  321. //
  322. let coin_pk = {
  323. let coin_pk_commit_v = FixedPointBaseField::from_inner(ecc_chip.clone(), NullifierK);
  324. coin_pk_commit_v.mul(layouter.namespace(|| "coin pk commit v"), sk.clone())?
  325. };
  326. let coin_pk_x = coin_pk.inner().x();
  327. let coin_pk_y = coin_pk.inner().y();
  328. // coin c1 serial number sn=PRF_{root_sk}(nonce)
  329. // coin's serial number is derived from coin nonce (sampled at random)
  330. // and root of the coin's secret key sampled an random.
  331. let sn_commit: AssignedCell<Fp, Fp> = {
  332. let poseidon_message = [coin_nonce.clone(), _root_sk.clone()];
  333. let poseidon_hasher = PoseidonHash::<
  334. _,
  335. _,
  336. poseidon::P128Pow5T3,
  337. poseidon::ConstantLength<2>,
  338. 3,
  339. 2,
  340. >::init(
  341. config.poseidon_chip(), layouter.namespace(|| "Poseidon init")
  342. )?;
  343. let poseidon_output =
  344. poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
  345. let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
  346. poseidon_output
  347. };
  348. // commitment to the staking coin
  349. // coin commiment H=COMMIT(PRF(prefix||pk||V||nonce), r)
  350. let com = {
  351. // coin c1 nullifier is a commitment of the following
  352. // nullifier input
  353. let nullifier_msg: AssignedCell<Fp, Fp> = {
  354. let poseidon_message = [
  355. prf_nullifier_prefix_base.clone(),
  356. coin_pk_x.clone(),
  357. coin_pk_y.clone(),
  358. coin_value.clone(),
  359. coin_nonce.clone(),
  360. ];
  361. let poseidon_hasher = PoseidonHash::<
  362. _,
  363. _,
  364. poseidon::P128Pow5T3,
  365. poseidon::ConstantLength<5>,
  366. 3,
  367. 2,
  368. >::init(
  369. config.poseidon_chip(),
  370. layouter.namespace(|| "Poseidon init"),
  371. )?;
  372. let poseidon_output = poseidon_hasher
  373. .hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
  374. let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
  375. poseidon_output
  376. };
  377. let coin_commit_v = FixedPointBaseField::from_inner(ecc_chip.clone(), NullifierK);
  378. coin_commit_v.mul(layouter.namespace(|| "coin commit v"), nullifier_msg)?
  379. };
  380. // r*G_2
  381. let (blind, _) = {
  382. let rcv = ScalarFixed::new(
  383. ecc_chip.clone(),
  384. layouter.namespace(|| "coin1 blind scalar"),
  385. self.coin1_blind,
  386. )?;
  387. let coin_commit_r =
  388. FixedPoint::from_inner(ecc_chip.clone(), OrchardFixedBasesFull::ValueCommitR);
  389. coin_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), rcv)?
  390. };
  391. let coin_commit = com.add(layouter.namespace(|| "nonce commit"), &blind)?;
  392. let coin_commit_x: AssignedCell<Fp, Fp> = coin_commit.inner().x();
  393. let coin_commit_y: AssignedCell<Fp, Fp> = coin_commit.inner().y();
  394. // nonce2 = PRF_{root_sk}(coin_nonce)
  395. // poured coin derived nonce as a poseidon of the previous nonce, and
  396. // root of secret key.
  397. let coin2_nonce: AssignedCell<Fp, Fp> = {
  398. let poseidon_message = [coin_nonce.clone(), _root_sk.clone()];
  399. let poseidon_hasher = PoseidonHash::<
  400. _,
  401. _,
  402. poseidon::P128Pow5T3,
  403. poseidon::ConstantLength<2>,
  404. 3,
  405. 2,
  406. >::init(
  407. config.poseidon_chip(), layouter.namespace(|| "Poseidon init")
  408. )?;
  409. let poseidon_output =
  410. poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
  411. let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
  412. poseidon_output
  413. };
  414. // coin2 commiment H=COMMIT(PRF(pk||V||nonce2), r2)
  415. // poured coin's commitment is a nullifier
  416. let com2 = {
  417. // coin2's commitment input body as a poseidon of input concatenation of
  418. // public key, stake, and poured coin's nonce.
  419. let nullifier2_msg: AssignedCell<Fp, Fp> = {
  420. let poseidon_message = [
  421. prf_nullifier_prefix_base,
  422. coin_pk_x.clone(),
  423. coin_pk_y.clone(),
  424. coin_value.clone(),
  425. coin2_nonce.clone(),
  426. ];
  427. let poseidon_hasher = PoseidonHash::<
  428. _,
  429. _,
  430. poseidon::P128Pow5T3,
  431. poseidon::ConstantLength<5>,
  432. 3,
  433. 2,
  434. >::init(
  435. config.poseidon_chip(),
  436. layouter.namespace(|| "Poseidon init"),
  437. )?;
  438. let poseidon_output = poseidon_hasher
  439. .hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
  440. let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
  441. poseidon_output
  442. };
  443. let coin_commit_v = FixedPointBaseField::from_inner(ecc_chip.clone(), NullifierK);
  444. coin_commit_v.mul(layouter.namespace(|| "coin commit v"), nullifier2_msg)?
  445. };
  446. // r*G_2
  447. let (blind, _) = {
  448. let coin2_blind = ScalarFixed::new(
  449. ecc_chip.clone(),
  450. layouter.namespace(|| "coin2 blind scalar"),
  451. self.coin2_blind,
  452. )?;
  453. let coin_commit_r =
  454. FixedPoint::from_inner(ecc_chip.clone(), OrchardFixedBasesFull::ValueCommitR);
  455. coin_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), coin2_blind)?
  456. };
  457. let coin2_commit = com2.add(layouter.namespace(|| "nonce commit"), &blind)?;
  458. let coin2_commit_x: AssignedCell<Fp, Fp> = coin2_commit.inner().x();
  459. let coin2_commit_y: AssignedCell<Fp, Fp> = coin2_commit.inner().y();
  460. // path is valid path to staked coin's commitment
  461. let path: Value<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
  462. self.path.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
  463. let merkle_inputs = MerklePath::construct(
  464. [config.merkle_chip_1(), config.merkle_chip_2()],
  465. OrchardHashDomains::MerkleCrh,
  466. self.cm_pos,
  467. path,
  468. );
  469. let coin_commit_prod: AssignedCell<Fp, Fp> = {
  470. let coin_commit_coordinates = coin_commit.inner();
  471. let res: AssignedCell<Fp, Fp> = ar_chip.mul(
  472. layouter.namespace(|| ""),
  473. &coin_commit_coordinates.x(),
  474. &coin_commit_coordinates.y(),
  475. )?;
  476. res
  477. };
  478. let computed_final_root = merkle_inputs
  479. .calculate_root(layouter.namespace(|| "calculate root"), coin_commit_prod)?;
  480. // lhs of the leader election lottery
  481. // * y as COMIT(root_sk||nonce, mau_y)
  482. // beging the commitment to the coin's secret key, coin's nonce, and
  483. // random value deriven from the epoch sampled random eta.
  484. let lottery_commit_msg: AssignedCell<Fp, Fp> = {
  485. let poseidon_message = [_root_sk, coin_nonce];
  486. let poseidon_hasher = PoseidonHash::<
  487. _,
  488. _,
  489. poseidon::P128Pow5T3,
  490. poseidon::ConstantLength<2>,
  491. 3,
  492. 2,
  493. >::init(
  494. config.poseidon_chip(), layouter.namespace(|| "Poseidon init")
  495. )?;
  496. let poseidon_output =
  497. poseidon_hasher.hash(layouter.namespace(|| "Poseidon hash"), poseidon_message)?;
  498. let poseidon_output: AssignedCell<Fp, Fp> = poseidon_output;
  499. poseidon_output
  500. };
  501. let com = {
  502. let y_commit_v = FixedPointBaseField::from_inner(ecc_chip.clone(), NullifierK);
  503. y_commit_v.mul(layouter.namespace(|| "coin commit v"), lottery_commit_msg)?
  504. };
  505. // r*G_2
  506. let (blind, _) = {
  507. let mau_y = ScalarFixed::new(
  508. ecc_chip.clone(),
  509. layouter.namespace(|| "mau_y scalar"),
  510. self.mau_y,
  511. )?;
  512. let y_commit_r =
  513. FixedPoint::from_inner(ecc_chip.clone(), OrchardFixedBasesFull::ValueCommitR);
  514. y_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), mau_y)?
  515. };
  516. let y_commit = com.add(layouter.namespace(|| "nonce commit"), &blind)?;
  517. let y_commit_base = y_commit.inner().x();
  518. // constraint rho as COMIT(PRF(root_sk||nonce), rho_mu)
  519. // r*G_2
  520. let (blind, _) = {
  521. let mau_rho = ScalarFixed::new(
  522. ecc_chip.clone(),
  523. layouter.namespace(|| "mau_rho scalar"),
  524. self.mau_rho,
  525. )?;
  526. let rho_commit_r =
  527. FixedPoint::from_inner(ecc_chip, OrchardFixedBasesFull::ValueCommitR);
  528. rho_commit_r.mul(layouter.namespace(|| "coin serial number commit R"), mau_rho)?
  529. };
  530. let rho_commit = com.add(layouter.namespace(|| "nonce commit"), &blind)?;
  531. let rho_commit_base = rho_commit.inner().x();
  532. // stakeholder absolute stake + 1 (epsilon)
  533. let stake_plus = ar_chip.add(layouter.namespace(|| ""), &one, &coin_value)?;
  534. let target =
  535. ar_chip.mul(layouter.namespace(|| "calculate target"), &sigma_scalar, &stake_plus)?;
  536. let y: Value<pallas::Base> = y_commit_base.value().cloned();
  537. let target: Value<pallas::Base> = target.value().cloned();
  538. less_than_chip.witness_less_than(
  539. layouter.namespace(|| "y < target"),
  540. target, //reversed for testing
  541. y,
  542. 0,
  543. true,
  544. )?;
  545. layouter.constrain_instance(
  546. coin_commit_x.cell(),
  547. config.primary,
  548. LEAD_COIN_COMMIT_X_OFFSET,
  549. )?;
  550. // constrain coin's pub key y value
  551. layouter.constrain_instance(
  552. coin_commit_y.cell(),
  553. config.primary,
  554. LEAD_COIN_COMMIT_Y_OFFSET,
  555. )?;
  556. layouter.constrain_instance(
  557. coin2_commit_x.cell(),
  558. config.primary,
  559. LEAD_COIN_COMMIT2_X_OFFSET,
  560. )?;
  561. // constrain coin's pub key y value
  562. layouter.constrain_instance(
  563. coin2_commit_y.cell(),
  564. config.primary,
  565. LEAD_COIN_COMMIT2_Y_OFFSET,
  566. )?;
  567. layouter.constrain_instance(coin2_nonce.cell(), config.primary, LEAD_COIN_NONCE2_OFFSET)?;
  568. layouter.constrain_instance(
  569. computed_final_root.cell(),
  570. config.primary,
  571. LEAD_COIN_COMMIT_PATH_OFFSET,
  572. )?;
  573. layouter.constrain_instance(coin_pk_x.cell(), config.primary, LEAD_COIN_PK_X_OFFSET)?;
  574. layouter.constrain_instance(coin_pk_y.cell(), config.primary, LEAD_COIN_PK_Y_OFFSET)?;
  575. // constrain coin's pub key x value
  576. layouter.constrain_instance(
  577. sn_commit.cell(),
  578. config.primary,
  579. LEAD_COIN_SERIAL_NUMBER_OFFSET,
  580. )?;
  581. layouter.constrain_instance(
  582. y_commit_base.cell(),
  583. config.primary,
  584. LEAD_Y_COMMIT_BASE_OFFSET,
  585. )?;
  586. layouter.constrain_instance(
  587. rho_commit_base.cell(),
  588. config.primary,
  589. LEAD_RHO_COMMIT_BASE_OFFSET,
  590. )?;
  591. Ok(())
  592. }
  593. }