vm.rs 46 KB

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