vm.rs 48 KB

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