vm.rs 46 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217
  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. pub(super) witnesses: Vec<Witness>,
  228. literals: Vec<(LitType, String)>,
  229. pub(super) 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().try_into()?;
  651. let rhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  652. heap[args[1].1].clone().try_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().try_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().try_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().try_into()?;
  679. let rhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().try_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().try_into()?;
  695. let rhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().try_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().try_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().try_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().try_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().try_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().try_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().try_into()?;
  786. let merkle_path = heap[args[1].1].clone().try_into()?;
  787. let leaf = heap[args[2].1].clone().try_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().try_into()?;
  804. let rhs = &heap[args[1].1].clone().try_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().try_into()?;
  818. let rhs = &heap[args[1].1].clone().try_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().try_into()?;
  832. let rhs = &heap[args[1].1].clone().try_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.try_into()?,
  873. )?;
  874. }
  875. 253 => {
  876. rangecheck253_chip.as_ref().unwrap().copy_range_check(
  877. layouter.namespace(|| "copy range check 253"),
  878. arg.try_into()?,
  879. )?;
  880. }
  881. x => {
  882. error!(target: "zk::vm", "Unsupported bit-range {} for range_check", x);
  883. return Err(plonk::Error::Synthesis)
  884. }
  885. }
  886. self.tracer.push_void();
  887. }
  888. Opcode::LessThanStrict => {
  889. trace!(target: "zk::vm", "Executing `LessThanStrict{:?}` opcode", opcode.1);
  890. let args = &opcode.1;
  891. let a = heap[args[0].1].clone().try_into()?;
  892. let b = heap[args[1].1].clone().try_into()?;
  893. lessthan_chip.as_ref().unwrap().copy_less_than(
  894. layouter.namespace(|| "copy a<b check"),
  895. a,
  896. b,
  897. 0,
  898. true,
  899. )?;
  900. self.tracer.push_void();
  901. }
  902. Opcode::LessThanLoose => {
  903. trace!(target: "zk::vm", "Executing `LessThanLoose{:?}` opcode", opcode.1);
  904. let args = &opcode.1;
  905. let a = heap[args[0].1].clone().try_into()?;
  906. let b = heap[args[1].1].clone().try_into()?;
  907. lessthan_chip.as_ref().unwrap().copy_less_than(
  908. layouter.namespace(|| "copy a<b check"),
  909. a,
  910. b,
  911. 0,
  912. false,
  913. )?;
  914. self.tracer.push_void();
  915. }
  916. Opcode::BoolCheck => {
  917. trace!(target: "zk::vm", "Executing `BoolCheck{:?}` opcode", opcode.1);
  918. let args = &opcode.1;
  919. let w = heap[args[0].1].clone().try_into()?;
  920. boolcheck_chip
  921. .as_ref()
  922. .unwrap()
  923. .small_range_check(layouter.namespace(|| "copy boolean check"), w)?;
  924. self.tracer.push_void();
  925. }
  926. Opcode::CondSelect => {
  927. trace!(target: "zk::vm", "Executing `CondSelect{:?}` opcode", opcode.1);
  928. let args = &opcode.1;
  929. let cond: AssignedCell<Fp, Fp> = heap[args[0].1].clone().try_into()?;
  930. let lhs: AssignedCell<Fp, Fp> = heap[args[1].1].clone().try_into()?;
  931. let rhs: AssignedCell<Fp, Fp> = heap[args[2].1].clone().try_into()?;
  932. let out: AssignedCell<Fp, Fp> =
  933. condselect_chip.as_ref().unwrap().conditional_select(
  934. &mut layouter.namespace(|| "cond_select"),
  935. lhs,
  936. rhs,
  937. cond,
  938. )?;
  939. trace!(target: "zk::vm", "Pushing assignment to heap address {}", heap.len());
  940. self.tracer.push_base(&out);
  941. heap.push(HeapVar::Base(out));
  942. }
  943. Opcode::ZeroCondSelect => {
  944. trace!(target: "zk::vm", "Executing `ZeroCondSelect{:?}` opcode", opcode.1);
  945. let args = &opcode.1;
  946. let lhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().try_into()?;
  947. let rhs: AssignedCell<Fp, Fp> = heap[args[1].1].clone().try_into()?;
  948. let out: AssignedCell<Fp, Fp> = zerocond_chip.as_ref().unwrap().assign(
  949. layouter.namespace(|| "zero_cond"),
  950. lhs,
  951. rhs,
  952. )?;
  953. trace!(target: "zk::vm", "Pushing assignment to heap address {}", heap.len());
  954. self.tracer.push_base(&out);
  955. heap.push(HeapVar::Base(out));
  956. }
  957. Opcode::ConstrainEqualBase => {
  958. trace!(target: "zk::vm", "Executing `ConstrainEqualBase{:?}` opcode", opcode.1);
  959. let args = &opcode.1;
  960. let lhs: AssignedCell<Fp, Fp> = heap[args[0].1].clone().try_into()?;
  961. let rhs: AssignedCell<Fp, Fp> = heap[args[1].1].clone().try_into()?;
  962. layouter.assign_region(
  963. || "constrain witnessed base equality",
  964. |mut region| region.constrain_equal(lhs.cell(), rhs.cell()),
  965. )?;
  966. self.tracer.push_void();
  967. }
  968. Opcode::ConstrainEqualPoint => {
  969. trace!(target: "zk::vm", "Executing `ConstrainEqualPoint{:?}` opcode", opcode.1);
  970. let args = &opcode.1;
  971. let lhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  972. heap[args[0].1].clone().try_into()?;
  973. let rhs: Point<pallas::Affine, EccChip<OrchardFixedBases>> =
  974. heap[args[1].1].clone().try_into()?;
  975. lhs.constrain_equal(
  976. layouter.namespace(|| "constrain ec point equality"),
  977. &rhs,
  978. )?;
  979. self.tracer.push_void();
  980. }
  981. Opcode::ConstrainInstance => {
  982. trace!(target: "zk::vm", "Executing `ConstrainInstance{:?}` opcode", opcode.1);
  983. let args = &opcode.1;
  984. let var: AssignedCell<Fp, Fp> = heap[args[0].1].clone().try_into()?;
  985. layouter.constrain_instance(
  986. var.cell(),
  987. config.primary,
  988. public_inputs_offset,
  989. )?;
  990. public_inputs_offset += 1;
  991. self.tracer.push_void();
  992. }
  993. Opcode::DebugPrint => {
  994. trace!(target: "zk::vm", "Executing `DebugPrint{:?}` opcode", opcode.1);
  995. let args = &opcode.1;
  996. println!("[ZKVM DEBUG] HEAP INDEX: {}", args[0].1);
  997. println!("[ZKVM DEBUG] {:#?}", heap[args[0].1]);
  998. self.tracer.push_void();
  999. }
  1000. Opcode::Noop => {
  1001. error!(target: "zk::vm", "Unsupported opcode");
  1002. return Err(plonk::Error::Synthesis)
  1003. }
  1004. }
  1005. }
  1006. self.tracer.assert_correct(self.opcodes.len());
  1007. trace!(target: "zk::vm", "Exiting synthesize() successfully");
  1008. Ok(())
  1009. }
  1010. }