dao.rs 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. use bitvec::prelude::*;
  2. use halo2_gadgets::{
  3. ecc::{
  4. chip::{EccChip, EccConfig},
  5. FixedPoint, FixedPointShort, Point,
  6. },
  7. poseidon::{Hash as PoseidonHash, Pow5Chip as PoseidonChip, Pow5Config as PoseidonConfig},
  8. primitives::{
  9. poseidon,
  10. poseidon::{ConstantLength, P128Pow5T3},
  11. },
  12. sinsemilla::{
  13. chip::{SinsemillaChip, SinsemillaConfig},
  14. merkle::{
  15. chip::{MerkleChip, MerkleConfig},
  16. MerklePath,
  17. },
  18. },
  19. utilities::{lookup_range_check::LookupRangeCheckConfig, UtilitiesInstructions},
  20. };
  21. use halo2_proofs::{
  22. arithmetic::Field,
  23. circuit::{AssignedCell, Layouter, SimpleFloorPlanner},
  24. dev::MockProver,
  25. plonk,
  26. plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
  27. };
  28. use incrementalmerkletree::{bridgetree::BridgeTree, Frontier, Tree};
  29. use log::debug;
  30. use pasta_curves::{
  31. arithmetic::{CurveAffine, FieldExt},
  32. group::{ff::PrimeField, Curve, Group},
  33. pallas,
  34. };
  35. use rand::rngs::OsRng;
  36. use simplelog::{ColorChoice::Auto, Config, LevelFilter, TermLogger, TerminalMode::Mixed};
  37. use darkfi::{
  38. crypto::{
  39. constants::{
  40. sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
  41. util::gen_const_array,
  42. OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV, MERKLE_DEPTH_ORCHARD,
  43. },
  44. keypair::Keypair,
  45. merkle_node::MerkleNode,
  46. schnorr::SchnorrSecret,
  47. util::{mod_r_p, pedersen_commitment_scalar},
  48. },
  49. Result,
  50. };
  51. #[derive(Clone)]
  52. pub struct VmConfig {
  53. primary: Column<InstanceColumn>,
  54. advices: [Column<Advice>; 10],
  55. ecc_config: EccConfig<OrchardFixedBases>,
  56. merkle_cfg1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  57. merkle_cfg2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  58. sinsemilla_cfg1: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  59. _sinsemilla_cfg2: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  60. poseidon_config: PoseidonConfig<pallas::Base, 3, 2>,
  61. }
  62. impl VmConfig {
  63. fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
  64. EccChip::construct(self.ecc_config.clone())
  65. }
  66. fn merkle_chip_1(
  67. &self,
  68. ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
  69. MerkleChip::construct(self.merkle_cfg1.clone())
  70. }
  71. fn merkle_chip_2(
  72. &self,
  73. ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
  74. MerkleChip::construct(self.merkle_cfg2.clone())
  75. }
  76. fn poseidon_chip(&self) -> PoseidonChip<pallas::Base, 3, 2> {
  77. PoseidonChip::construct(self.poseidon_config.clone())
  78. }
  79. }
  80. #[derive(Clone, Default)]
  81. pub struct ZkCircuit {
  82. a: Option<pallas::Base>, // contract address
  83. s: Option<pallas::Base>, // serial number
  84. t: Option<pallas::Base>, // treasury balance
  85. b_b: Option<pallas::Base>, // bulla blinding
  86. leaf_pos: Option<u32>,
  87. merkle_path: Option<[MerkleNode; 32]>,
  88. u: Option<pallas::Base>, // output 0 value
  89. p_x: Option<pallas::Base>, // output0 pub_x
  90. p_y: Option<pallas::Base>, // output0 pub_y
  91. b_m: Option<pallas::Base>, // output0 blind
  92. votes: Option<pallas::Base>,
  93. vote_blinds: Option<pallas::Scalar>,
  94. output_1_blind: Option<pallas::Scalar>,
  95. }
  96. impl UtilitiesInstructions<pallas::Base> for ZkCircuit {
  97. type Var = AssignedCell<pallas::Base, pallas::Base>;
  98. }
  99. impl Circuit<pallas::Base> for ZkCircuit {
  100. type Config = VmConfig;
  101. type FloorPlanner = SimpleFloorPlanner;
  102. fn without_witnesses(&self) -> Self {
  103. Self::default()
  104. }
  105. fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
  106. // Advice columns used in the circuit
  107. let advices = [
  108. meta.advice_column(),
  109. meta.advice_column(),
  110. meta.advice_column(),
  111. meta.advice_column(),
  112. meta.advice_column(),
  113. meta.advice_column(),
  114. meta.advice_column(),
  115. meta.advice_column(),
  116. meta.advice_column(),
  117. meta.advice_column(),
  118. ];
  119. // Fixed columns for the Sinsemilla generator lookup table
  120. let table_idx = meta.lookup_table_column();
  121. let lookup = (table_idx, meta.lookup_table_column(), meta.lookup_table_column());
  122. // Instance column used for public inputs
  123. let primary = meta.instance_column();
  124. meta.enable_equality(primary);
  125. // Permutation over all advice columns
  126. for advice in advices.iter() {
  127. meta.enable_equality(*advice);
  128. }
  129. // Poseidon requires four advice columns, while ECC incomplete addition
  130. // requires six. We can reduce the proof size by sharing fixed columns
  131. // between the ECC and Poseidon chips.
  132. // TODO: For multiple invocations perhaps they could/should be configured
  133. // in parallel rather than sharing?
  134. let lagrange_coeffs = [
  135. meta.fixed_column(),
  136. meta.fixed_column(),
  137. meta.fixed_column(),
  138. meta.fixed_column(),
  139. meta.fixed_column(),
  140. meta.fixed_column(),
  141. meta.fixed_column(),
  142. meta.fixed_column(),
  143. ];
  144. let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
  145. let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
  146. // Also use the first Lagrange coefficient column for loading global constants.
  147. meta.enable_constant(lagrange_coeffs[0]);
  148. // Use one of the right-most advice columns for all of our range checks.
  149. let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
  150. // Configuration for curve point operations.
  151. // This uses 10 advice columns and spans the whole circuit.
  152. let ecc_config = EccChip::<OrchardFixedBases>::configure(
  153. meta,
  154. advices,
  155. lagrange_coeffs,
  156. range_check.clone(),
  157. );
  158. // Configuration for the Poseidon hash
  159. let poseidon_config = PoseidonChip::configure::<P128Pow5T3>(
  160. meta,
  161. advices[6..9].try_into().unwrap(),
  162. advices[5],
  163. rc_a,
  164. rc_b,
  165. );
  166. // Configuration for a Sinsemilla hash instantiation and a
  167. // Merkle hash instantiation using this Sinsemilla instance.
  168. // Since the Sinsemilla config uses only 5 advice columns,
  169. // we can fit two instances side-by-side.
  170. let (sinsemilla_cfg1, merkle_cfg1) = {
  171. let sinsemilla_cfg1 = SinsemillaChip::configure(
  172. meta,
  173. advices[..5].try_into().unwrap(),
  174. advices[6],
  175. lagrange_coeffs[0],
  176. lookup,
  177. range_check.clone(),
  178. );
  179. let merkle_cfg1 = MerkleChip::configure(meta, sinsemilla_cfg1.clone());
  180. (sinsemilla_cfg1, merkle_cfg1)
  181. };
  182. let (_sinsemilla_cfg2, merkle_cfg2) = {
  183. let sinsemilla_cfg2 = SinsemillaChip::configure(
  184. meta,
  185. advices[5..].try_into().unwrap(),
  186. advices[7],
  187. lagrange_coeffs[1],
  188. lookup,
  189. range_check,
  190. );
  191. let merkle_cfg2 = MerkleChip::configure(meta, sinsemilla_cfg2.clone());
  192. (sinsemilla_cfg2, merkle_cfg2)
  193. };
  194. VmConfig {
  195. primary,
  196. advices,
  197. ecc_config,
  198. merkle_cfg1,
  199. merkle_cfg2,
  200. sinsemilla_cfg1,
  201. _sinsemilla_cfg2,
  202. poseidon_config,
  203. }
  204. }
  205. fn synthesize(
  206. &self,
  207. config: Self::Config,
  208. mut layouter: impl Layouter<pallas::Base>,
  209. ) -> std::result::Result<(), plonk::Error> {
  210. debug!("Entering synthesize()");
  211. // Load the Sinsemilla generator lookup table used by the whole circuit.
  212. SinsemillaChip::load(config.sinsemilla_cfg1.clone(), &mut layouter)?;
  213. // Construct the ECC chip.
  214. let ecc_chip = config.ecc_chip();
  215. // This constant one is used for short multiplication
  216. let one = self.load_private(
  217. layouter.namespace(|| "Load constant one"),
  218. config.advices[0],
  219. Some(pallas::Base::one()),
  220. )?;
  221. let contract_address = self.load_private(
  222. layouter.namespace(|| "Load contract address"),
  223. config.advices[0],
  224. self.a,
  225. )?;
  226. let serial_number = self.load_private(
  227. layouter.namespace(|| "Load serial number"),
  228. config.advices[0],
  229. self.s,
  230. )?;
  231. let treasury_balance = self.load_private(
  232. layouter.namespace(|| "Load treasury balance"),
  233. config.advices[0],
  234. self.t,
  235. )?;
  236. let bulla_blind = self.load_private(
  237. layouter.namespace(|| "Load bulla blind"),
  238. config.advices[0],
  239. self.b_b,
  240. )?;
  241. let output0_value = self.load_private(
  242. layouter.namespace(|| "Load output0 value"),
  243. config.advices[0],
  244. self.u,
  245. )?;
  246. let output0_pub_x = self.load_private(
  247. layouter.namespace(|| "Load output0 dest pub x"),
  248. config.advices[0],
  249. self.p_x,
  250. )?;
  251. let output0_pub_y = self.load_private(
  252. layouter.namespace(|| "Load output0 dest pub y"),
  253. config.advices[0],
  254. self.p_y,
  255. )?;
  256. let output0_blind = self.load_private(
  257. layouter.namespace(|| "Load output0 blind"),
  258. config.advices[0],
  259. self.b_m,
  260. )?;
  261. let votes = self.load_private(
  262. layouter.namespace(|| "Load votes summed"),
  263. config.advices[0],
  264. self.votes,
  265. )?;
  266. // Constrain the serial number
  267. println!("Serial in circuit: {:?}", serial_number.value());
  268. layouter.constrain_instance(serial_number.cell(), config.primary, 0)?;
  269. // Hash the treasury bulla
  270. let mut poseidon_message: Vec<AssignedCell<pallas::Base, pallas::Base>> =
  271. Vec::with_capacity(4);
  272. poseidon_message.push(contract_address);
  273. poseidon_message.push(serial_number);
  274. poseidon_message.push(treasury_balance);
  275. poseidon_message.push(bulla_blind);
  276. let hasher = PoseidonHash::<_, _, P128Pow5T3, ConstantLength<4>, 3, 2>::init(
  277. config.poseidon_chip(),
  278. layouter.namespace(|| "PoseidonHash init"),
  279. )?;
  280. let output = hasher.hash(
  281. layouter.namespace(|| "PoseidonHash hash"),
  282. poseidon_message.try_into().unwrap(),
  283. )?;
  284. let dao_bulla: AssignedCell<pallas::Base, pallas::Base> = output.into();
  285. // Constrain the merkle root
  286. let path: Option<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
  287. self.merkle_path.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
  288. let merkle_inputs = MerklePath::construct(
  289. config.merkle_chip_1(),
  290. config.merkle_chip_2(),
  291. OrchardHashDomains::MerkleCrh,
  292. self.leaf_pos,
  293. path,
  294. );
  295. let root = merkle_inputs
  296. .calculate_root(layouter.namespace(|| "Calculate merkle root"), dao_bulla)?;
  297. println!("Merkle root in circuit: {:?}", root.value());
  298. layouter.constrain_instance(root.cell(), config.primary, 1)?;
  299. // Hash output 0
  300. let mut poseidon_message: Vec<AssignedCell<pallas::Base, pallas::Base>> =
  301. Vec::with_capacity(4);
  302. poseidon_message.push(output0_value);
  303. poseidon_message.push(output0_pub_x);
  304. poseidon_message.push(output0_pub_y);
  305. poseidon_message.push(output0_blind);
  306. let hasher = PoseidonHash::<_, _, P128Pow5T3, ConstantLength<4>, 3, 2>::init(
  307. config.poseidon_chip(),
  308. layouter.namespace(|| "PoseidonHash init"),
  309. )?;
  310. let output = hasher.hash(
  311. layouter.namespace(|| "PoseidonHash hash"),
  312. poseidon_message.try_into().unwrap(),
  313. )?;
  314. let output0: AssignedCell<pallas::Base, pallas::Base> = output.into();
  315. println!("Output0 in circuit: {:?}", output0.value());
  316. // Constrain output 0
  317. layouter.constrain_instance(output0.cell(), config.primary, 2)?;
  318. // Commit to votes with votes_blind
  319. let (commitment, _) = {
  320. let value_commit_v = ValueCommitV;
  321. let value_commit_v = FixedPointShort::from_inner(ecc_chip.clone(), value_commit_v);
  322. value_commit_v.mul(layouter.namespace(|| "[value] ValueCommitV"), (votes, one))?
  323. };
  324. let (blind, _) = {
  325. let rcv = self.vote_blinds;
  326. let value_commit_r = OrchardFixedBasesFull::ValueCommitR;
  327. let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), value_commit_r);
  328. value_commit_r.mul(layouter.namespace(|| "[value_blind] ValueCommitR"), rcv)?
  329. };
  330. // Constrain votes_commit_x and votes_commit_y
  331. let votes_commit = commitment.add(layouter.namespace(|| "valuecommit"), &blind)?;
  332. println!("VoteComX in circuit: {:?}", votes_commit.inner().x().value());
  333. println!("VoteComY in circuit: {:?}", votes_commit.inner().y().value());
  334. layouter.constrain_instance(votes_commit.inner().x().cell(), config.primary, 3)?;
  335. layouter.constrain_instance(votes_commit.inner().y().cell(), config.primary, 4)?;
  336. // TODO: Enforce votes > 0
  337. // TODO: Output 1 (change) = treasury_balance - output0_value
  338. // Commit to output 1 value
  339. // Constrain output1_commit_x and output1_commit_y
  340. debug!("Exiting synthesize()");
  341. Ok(())
  342. }
  343. }
  344. fn main() -> Result<()> {
  345. let loglevel = match option_env!("RUST_LOG") {
  346. Some("debug") => LevelFilter::Debug,
  347. Some("trace") => LevelFilter::Trace,
  348. Some(_) | None => LevelFilter::Info,
  349. };
  350. TermLogger::init(loglevel, Config::default(), Mixed, Auto)?;
  351. /*
  352. let bincode = include_bytes!("../proof/dao.zk.bin");
  353. let zkbin = ZkBinary::decode(bincode)?;
  354. */
  355. // Contract address
  356. let a = pallas::Base::random(&mut OsRng);
  357. // Serial number
  358. let s = pallas::Base::random(&mut OsRng);
  359. // Money in treasury
  360. let t = pallas::Base::from(666);
  361. // Bulla blind
  362. let b_b = pallas::Base::random(&mut OsRng);
  363. let message = [a, s, t, b_b];
  364. let hasher = poseidon::Hash::<_, P128Pow5T3, ConstantLength<4>, 3, 2>::init();
  365. let bulla = hasher.hash(message);
  366. // Merkle tree of DAOs
  367. let mut tree = BridgeTree::<MerkleNode, 32>::new(100);
  368. let dao0 = pallas::Base::random(&mut OsRng);
  369. let dao2 = pallas::Base::random(&mut OsRng);
  370. tree.append(&MerkleNode(dao0));
  371. tree.witness();
  372. tree.append(&MerkleNode(bulla));
  373. tree.witness();
  374. tree.append(&MerkleNode(dao2));
  375. tree.witness();
  376. let (leaf_pos, merkle_path) = tree.authentication_path(&MerkleNode(bulla)).unwrap();
  377. let leaf_pos: u64 = leaf_pos.into();
  378. let leaf_pos = leaf_pos as u32;
  379. // Output 0:
  380. let output0_val = pallas::Base::from(42);
  381. let output0_dest = pallas::Point::random(&mut OsRng);
  382. let output0_coords = output0_dest.to_affine().coordinates().unwrap();
  383. let output0_blind = pallas::Base::random(&mut OsRng);
  384. let message = [output0_val, *output0_coords.x(), *output0_coords.y(), output0_blind];
  385. let hasher = poseidon::Hash::<_, P128Pow5T3, ConstantLength<4>, 3, 2>::init();
  386. let output0 = hasher.hash(message);
  387. let authority = Keypair::random(&mut OsRng);
  388. let _signature = authority.secret.sign(&output0.to_repr());
  389. let vote_1 = pallas::Base::from(44);
  390. let vote_2 = pallas::Base::from(13);
  391. // This is a NO vote
  392. let vote_3 = -pallas::Base::from(49);
  393. let vote_1_blind = pallas::Scalar::random(&mut OsRng);
  394. let vote_1_commit = pedersen_commitment_scalar(mod_r_p(vote_1), vote_1_blind);
  395. let vote_2_blind = pallas::Scalar::random(&mut OsRng);
  396. let vote_2_commit = pedersen_commitment_scalar(mod_r_p(vote_2), vote_2_blind);
  397. let vote_3_blind = pallas::Scalar::random(&mut OsRng);
  398. let vote_3_commit = pedersen_commitment_scalar(mod_r_p(vote_3), vote_3_blind);
  399. let vote_commit = vote_1_commit + vote_2_commit; //+ vote_3_commit;
  400. let vote_commit_coords = vote_commit.to_affine().coordinates().unwrap();
  401. let votes = vote_1 + vote_2; //+vote_3;
  402. let vote_blinds = vote_1_blind + vote_2_blind; //+ vote_3_blind;
  403. let output_1_blind = pallas::Scalar::random(&mut OsRng);
  404. /*
  405. let number = pallas::Base::from(u64::MAX).to_bytes();
  406. let bits = number.view_bits::<Lsb0>();
  407. println!("Positive: {:?}", bits);
  408. //let number = (-pallas::Base::from(u64::MAX)).to_bytes();
  409. let number = pallas::Base::from(0).to_bytes();
  410. let bits = number.view_bits::<Lsb0>();
  411. println!("Negative: {:?}", bits);
  412. */
  413. let circuit = ZkCircuit {
  414. a: Some(a),
  415. s: Some(s),
  416. t: Some(t),
  417. b_b: Some(b_b),
  418. leaf_pos: Some(leaf_pos),
  419. merkle_path: Some(merkle_path.try_into().unwrap()),
  420. u: Some(output0_val),
  421. p_x: Some(*output0_coords.x()),
  422. p_y: Some(*output0_coords.y()),
  423. b_m: Some(output0_blind),
  424. votes: Some(votes),
  425. vote_blinds: Some(vote_blinds),
  426. output_1_blind: Some(output_1_blind),
  427. };
  428. let public_inputs =
  429. vec![s, tree.root().inner(), output0, *vote_commit_coords.x(), *vote_commit_coords.y()];
  430. println!("{:#?}", public_inputs);
  431. let prover = MockProver::run(11, &circuit, vec![public_inputs]).unwrap();
  432. assert_eq!(prover.verify(), Ok(()));
  433. Ok(())
  434. }