vm.rs 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2023 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 std::collections::HashSet;
  19. use darkfi_sdk::crypto::constants::{
  20. sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
  21. util::gen_const_array,
  22. NullifierK, OrchardFixedBases, OrchardFixedBasesFull, ValueCommitV, MERKLE_DEPTH_ORCHARD,
  23. };
  24. use halo2_gadgets::{
  25. ecc::{
  26. chip::{EccChip, EccConfig},
  27. FixedPoint, FixedPointBaseField, FixedPointShort, NonIdentityPoint, Point, ScalarFixed,
  28. ScalarFixedShort, ScalarVar,
  29. },
  30. poseidon::{
  31. primitives as poseidon, Hash as PoseidonHash, Pow5Chip as PoseidonChip,
  32. Pow5Config as PoseidonConfig,
  33. },
  34. sinsemilla::{
  35. chip::{SinsemillaChip, SinsemillaConfig},
  36. merkle::{
  37. chip::{MerkleChip, MerkleConfig},
  38. MerklePath,
  39. },
  40. },
  41. utilities::lookup_range_check::LookupRangeCheckConfig,
  42. };
  43. use halo2_proofs::{
  44. arithmetic::Field,
  45. circuit::{floor_planner, AssignedCell, Layouter, Value},
  46. pasta::{group::Curve, pallas, Fp},
  47. plonk,
  48. plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
  49. };
  50. use log::{error, trace};
  51. pub use super::vm_heap::{HeapVar, Witness};
  52. use super::{
  53. assign_free_advice,
  54. gadget::{
  55. arithmetic::{ArithChip, ArithConfig, ArithInstruction},
  56. cond_select::{ConditionalSelectChip, ConditionalSelectConfig},
  57. less_than::{LessThanChip, LessThanConfig},
  58. native_range_check::{NativeRangeCheckChip, NativeRangeCheckConfig},
  59. small_range_check::{SmallRangeCheckChip, SmallRangeCheckConfig},
  60. zero_cond::{ZeroCondChip, ZeroCondConfig},
  61. },
  62. };
  63. use crate::zkas::{
  64. types::{HeapType, LitType},
  65. Opcode, ZkBinary,
  66. };
  67. /// Available chips/gadgets in the zkvm
  68. #[derive(Debug, Clone)]
  69. #[allow(clippy::large_enum_variant)]
  70. enum VmChip {
  71. /// ECC Chip
  72. Ecc(EccConfig<OrchardFixedBases>),
  73. /// Merkle tree chip (using Sinsemilla)
  74. Merkle(
  75. (
  76. MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  77. MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  78. ),
  79. ),
  80. /// Sinsemilla chip
  81. Sinsemilla(
  82. (
  83. SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  84. SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  85. ),
  86. ),
  87. /// Poseidon hash chip
  88. Poseidon(PoseidonConfig<pallas::Base, 3, 2>),
  89. /// Base field arithmetic chip
  90. Arithmetic(ArithConfig),
  91. /// 64 bit native range check
  92. NativeRange64(NativeRangeCheckConfig<3, 64, 22>),
  93. /// 253 bit native range check
  94. NativeRange253(NativeRangeCheckConfig<3, 253, 85>),
  95. /// 253 bit `a < b` check
  96. LessThan(LessThanConfig<3, 253, 85>),
  97. /// Boolean check
  98. BoolCheck(SmallRangeCheckConfig),
  99. /// Conditional selection
  100. CondSelect(ConditionalSelectConfig<pallas::Base>),
  101. /// Zero-Cond selection
  102. ZeroCond(ZeroCondConfig<pallas::Base>),
  103. }
  104. /// zkvm configuration
  105. #[derive(Clone)]
  106. pub struct VmConfig {
  107. /// Chips used in the circuit
  108. chips: Vec<VmChip>,
  109. /// Instance column used for public inputs
  110. primary: Column<InstanceColumn>,
  111. /// Advice column used to witness values
  112. witness: Column<Advice>,
  113. }
  114. impl VmConfig {
  115. fn ecc_chip(&self) -> Option<EccChip<OrchardFixedBases>> {
  116. let Some(VmChip::Ecc(ecc_config)) =
  117. self.chips.iter().find(|&c| matches!(c, VmChip::Ecc(_)))
  118. else {
  119. return None
  120. };
  121. Some(EccChip::construct(ecc_config.clone()))
  122. }
  123. fn merkle_chip_1(
  124. &self,
  125. ) -> Option<MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>> {
  126. let Some(VmChip::Merkle((merkle_cfg1, _))) =
  127. self.chips.iter().find(|&c| matches!(c, VmChip::Merkle(_)))
  128. else {
  129. return None
  130. };
  131. Some(MerkleChip::construct(merkle_cfg1.clone()))
  132. }
  133. fn merkle_chip_2(
  134. &self,
  135. ) -> Option<MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>> {
  136. let Some(VmChip::Merkle((_, merkle_cfg2))) =
  137. self.chips.iter().find(|&c| matches!(c, VmChip::Merkle(_)))
  138. else {
  139. return None
  140. };
  141. Some(MerkleChip::construct(merkle_cfg2.clone()))
  142. }
  143. fn poseidon_chip(&self) -> Option<PoseidonChip<pallas::Base, 3, 2>> {
  144. let Some(VmChip::Poseidon(poseidon_config)) =
  145. self.chips.iter().find(|&c| matches!(c, VmChip::Poseidon(_)))
  146. else {
  147. return None
  148. };
  149. Some(PoseidonChip::construct(poseidon_config.clone()))
  150. }
  151. fn arithmetic_chip(&self) -> Option<ArithChip<pallas::Base>> {
  152. let Some(VmChip::Arithmetic(arith_config)) =
  153. self.chips.iter().find(|&c| matches!(c, VmChip::Arithmetic(_)))
  154. else {
  155. return None
  156. };
  157. Some(ArithChip::construct(arith_config.clone()))
  158. }
  159. fn condselect_chip(&self) -> Option<ConditionalSelectChip<pallas::Base>> {
  160. let Some(VmChip::CondSelect(condselect_config)) =
  161. self.chips.iter().find(|&c| matches!(c, VmChip::CondSelect(_)))
  162. else {
  163. return None
  164. };
  165. Some(ConditionalSelectChip::construct(condselect_config.clone(), ()))
  166. }
  167. fn zerocond_chip(&self) -> Option<ZeroCondChip<pallas::Base>> {
  168. let Some(VmChip::ZeroCond(zerocond_config)) =
  169. self.chips.iter().find(|&c| matches!(c, VmChip::ZeroCond(_)))
  170. else {
  171. return None
  172. };
  173. Some(ZeroCondChip::construct(zerocond_config.clone()))
  174. }
  175. fn rangecheck64_chip(&self) -> Option<NativeRangeCheckChip<3, 64, 22>> {
  176. let Some(VmChip::NativeRange64(range_config)) =
  177. self.chips.iter().find(|&c| matches!(c, VmChip::NativeRange64(_)))
  178. else {
  179. return None
  180. };
  181. Some(NativeRangeCheckChip::construct(range_config.clone()))
  182. }
  183. fn rangecheck253_chip(&self) -> Option<NativeRangeCheckChip<3, 253, 85>> {
  184. let Some(VmChip::NativeRange253(range_config)) =
  185. self.chips.iter().find(|&c| matches!(c, VmChip::NativeRange253(_)))
  186. else {
  187. return None
  188. };
  189. Some(NativeRangeCheckChip::construct(range_config.clone()))
  190. }
  191. fn lessthan_chip(&self) -> Option<LessThanChip<3, 253, 85>> {
  192. let Some(VmChip::LessThan(lessthan_config)) =
  193. self.chips.iter().find(|&c| matches!(c, VmChip::LessThan(_)))
  194. else {
  195. return None
  196. };
  197. Some(LessThanChip::construct(lessthan_config.clone()))
  198. }
  199. fn boolcheck_chip(&self) -> Option<SmallRangeCheckChip> {
  200. let Some(VmChip::BoolCheck(boolcheck_config)) =
  201. self.chips.iter().find(|&c| matches!(c, VmChip::BoolCheck(_)))
  202. else {
  203. return None
  204. };
  205. Some(SmallRangeCheckChip::construct(boolcheck_config.clone()))
  206. }
  207. }
  208. /// Configuration parameters for the circuit.
  209. /// Defines which chips we need to initialize and configure.
  210. #[derive(Default)]
  211. #[allow(dead_code)]
  212. pub struct ZkParams {
  213. init_ecc: bool,
  214. init_poseidon: bool,
  215. init_sinsemilla: bool,
  216. init_arithmetic: bool,
  217. init_nativerange: bool,
  218. init_lessthan: bool,
  219. init_boolcheck: bool,
  220. init_condselect: bool,
  221. init_zerocond: bool,
  222. }
  223. #[derive(Clone)]
  224. pub struct ZkCircuit {
  225. constants: Vec<String>,
  226. witnesses: Vec<Witness>,
  227. literals: Vec<(LitType, String)>,
  228. opcodes: Vec<(Opcode, Vec<(HeapType, usize)>)>,
  229. }
  230. impl ZkCircuit {
  231. pub fn new(witnesses: Vec<Witness>, circuit_code: &ZkBinary) -> Self {
  232. let constants = circuit_code.constants.iter().map(|x| x.1.clone()).collect();
  233. #[allow(clippy::map_clone)]
  234. let literals = circuit_code.literals.iter().map(|x| x.clone()).collect();
  235. Self { constants, witnesses, literals, opcodes: circuit_code.opcodes.clone() }
  236. }
  237. }
  238. impl Circuit<pallas::Base> for ZkCircuit {
  239. type Config = VmConfig;
  240. type FloorPlanner = floor_planner::V1;
  241. type Params = ZkParams;
  242. fn without_witnesses(&self) -> Self {
  243. Self {
  244. constants: self.constants.clone(),
  245. witnesses: self.witnesses.clone(),
  246. literals: self.literals.clone(),
  247. opcodes: self.opcodes.clone(),
  248. }
  249. }
  250. fn configure(_meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
  251. unreachable!();
  252. }
  253. fn params(&self) -> Self::Params {
  254. // Gather all opcodes used in the circuit.
  255. let mut opcodes = HashSet::new();
  256. for (opcode, _) in &self.opcodes {
  257. opcodes.insert(opcode);
  258. }
  259. // Conditions on which we enable the ECC chip
  260. let init_ecc = !self.constants.is_empty() ||
  261. opcodes.contains(&Opcode::EcAdd) ||
  262. opcodes.contains(&Opcode::EcMul) ||
  263. opcodes.contains(&Opcode::EcMulBase) ||
  264. opcodes.contains(&Opcode::EcMulShort) ||
  265. opcodes.contains(&Opcode::EcMulVarBase) ||
  266. opcodes.contains(&Opcode::EcGetX) ||
  267. opcodes.contains(&Opcode::EcGetY) ||
  268. opcodes.contains(&Opcode::ConstrainEqualPoint) ||
  269. self.witnesses.iter().any(|x| {
  270. matches!(x, Witness::EcPoint(_)) ||
  271. matches!(x, Witness::EcNiPoint(_)) ||
  272. matches!(x, Witness::EcFixedPoint(_)) ||
  273. matches!(x, Witness::Scalar(_))
  274. });
  275. // Conditions on which we enable the Poseidon hash chip
  276. let init_poseidon = opcodes.contains(&Opcode::PoseidonHash);
  277. // Conditions on which we enable the Sinsemilla and Merkle chips
  278. let init_sinsemilla = opcodes.contains(&Opcode::MerkleRoot);
  279. // Conditions on which we enable the base field Arithmetic chip
  280. let init_arithmetic = opcodes.contains(&Opcode::BaseAdd) ||
  281. opcodes.contains(&Opcode::BaseSub) ||
  282. opcodes.contains(&Opcode::BaseMul);
  283. // Conditions on which we enable the native range check chips
  284. // TODO: Separate 253 and 64.
  285. let init_nativerange = opcodes.contains(&Opcode::RangeCheck) ||
  286. opcodes.contains(&Opcode::LessThanLoose) ||
  287. opcodes.contains(&Opcode::LessThanStrict);
  288. // Conditions on which we enable the less than comparison chip
  289. let init_lessthan =
  290. opcodes.contains(&Opcode::LessThanLoose) || opcodes.contains(&Opcode::LessThanStrict);
  291. // Conditions on which we enable the boolean check chip
  292. let init_boolcheck = opcodes.contains(&Opcode::BoolCheck);
  293. // Conditions on which we enable the conditional selection chip
  294. let init_condselect = opcodes.contains(&Opcode::CondSelect);
  295. // Conditions on which we enable the zero cond selection chip
  296. let init_zerocond = opcodes.contains(&Opcode::ZeroCondSelect);
  297. ZkParams {
  298. init_ecc,
  299. init_poseidon,
  300. init_sinsemilla,
  301. init_arithmetic,
  302. init_nativerange,
  303. init_lessthan,
  304. init_boolcheck,
  305. init_condselect,
  306. init_zerocond,
  307. }
  308. }
  309. fn configure_with_params(
  310. meta: &mut ConstraintSystem<pallas::Base>,
  311. _params: Self::Params,
  312. ) -> Self::Config {
  313. // Advice columns used in the circuit
  314. let mut advices = vec![];
  315. for _ in 0..10 {
  316. advices.push(meta.advice_column());
  317. }
  318. // Instance column used for public inputs
  319. let primary = meta.instance_column();
  320. meta.enable_equality(primary);
  321. // Permutation over all advice columns
  322. for advice in advices.iter() {
  323. meta.enable_equality(*advice);
  324. }
  325. // Fixed columns for the Sinsemilla generator lookup table
  326. let table_idx = meta.lookup_table_column();
  327. let lookup = (table_idx, meta.lookup_table_column(), meta.lookup_table_column());
  328. // Poseidon requires four advice columns, while ECC incomplete addition
  329. // requires six. We can reduce the proof size by sharing fixed columns
  330. // between the ECC and Poseidon chips.
  331. // TODO: For multiple invocations perhaps they could/should be configured
  332. // in parallel rather than sharing?
  333. let lagrange_coeffs = [
  334. meta.fixed_column(),
  335. meta.fixed_column(),
  336. meta.fixed_column(),
  337. meta.fixed_column(),
  338. meta.fixed_column(),
  339. meta.fixed_column(),
  340. meta.fixed_column(),
  341. meta.fixed_column(),
  342. ];
  343. let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
  344. let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
  345. // Also use the first Lagrange coefficient column for loading global constants.
  346. meta.enable_constant(lagrange_coeffs[0]);
  347. // Use one of the right-most advice columns for all of our range checks.
  348. let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
  349. // Configuration for curve point operations.
  350. // This uses 10 advice columns and spans the whole circuit.
  351. let ecc_config = EccChip::<OrchardFixedBases>::configure(
  352. meta,
  353. advices[0..10].try_into().unwrap(),
  354. lagrange_coeffs,
  355. range_check,
  356. );
  357. // Configuration for the Poseidon hash
  358. let poseidon_config = PoseidonChip::configure::<poseidon::P128Pow5T3>(
  359. meta,
  360. advices[6..9].try_into().unwrap(),
  361. advices[5],
  362. rc_a,
  363. rc_b,
  364. );
  365. // Configuration for the Arithmetic chip
  366. let arith_config = ArithChip::configure(meta, advices[7], advices[8], advices[6]);
  367. // Configuration for a Sinsemilla hash instantiation and a
  368. // Merkle hash instantiation using this Sinsemilla instance.
  369. // Since the Sinsemilla config uses only 5 advice columns,
  370. // we can fit two instances side-by-side.
  371. let (sinsemilla_cfg1, merkle_cfg1) = {
  372. let sinsemilla_cfg1 = SinsemillaChip::configure(
  373. meta,
  374. advices[..5].try_into().unwrap(),
  375. advices[6],
  376. lagrange_coeffs[0],
  377. lookup,
  378. range_check,
  379. );
  380. let merkle_cfg1 = MerkleChip::configure(meta, sinsemilla_cfg1.clone());
  381. (sinsemilla_cfg1, merkle_cfg1)
  382. };
  383. let (sinsemilla_cfg2, merkle_cfg2) = {
  384. let sinsemilla_cfg2 = SinsemillaChip::configure(
  385. meta,
  386. advices[5..].try_into().unwrap(),
  387. advices[7],
  388. lagrange_coeffs[1],
  389. lookup,
  390. range_check,
  391. );
  392. let merkle_cfg2 = MerkleChip::configure(meta, sinsemilla_cfg2.clone());
  393. (sinsemilla_cfg2, merkle_cfg2)
  394. };
  395. // K-table for 64 bit range check lookups
  396. let k_values_table_64 = meta.lookup_table_column();
  397. let native_64_range_check_config =
  398. NativeRangeCheckChip::<3, 64, 22>::configure(meta, advices[8], k_values_table_64);
  399. // K-table for 253 bit range check lookups
  400. let k_values_table_253 = meta.lookup_table_column();
  401. let native_253_range_check_config =
  402. NativeRangeCheckChip::<3, 253, 85>::configure(meta, advices[8], k_values_table_253);
  403. // TODO: FIXME: Configure these better, this is just a stop-gap
  404. let z1 = meta.advice_column();
  405. let z2 = meta.advice_column();
  406. let lessthan_config = LessThanChip::<3, 253, 85>::configure(
  407. meta,
  408. advices[6],
  409. advices[7],
  410. advices[8],
  411. z1,
  412. z2,
  413. k_values_table_253,
  414. );
  415. // Configuration for boolean checks, it uses the small_range_check
  416. // chip with a range of 2, which enforces one bit, i.e. 0 or 1.
  417. let boolcheck_config = SmallRangeCheckChip::configure(meta, advices[9], 2);
  418. // Configuration for the conditional selection chip
  419. let condselect_config =
  420. ConditionalSelectChip::configure(meta, advices[1..5].try_into().unwrap());
  421. // Configuration for the zero_cond selection chip
  422. let zerocond_config = ZeroCondChip::configure(meta, advices[1..5].try_into().unwrap());
  423. // Later we'll use this for optimisation
  424. let chips = vec![
  425. VmChip::Ecc(ecc_config),
  426. VmChip::Merkle((merkle_cfg1, merkle_cfg2)),
  427. VmChip::Sinsemilla((sinsemilla_cfg1, sinsemilla_cfg2)),
  428. VmChip::Poseidon(poseidon_config),
  429. VmChip::Arithmetic(arith_config),
  430. VmChip::NativeRange64(native_64_range_check_config),
  431. VmChip::NativeRange253(native_253_range_check_config),
  432. VmChip::LessThan(lessthan_config),
  433. VmChip::BoolCheck(boolcheck_config),
  434. VmChip::CondSelect(condselect_config),
  435. VmChip::ZeroCond(zerocond_config),
  436. ];
  437. VmConfig { primary, witness: advices[0], chips }
  438. }
  439. fn synthesize(
  440. &self,
  441. config: Self::Config,
  442. mut layouter: impl Layouter<pallas::Base>,
  443. ) -> std::result::Result<(), plonk::Error> {
  444. trace!(target: "zk::vm", "Entering synthesize()");
  445. // ===================
  446. // VM Setup
  447. //====================
  448. // Our heap which holds every variable we reference and create.
  449. let mut heap: Vec<HeapVar> = vec![];
  450. // Our heap which holds all the literal values we have in the circuit.
  451. // For now, we only support u64.
  452. let mut litheap: Vec<u64> = vec![];
  453. // Offset for public inputs
  454. let mut public_inputs_offset = 0;
  455. // Offset for literals
  456. let mut literals_offset = 0;
  457. // Load the Sinsemilla generator lookup table used by the whole circuit.
  458. if let Some(VmChip::Sinsemilla((sinsemilla_cfg1, _))) =
  459. config.chips.iter().find(|&c| matches!(c, VmChip::Sinsemilla(_)))
  460. {
  461. trace!(target: "zk::vm", "Initializing Sinsemilla generator lookup table");
  462. SinsemillaChip::load(sinsemilla_cfg1.clone(), &mut layouter)?;
  463. }
  464. // Construct the 64-bit NativeRangeCheck chip
  465. let rangecheck64_chip = config.rangecheck64_chip();
  466. if let Some(VmChip::NativeRange64(rangecheck64_config)) =
  467. config.chips.iter().find(|&c| matches!(c, VmChip::NativeRange64(_)))
  468. {
  469. trace!(target: "zk::vm", "Initializing k table for 64bit NativeRangeCheck");
  470. NativeRangeCheckChip::<3, 64, 22>::load_k_table(
  471. &mut layouter,
  472. rangecheck64_config.k_values_table,
  473. )?;
  474. }
  475. // Construct the 253-bit NativeRangeCheck and LessThan chips.
  476. let rangecheck253_chip = config.rangecheck253_chip();
  477. let lessthan_chip = config.lessthan_chip();
  478. if let Some(VmChip::NativeRange253(rangecheck253_config)) =
  479. config.chips.iter().find(|&c| matches!(c, VmChip::NativeRange253(_)))
  480. {
  481. trace!(target: "zk::vm", "Initializing k table for 253bit NativeRangeCheck");
  482. NativeRangeCheckChip::<3, 253, 85>::load_k_table(
  483. &mut layouter,
  484. rangecheck253_config.k_values_table,
  485. )?;
  486. }
  487. // Construct the ECC chip.
  488. let ecc_chip = config.ecc_chip();
  489. // Construct the Arithmetic chip.
  490. let arith_chip = config.arithmetic_chip();
  491. // Construct the boolean check chip.
  492. let boolcheck_chip = config.boolcheck_chip();
  493. // Construct the conditional selection chip
  494. let condselect_chip = config.condselect_chip();
  495. // Construct the zero_cond selection chip
  496. let zerocond_chip = config.zerocond_chip();
  497. // ==========================
  498. // Constants setup
  499. // ==========================
  500. // This constant one is used for short multiplication
  501. let one = assign_free_advice(
  502. layouter.namespace(|| "Load constant one"),
  503. config.witness,
  504. Value::known(pallas::Base::ONE),
  505. )?;
  506. layouter.assign_region(
  507. || "constrain constant",
  508. |mut region| region.constrain_constant(one.cell(), pallas::Base::ONE),
  509. )?;
  510. // ANCHOR: constant_init
  511. // Lookup and push constants onto the heap
  512. for constant in &self.constants {
  513. trace!(
  514. target: "zk::vm",
  515. "Pushing constant `{}` to heap address {}",
  516. constant.as_str(),
  517. heap.len()
  518. );
  519. match constant.as_str() {
  520. "VALUE_COMMIT_VALUE" => {
  521. let vcv = ValueCommitV;
  522. let vcv = FixedPointShort::from_inner(ecc_chip.as_ref().unwrap().clone(), vcv);
  523. heap.push(HeapVar::EcFixedPointShort(vcv));
  524. }
  525. "VALUE_COMMIT_RANDOM" => {
  526. let vcr = OrchardFixedBasesFull::ValueCommitR;
  527. let vcr = FixedPoint::from_inner(ecc_chip.as_ref().unwrap().clone(), vcr);
  528. heap.push(HeapVar::EcFixedPoint(vcr));
  529. }
  530. "NULLIFIER_K" => {
  531. let nfk = NullifierK;
  532. let nfk =
  533. FixedPointBaseField::from_inner(ecc_chip.as_ref().unwrap().clone(), nfk);
  534. heap.push(HeapVar::EcFixedPointBase(nfk));
  535. }
  536. _ => {
  537. error!(target: "zk::vm", "Invalid constant name: {}", constant.as_str());
  538. return Err(plonk::Error::Synthesis)
  539. }
  540. }
  541. }
  542. // ANCHOR_END: constant_init
  543. // ANCHOR: literals_init
  544. // Load the literals onto the literal heap
  545. // N.B. Only uint64 is supported right now.
  546. for literal in &self.literals {
  547. match literal.0 {
  548. LitType::Uint64 => match literal.1.parse::<u64>() {
  549. Ok(v) => litheap.push(v),
  550. Err(e) => {
  551. error!(target: "zk::vm", "Failed converting u64 literal: {}", e);
  552. return Err(plonk::Error::Synthesis)
  553. }
  554. },
  555. _ => {
  556. error!(target: "zk::vm", "Invalid literal: {:?}", literal);
  557. return Err(plonk::Error::Synthesis)
  558. }
  559. }
  560. }
  561. // ANCHOR_END: literals_init
  562. // ANCHOR: witness_init
  563. // Push the witnesses onto the heap, and potentially, if the witness
  564. // is in the Base field (like the entire circuit is), load it into a
  565. // table cell.
  566. for witness in &self.witnesses {
  567. match witness {
  568. Witness::EcPoint(w) => {
  569. trace!(target: "zk::vm", "Witnessing EcPoint into circuit");
  570. let point = Point::new(
  571. ecc_chip.as_ref().unwrap().clone(),
  572. layouter.namespace(|| "Witness EcPoint"),
  573. w.as_ref().map(|cm| cm.to_affine()),
  574. )?;
  575. trace!(target: "zk::vm", "Pushing EcPoint to heap address {}", heap.len());
  576. heap.push(HeapVar::EcPoint(point));
  577. }
  578. Witness::EcNiPoint(w) => {
  579. trace!(target: "zk::vm", "Witnessing EcNiPoint into circuit");
  580. let point = NonIdentityPoint::new(
  581. ecc_chip.as_ref().unwrap().clone(),
  582. layouter.namespace(|| "Witness EcNiPoint"),
  583. w.as_ref().map(|cm| cm.to_affine()),
  584. )?;
  585. trace!(target: "zk::vm", "Pushing EcNiPoint to heap address {}", heap.len());
  586. heap.push(HeapVar::EcNiPoint(point));
  587. }
  588. Witness::EcFixedPoint(_) => {
  589. error!(target: "zk::vm", "Unable to witness EcFixedPoint, this is unimplemented.");
  590. return Err(plonk::Error::Synthesis)
  591. }
  592. Witness::Base(w) => {
  593. trace!(target: "zk::vm", "Witnessing Base into circuit");
  594. let base = assign_free_advice(
  595. layouter.namespace(|| "Witness Base"),
  596. config.witness,
  597. *w,
  598. )?;
  599. trace!(target: "zk::vm", "Pushing Base to heap address {}", heap.len());
  600. heap.push(HeapVar::Base(base));
  601. }
  602. Witness::Scalar(w) => {
  603. // NOTE: Because the type in `halo2_gadgets` does not have a `Clone`
  604. // impl, we push scalars as-is to the heap. They get witnessed
  605. // when they get used.
  606. trace!(target: "zk::vm", "Pushing Scalar to heap address {}", heap.len());
  607. heap.push(HeapVar::Scalar(*w));
  608. }
  609. Witness::MerklePath(w) => {
  610. trace!(target: "zk::vm", "Witnessing MerklePath into circuit");
  611. let path: Value<[pallas::Base; MERKLE_DEPTH_ORCHARD]> =
  612. w.map(|typed_path| gen_const_array(|i| typed_path[i].inner()));
  613. trace!(target: "zk::vm", "Pushing MerklePath to heap address {}", heap.len());
  614. heap.push(HeapVar::MerklePath(path));
  615. }
  616. Witness::Uint32(w) => {
  617. trace!(target: "zk::vm", "Pushing Uint32 to heap address {}", heap.len());
  618. heap.push(HeapVar::Uint32(*w));
  619. }
  620. Witness::Uint64(w) => {
  621. trace!(target: "zk::vm", "Pushing Uint64 to heap address {}", heap.len());
  622. heap.push(HeapVar::Uint64(*w));
  623. }
  624. }
  625. }
  626. // ANCHOR_END: witness_init
  627. // =============================
  628. // And now, work through opcodes
  629. // =============================
  630. // TODO: Copy constraints
  631. // ANCHOR: opcode_begin
  632. for opcode in &self.opcodes {
  633. match opcode.0 {
  634. Opcode::EcAdd => {
  635. trace!(target: "zk::vm", "Executing `EcAdd{:?}` opcode", opcode.1);
  636. let args = &opcode.1;
  637. let lhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  638. heap[args[0].1].clone().into();
  639. let rhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  640. heap[args[1].1].clone().into();
  641. let ret = lhs.add(layouter.namespace(|| "EcAdd()"), &rhs)?;
  642. trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
  643. heap.push(HeapVar::EcPoint(ret));
  644. }
  645. // ANCHOR_END: opcode_begin
  646. Opcode::EcMul => {
  647. trace!(target: "zk::vm", "Executing `EcMul{:?}` opcode", opcode.1);
  648. let args = &opcode.1;
  649. let lhs: FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>> =
  650. heap[args[1].1].clone().into();
  651. let rhs = ScalarFixed::new(
  652. ecc_chip.as_ref().unwrap().clone(),
  653. layouter.namespace(|| "EcMul: ScalarFixed::new()"),
  654. heap[args[0].1].clone().into(),
  655. )?;
  656. let (ret, _) = lhs.mul(layouter.namespace(|| "EcMul()"), rhs)?;
  657. trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
  658. heap.push(HeapVar::EcPoint(ret));
  659. }
  660. Opcode::EcMulVarBase => {
  661. trace!(target: "zk::vm", "Executing `EcMulVarBase{:?}` opcode", opcode.1);
  662. let args = &opcode.1;
  663. let lhs: NonIdentityPoint<pallas::Affine, EccChip<OrchardFixedBases>> =
  664. heap[args[1].1].clone().into();
  665. let rhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
  666. let rhs = ScalarVar::from_base(
  667. ecc_chip.as_ref().unwrap().clone(),
  668. layouter.namespace(|| "EcMulVarBase::from_base()"),
  669. &rhs,
  670. )?;
  671. let (ret, _) = lhs.mul(layouter.namespace(|| "EcMulVarBase()"), rhs)?;
  672. trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
  673. heap.push(HeapVar::EcPoint(ret));
  674. }
  675. Opcode::EcMulBase => {
  676. trace!(target: "zk::vm", "Executing `EcMulBase{:?}` opcode", opcode.1);
  677. let args = &opcode.1;
  678. let lhs: FixedPointBaseField<pallas::Affine, EccChip<OrchardFixedBases>> =
  679. heap[args[1].1].clone().into();
  680. let rhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
  681. let ret = lhs.mul(layouter.namespace(|| "EcMulBase()"), rhs)?;
  682. trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
  683. heap.push(HeapVar::EcPoint(ret));
  684. }
  685. Opcode::EcMulShort => {
  686. trace!(target: "zk::vm", "Executing `EcMulShort{:?}` opcode", opcode.1);
  687. let args = &opcode.1;
  688. let lhs: FixedPointShort<pallas::Affine, EccChip<OrchardFixedBases>> =
  689. heap[args[1].1].clone().into();
  690. let rhs = ScalarFixedShort::new(
  691. ecc_chip.as_ref().unwrap().clone(),
  692. layouter.namespace(|| "EcMulShort: ScalarFixedShort::new()"),
  693. (heap[args[0].1].clone().into(), one.clone()),
  694. )?;
  695. let (ret, _) = lhs.mul(layouter.namespace(|| "EcMulShort()"), rhs)?;
  696. trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
  697. heap.push(HeapVar::EcPoint(ret));
  698. }
  699. Opcode::EcGetX => {
  700. trace!(target: "zk::vm", "Executing `EcGetX{:?}` opcode", opcode.1);
  701. let args = &opcode.1;
  702. let point: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  703. heap[args[0].1].clone().into();
  704. let ret = point.inner().x();
  705. trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
  706. heap.push(HeapVar::Base(ret));
  707. }
  708. Opcode::EcGetY => {
  709. trace!(target: "zk::vm", "Executing `EcGetY{:?}` opcode", opcode.1);
  710. let args = &opcode.1;
  711. let point: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  712. heap[args[0].1].clone().into();
  713. let ret = point.inner().y();
  714. trace!(target: "zk::vm", "Pushing result to heap address {}", heap.len());
  715. heap.push(HeapVar::Base(ret));
  716. }
  717. Opcode::PoseidonHash => {
  718. trace!(target: "zk::vm", "Executing `PoseidonHash{:?}` opcode", opcode.1);
  719. let args = &opcode.1;
  720. let mut poseidon_message: Vec<AssignedCell<Fp, Fp>> =
  721. Vec::with_capacity(args.len());
  722. for idx in args {
  723. poseidon_message.push(heap[idx.1].clone().into());
  724. }
  725. macro_rules! poseidon_hash {
  726. ($len:expr, $hasher:ident, $output:ident, $cell:ident) => {
  727. let $hasher = PoseidonHash::<
  728. _,
  729. _,
  730. poseidon::P128Pow5T3,
  731. poseidon::ConstantLength<$len>,
  732. 3,
  733. 2,
  734. >::init(
  735. config.poseidon_chip().unwrap(),
  736. layouter.namespace(|| "PoseidonHash init"),
  737. )?;
  738. let $output = $hasher.hash(
  739. layouter.namespace(|| "PoseidonHash hash"),
  740. poseidon_message.try_into().unwrap(),
  741. )?;
  742. let $cell: AssignedCell<Fp, Fp> = $output.into();
  743. trace!(target: "zk::vm", "Pushing hash to heap address {}", heap.len());
  744. heap.push(HeapVar::Base($cell));
  745. };
  746. }
  747. macro_rules! vla {
  748. ($args:ident, $a:ident, $b:ident, $c:ident, $($num:tt)*) => {
  749. match $args.len() {
  750. $($num => {
  751. poseidon_hash!($num, $a, $b, $c);
  752. })*
  753. _ => {
  754. error!(target: "zk::vm", "Unsupported poseidon hash for {} elements", $args.len());
  755. return Err(plonk::Error::Synthesis)
  756. }
  757. }
  758. };
  759. }
  760. vla!(args, a, b, c, 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16);
  761. }
  762. Opcode::MerkleRoot => {
  763. trace!(target: "zk::vm", "Executing `MerkleRoot{:?}` opcode", opcode.1);
  764. let args = &opcode.1;
  765. let leaf_pos = heap[args[0].1].clone().into();
  766. let merkle_path = heap[args[1].1].clone().into();
  767. let leaf = heap[args[2].1].clone().into();
  768. let merkle_inputs = MerklePath::construct(
  769. [config.merkle_chip_1().unwrap(), config.merkle_chip_2().unwrap()],
  770. OrchardHashDomains::MerkleCrh,
  771. leaf_pos,
  772. merkle_path,
  773. );
  774. let root = merkle_inputs
  775. .calculate_root(layouter.namespace(|| "MerkleRoot()"), leaf)?;
  776. trace!(target: "zk::vm", "Pushing merkle root to heap address {}", heap.len());
  777. heap.push(HeapVar::Base(root));
  778. }
  779. Opcode::BaseAdd => {
  780. trace!(target: "zk::vm", "Executing `BaseAdd{:?}` opcode", opcode.1);
  781. let args = &opcode.1;
  782. let lhs = &heap[args[0].1].clone().into();
  783. let rhs = &heap[args[1].1].clone().into();
  784. let sum = arith_chip.as_ref().unwrap().add(
  785. layouter.namespace(|| "BaseAdd()"),
  786. lhs,
  787. rhs,
  788. )?;
  789. trace!(target: "zk::vm", "Pushing sum to heap address {}", heap.len());
  790. heap.push(HeapVar::Base(sum));
  791. }
  792. Opcode::BaseMul => {
  793. trace!(target: "zk::vm", "Executing `BaseSub{:?}` opcode", opcode.1);
  794. let args = &opcode.1;
  795. let lhs = &heap[args[0].1].clone().into();
  796. let rhs = &heap[args[1].1].clone().into();
  797. let product = arith_chip.as_ref().unwrap().mul(
  798. layouter.namespace(|| "BaseMul()"),
  799. lhs,
  800. rhs,
  801. )?;
  802. trace!(target: "zk::vm", "Pushing product to heap address {}", heap.len());
  803. heap.push(HeapVar::Base(product));
  804. }
  805. Opcode::BaseSub => {
  806. trace!(target: "zk::vm", "Executing `BaseSub{:?}` opcode", opcode.1);
  807. let args = &opcode.1;
  808. let lhs = &heap[args[0].1].clone().into();
  809. let rhs = &heap[args[1].1].clone().into();
  810. let difference = arith_chip.as_ref().unwrap().sub(
  811. layouter.namespace(|| "BaseSub()"),
  812. lhs,
  813. rhs,
  814. )?;
  815. trace!(target: "zk::vm", "Pushing difference to heap address {}", heap.len());
  816. heap.push(HeapVar::Base(difference));
  817. }
  818. Opcode::WitnessBase => {
  819. trace!(target: "zk::vm", "Executing `WitnessBase{:?}` opcode", opcode.1);
  820. //let args = &opcode.1;
  821. let lit = litheap[literals_offset];
  822. literals_offset += 1;
  823. let witness = assign_free_advice(
  824. layouter.namespace(|| "Witness literal"),
  825. config.witness,
  826. Value::known(pallas::Base::from(lit)),
  827. )?;
  828. layouter.assign_region(
  829. || "constrain constant",
  830. |mut region| {
  831. region.constrain_constant(witness.cell(), pallas::Base::from(lit))
  832. },
  833. )?;
  834. trace!(target: "zk::vm", "Pushing assignment to heap address {}", heap.len());
  835. heap.push(HeapVar::Base(witness));
  836. }
  837. Opcode::RangeCheck => {
  838. trace!(target: "zk::vm", "Executing `RangeCheck{:?}` opcode", opcode.1);
  839. let args = &opcode.1;
  840. let lit = litheap[literals_offset];
  841. literals_offset += 1;
  842. let arg = heap[args[1].1].clone();
  843. match lit {
  844. 64 => {
  845. rangecheck64_chip.as_ref().unwrap().copy_range_check(
  846. layouter.namespace(|| "copy range check 64"),
  847. arg.into(),
  848. true,
  849. )?;
  850. }
  851. 253 => {
  852. rangecheck253_chip.as_ref().unwrap().copy_range_check(
  853. layouter.namespace(|| "copy range check 253"),
  854. arg.into(),
  855. true,
  856. )?;
  857. }
  858. x => {
  859. error!(target: "zk::vm", "Unsupported bit-range {} for range_check", x);
  860. return Err(plonk::Error::Synthesis)
  861. }
  862. }
  863. }
  864. Opcode::LessThanStrict => {
  865. trace!(target: "zk::vm", "Executing `LessThanStrict{:?}` opcode", opcode.1);
  866. let args = &opcode.1;
  867. let a = heap[args[0].1].clone().into();
  868. let b = heap[args[1].1].clone().into();
  869. lessthan_chip.as_ref().unwrap().copy_less_than(
  870. layouter.namespace(|| "copy a<b check"),
  871. a,
  872. b,
  873. 0,
  874. true,
  875. )?;
  876. }
  877. Opcode::LessThanLoose => {
  878. trace!(target: "zk::vm", "Executing `LessThanLoose{:?}` opcode", opcode.1);
  879. let args = &opcode.1;
  880. let a = heap[args[0].1].clone().into();
  881. let b = heap[args[1].1].clone().into();
  882. lessthan_chip.as_ref().unwrap().copy_less_than(
  883. layouter.namespace(|| "copy a<b check"),
  884. a,
  885. b,
  886. 0,
  887. false,
  888. )?;
  889. }
  890. Opcode::BoolCheck => {
  891. trace!(target: "zk::vm", "Executing `BoolCheck{:?}` opcode", opcode.1);
  892. let args = &opcode.1;
  893. let w = heap[args[0].1].clone().into();
  894. boolcheck_chip
  895. .as_ref()
  896. .unwrap()
  897. .small_range_check(layouter.namespace(|| "copy boolean check"), w)?;
  898. }
  899. Opcode::CondSelect => {
  900. trace!(target: "zk::vm", "Executing `CondSelect{:?}` opcode", opcode.1);
  901. let args = &opcode.1;
  902. let cond: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
  903. let lhs: AssignedCell<Fp, Fp> = heap[args[1].1].clone().into();
  904. let rhs: AssignedCell<Fp, Fp> = heap[args[2].1].clone().into();
  905. let out: AssignedCell<Fp, Fp> =
  906. condselect_chip.as_ref().unwrap().conditional_select(
  907. &mut layouter.namespace(|| "cond_select"),
  908. lhs,
  909. rhs,
  910. cond,
  911. )?;
  912. trace!(target: "zk::vm", "Pushing assignment to heap address {}", heap.len());
  913. heap.push(HeapVar::Base(out));
  914. }
  915. Opcode::ZeroCondSelect => {
  916. trace!(target: "zk::vm", "Executing `ZeroCondSelect{:?}` opcode", opcode.1);
  917. let args = &opcode.1;
  918. let lhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
  919. let rhs: AssignedCell<Fp, Fp> = heap[args[1].1].clone().into();
  920. let out: AssignedCell<Fp, Fp> = zerocond_chip.as_ref().unwrap().assign(
  921. layouter.namespace(|| "zero_cond"),
  922. lhs,
  923. rhs,
  924. )?;
  925. trace!(target: "zk::vm", "Pushing assignment to heap address {}", heap.len());
  926. heap.push(HeapVar::Base(out));
  927. }
  928. Opcode::ConstrainEqualBase => {
  929. trace!(target: "zk::vm", "Executing `ConstrainEqualBase{:?}` opcode", opcode.1);
  930. let args = &opcode.1;
  931. let lhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
  932. let rhs: AssignedCell<Fp, Fp> = heap[args[1].1].clone().into();
  933. layouter.assign_region(
  934. || "constrain witnessed base equality",
  935. |mut region| region.constrain_equal(lhs.cell(), rhs.cell()),
  936. )?;
  937. }
  938. Opcode::ConstrainEqualPoint => {
  939. trace!(target: "zk::vm", "Executing `ConstrainEqualPoint{:?}` opcode", opcode.1);
  940. let args = &opcode.1;
  941. let lhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  942. heap[args[0].1].clone().into();
  943. let rhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  944. heap[args[1].1].clone().into();
  945. lhs.constrain_equal(
  946. layouter.namespace(|| "constrain ec point equality"),
  947. &rhs,
  948. )?;
  949. }
  950. Opcode::ConstrainInstance => {
  951. trace!(target: "zk::vm", "Executing `ConstrainInstance{:?}` opcode", opcode.1);
  952. let args = &opcode.1;
  953. let var: AssignedCell<Fp, Fp> = heap[args[0].1].clone().into();
  954. layouter.constrain_instance(
  955. var.cell(),
  956. config.primary,
  957. public_inputs_offset,
  958. )?;
  959. public_inputs_offset += 1;
  960. }
  961. Opcode::DebugPrint => {
  962. trace!(target: "zk::vm", "Executing `DebugPrint{:?}` opcode", opcode.1);
  963. let args = &opcode.1;
  964. println!("[ZKVM DEBUG] HEAP INDEX: {}", args[0].1);
  965. println!("[ZKVM DEBUG] {:#?}", heap[args[0].1]);
  966. }
  967. Opcode::Noop => {
  968. error!(target: "zk::vm", "Unsupported opcode");
  969. return Err(plonk::Error::Synthesis)
  970. }
  971. }
  972. }
  973. trace!(target: "zk::vm", "Exiting synthesize() successfully");
  974. Ok(())
  975. }
  976. }