vm2.rs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. use halo2::{
  2. circuit::{Layouter, SimpleFloorPlanner},
  3. plonk,
  4. plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn},
  5. };
  6. use halo2_gadgets::{
  7. ecc::{
  8. chip::{EccChip, EccConfig},
  9. FixedPoint, Point,
  10. },
  11. poseidon::{Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig},
  12. primitives::poseidon::{ConstantLength, P128Pow5T3},
  13. sinsemilla::{
  14. chip::{SinsemillaChip, SinsemillaConfig},
  15. merkle::{
  16. chip::{MerkleChip, MerkleConfig},
  17. MerklePath,
  18. },
  19. },
  20. utilities::{
  21. lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
  22. },
  23. };
  24. use log::debug;
  25. use pasta_curves::pallas;
  26. use crate::{
  27. crypto::{
  28. constants::{
  29. sinsemilla::{OrchardCommitDomains, OrchardHashDomains},
  30. OrchardFixedBases,
  31. },
  32. merkle_node::MerkleNode,
  33. },
  34. zkas::{decoder::ZkBinary, opcode::Opcode},
  35. };
  36. // Stack type abstractions
  37. #[derive(Clone)]
  38. enum ConstantVar {
  39. EcFixedPoint(FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
  40. }
  41. #[derive(Clone)]
  42. pub enum WitnessVar {
  43. EcPoint(Point<pallas::Affine, EccChip<OrchardFixedBases>>),
  44. EcFixedPoint(FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>>),
  45. Base(pallas::Base),
  46. Scalar(pallas::Scalar),
  47. MerklePath(Vec<MerkleNode>),
  48. Uint32(u32),
  49. Uint64(u64),
  50. }
  51. #[derive(Clone)]
  52. enum StackVar {
  53. Constant(ConstantVar),
  54. Witness(WitnessVar),
  55. Cell(CellValue<pallas::Base>),
  56. }
  57. impl StackVar {
  58. fn to_ec_point(&self) -> Point<pallas::Affine, EccChip<OrchardFixedBases>> {
  59. let inner = match self {
  60. StackVar::Witness(v) => v,
  61. _ => unimplemented!(),
  62. };
  63. let inner = match inner {
  64. WitnessVar::EcPoint(v) => v,
  65. _ => unimplemented!(),
  66. };
  67. inner.clone()
  68. }
  69. fn to_fixed_point(&self) -> FixedPoint<pallas::Affine, EccChip<OrchardFixedBases>> {
  70. let inner = match self {
  71. StackVar::Witness(WitnessVar::EcFixedPoint(v)) => v,
  72. StackVar::Constant(ConstantVar::EcFixedPoint(v)) => v,
  73. _ => unimplemented!(),
  74. };
  75. inner.clone()
  76. }
  77. fn to_scalar(&self) -> pallas::Scalar {
  78. let inner = match self {
  79. StackVar::Witness(v) => v,
  80. _ => unimplemented!(),
  81. };
  82. let inner = match inner {
  83. WitnessVar::Scalar(v) => v,
  84. _ => unimplemented!(),
  85. };
  86. *inner
  87. }
  88. fn to_base(&self) -> CellValue<pallas::Base> {
  89. let inner = match self {
  90. StackVar::Cell(v) => v,
  91. _ => unimplemented!(),
  92. };
  93. *inner
  94. }
  95. }
  96. impl From<StackVar> for std::option::Option<u32> {
  97. fn from(value: StackVar) -> Self {
  98. match value {
  99. StackVar::Witness(WitnessVar::Uint32(v)) => Some(v),
  100. _ => unimplemented!(),
  101. }
  102. }
  103. }
  104. impl From<StackVar> for std::option::Option<u64> {
  105. fn from(value: StackVar) -> Self {
  106. match value {
  107. StackVar::Witness(WitnessVar::Uint64(v)) => Some(v),
  108. _ => unimplemented!(),
  109. }
  110. }
  111. }
  112. impl From<StackVar> for std::option::Option<[pallas::Base; 32]> {
  113. fn from(value: StackVar) -> Self {
  114. match value {
  115. StackVar::Witness(WitnessVar::MerklePath(v)) => {
  116. let ret: Vec<pallas::Base> = v.iter().map(|x| x.0).collect();
  117. Some(ret.try_into().unwrap())
  118. }
  119. _ => unimplemented!(),
  120. }
  121. }
  122. }
  123. impl From<StackVar> for CellValue<pallas::Base> {
  124. fn from(value: StackVar) -> Self {
  125. match value {
  126. StackVar::Cell(v) => v,
  127. _ => unimplemented!(),
  128. }
  129. }
  130. }
  131. #[derive(Clone)]
  132. #[allow(dead_code)]
  133. pub struct VmConfig {
  134. primary: Column<InstanceColumn>,
  135. advices: [Column<Advice>; 10],
  136. ecc_config: EccConfig,
  137. merkle_cfg1: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  138. merkle_cfg2: MerkleConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  139. sinsemilla_cfg1: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  140. sinsemilla_cfg2: SinsemillaConfig<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases>,
  141. poseidon_config: PoseidonConfig<pallas::Base>,
  142. }
  143. impl VmConfig {
  144. fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
  145. EccChip::construct(self.ecc_config.clone())
  146. }
  147. /*
  148. fn sinsemilla_chip_1(
  149. &self,
  150. ) -> SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
  151. SinsemillaChip::construct(self.sinsemilla_cfg1.clone())
  152. }
  153. fn sinsemilla_chip_2(
  154. &self,
  155. ) -> SinsemillaChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
  156. SinsemillaChip::construct(self.sinsemilla_cfg2.clone())
  157. }
  158. */
  159. fn merkle_chip_1(
  160. &self,
  161. ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
  162. MerkleChip::construct(self.merkle_cfg1.clone())
  163. }
  164. fn merkle_chip_2(
  165. &self,
  166. ) -> MerkleChip<OrchardHashDomains, OrchardCommitDomains, OrchardFixedBases> {
  167. MerkleChip::construct(self.merkle_cfg2.clone())
  168. }
  169. fn poseidon_chip(&self) -> PoseidonChip<pallas::Base> {
  170. PoseidonChip::construct(self.poseidon_config.clone())
  171. }
  172. }
  173. #[derive(Default)]
  174. pub struct ZkCircuit {
  175. constants: Vec<String>,
  176. witnesses: Vec<WitnessVar>,
  177. opcodes: Vec<(Opcode, Vec<u64>)>,
  178. pub public_inputs: Vec<pallas::Base>,
  179. }
  180. impl ZkCircuit {
  181. pub fn new(
  182. witnesses: Vec<WitnessVar>,
  183. public_inputs: Vec<pallas::Base>,
  184. circuit_code: ZkBinary,
  185. ) -> Self {
  186. let constants = circuit_code.constants.iter().map(|x| x.1.clone()).collect();
  187. Self { constants, witnesses, opcodes: circuit_code.opcodes, public_inputs }
  188. }
  189. }
  190. impl UtilitiesInstructions<pallas::Base> for ZkCircuit {
  191. type Var = CellValue<pallas::Base>;
  192. }
  193. impl Circuit<pallas::Base> for ZkCircuit {
  194. type Config = VmConfig;
  195. type FloorPlanner = SimpleFloorPlanner;
  196. fn without_witnesses(&self) -> Self {
  197. Self::default()
  198. }
  199. fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
  200. // Advice columns used in the circuit
  201. let advices = [
  202. meta.advice_column(),
  203. meta.advice_column(),
  204. meta.advice_column(),
  205. meta.advice_column(),
  206. meta.advice_column(),
  207. meta.advice_column(),
  208. meta.advice_column(),
  209. meta.advice_column(),
  210. meta.advice_column(),
  211. meta.advice_column(),
  212. ];
  213. // Fixed columns for the Sinsemilla generator lookup table
  214. let table_idx = meta.lookup_table_column();
  215. let lookup = (table_idx, meta.lookup_table_column(), meta.lookup_table_column());
  216. // Instance column used for public inputs
  217. let primary = meta.instance_column();
  218. meta.enable_equality(primary.into());
  219. // Permutation over all advice columns
  220. for advice in advices.iter() {
  221. meta.enable_equality((*advice).into());
  222. }
  223. // Poseidon requires four advice columns, while ECC incomplete addition
  224. // requires six. We can reduce the proof size by sharing fixed columns
  225. // between the ECC and Poseidon chips.
  226. // TODO: For multiple invocations perhaps they could/should be configured
  227. // in parallel rather than sharing?
  228. let lagrange_coeffs = [
  229. meta.fixed_column(),
  230. meta.fixed_column(),
  231. meta.fixed_column(),
  232. meta.fixed_column(),
  233. meta.fixed_column(),
  234. meta.fixed_column(),
  235. meta.fixed_column(),
  236. meta.fixed_column(),
  237. ];
  238. let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
  239. let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
  240. // Also use the first Lagrange coefficient column for loading global constants.
  241. meta.enable_constant(lagrange_coeffs[0]);
  242. // Use one of the right-most advice columns for all of our range checks.
  243. let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
  244. // Configuration for curve point operations.
  245. // This uses 10 advice columns and spans the whole circuit.
  246. let ecc_config = EccChip::<OrchardFixedBases>::configure(
  247. meta,
  248. advices,
  249. lagrange_coeffs,
  250. range_check.clone(),
  251. );
  252. // Configuration for the Poseidon hash
  253. let poseidon_config = PoseidonChip::configure(
  254. meta,
  255. P128Pow5T3,
  256. advices[6..9].try_into().unwrap(),
  257. advices[5],
  258. rc_a,
  259. rc_b,
  260. );
  261. // Configuration for a Sinsemilla hash instantiation and a
  262. // Merkle hash instantiation using this Sinsemilla instance.
  263. // Since the Sinsemilla config uses only 5 advice columns,
  264. // we can fit two instances side-by-side.
  265. let (sinsemilla_cfg1, merkle_cfg1) = {
  266. let sinsemilla_cfg1 = SinsemillaChip::configure(
  267. meta,
  268. advices[..5].try_into().unwrap(),
  269. advices[6],
  270. lagrange_coeffs[0],
  271. lookup,
  272. range_check.clone(),
  273. );
  274. let merkle_cfg1 = MerkleChip::configure(meta, sinsemilla_cfg1.clone());
  275. (sinsemilla_cfg1, merkle_cfg1)
  276. };
  277. let (sinsemilla_cfg2, merkle_cfg2) = {
  278. let sinsemilla_cfg2 = SinsemillaChip::configure(
  279. meta,
  280. advices[5..].try_into().unwrap(),
  281. advices[7],
  282. lagrange_coeffs[1],
  283. lookup,
  284. range_check,
  285. );
  286. let merkle_cfg2 = MerkleChip::configure(meta, sinsemilla_cfg2.clone());
  287. (sinsemilla_cfg2, merkle_cfg2)
  288. };
  289. VmConfig {
  290. primary,
  291. advices,
  292. ecc_config,
  293. merkle_cfg1,
  294. merkle_cfg2,
  295. sinsemilla_cfg1,
  296. sinsemilla_cfg2,
  297. poseidon_config,
  298. }
  299. }
  300. fn synthesize(
  301. &self,
  302. config: Self::Config,
  303. mut layouter: impl Layouter<pallas::Base>,
  304. ) -> std::result::Result<(), plonk::Error> {
  305. debug!("Entering synthesize()");
  306. // Our stack which holds everything we reference
  307. let mut stack: Vec<StackVar> = vec![];
  308. // Offset for public inputs
  309. let mut public_inputs_offset = 0;
  310. // Load the Sinsemilla generator lookup table used by the whole circuit.
  311. SinsemillaChip::load(config.sinsemilla_cfg1.clone(), &mut layouter)?;
  312. // Construct the ECC chip.
  313. let ecc_chip = config.ecc_chip();
  314. // Construct the Merkle chips
  315. let merkle_chip_1 = config.merkle_chip_1();
  316. let merkle_chip_2 = config.merkle_chip_2();
  317. // This constant one is used for short multiplication
  318. let one = self.load_private(
  319. layouter.namespace(|| "Load constant one"),
  320. config.advices[0],
  321. Some(pallas::Base::one()),
  322. )?;
  323. for constant in &self.constants {
  324. debug!("Pushing constant `{}` to stack index {}", constant.as_str(), stack.len());
  325. match constant.as_str() {
  326. "VALUE_COMMIT_VALUE" => {
  327. let vcv = OrchardFixedBases::ValueCommitV;
  328. let vcv = FixedPoint::from_inner(ecc_chip.clone(), vcv);
  329. stack.push(StackVar::Constant(ConstantVar::EcFixedPoint(vcv)));
  330. }
  331. "VALUE_COMMIT_RANDOM" => {
  332. let vcr = OrchardFixedBases::ValueCommitR;
  333. let vcr = FixedPoint::from_inner(ecc_chip.clone(), vcr);
  334. stack.push(StackVar::Constant(ConstantVar::EcFixedPoint(vcr)));
  335. }
  336. "NULLIFIER_K" => {
  337. let nfk = OrchardFixedBases::NullifierK;
  338. let nfk = FixedPoint::from_inner(ecc_chip.clone(), nfk);
  339. stack.push(StackVar::Constant(ConstantVar::EcFixedPoint(nfk)));
  340. }
  341. _ => unimplemented!(),
  342. }
  343. }
  344. for witness in &self.witnesses {
  345. match witness {
  346. WitnessVar::EcPoint(_) => {
  347. debug!("Pushing EcPoint to stack index {}", stack.len());
  348. stack.push(StackVar::Witness(witness.clone()));
  349. }
  350. WitnessVar::EcFixedPoint(_) => {
  351. debug!("Pushing EcFixedPoint to stack index {}", stack.len());
  352. stack.push(StackVar::Witness(witness.clone()));
  353. }
  354. WitnessVar::Base(v) => {
  355. debug!("Loading Base element into cell");
  356. let w = self.load_private(
  357. layouter.namespace(|| "Load witness into cell"),
  358. config.advices[0],
  359. Some(*v),
  360. )?;
  361. debug!("Pushing Base to stack index {}", stack.len());
  362. stack.push(StackVar::Cell(w));
  363. }
  364. WitnessVar::Scalar(_) => {
  365. debug!("Pushing Scalar to stack index {}", stack.len());
  366. stack.push(StackVar::Witness(witness.clone()));
  367. }
  368. WitnessVar::MerklePath(_) => {
  369. debug!("Pushing MerklePath to stack index {}", stack.len());
  370. stack.push(StackVar::Witness(witness.clone()));
  371. }
  372. WitnessVar::Uint32(_) => {
  373. debug!("Pushing Uint32 to stack index {}", stack.len());
  374. stack.push(StackVar::Witness(witness.clone()));
  375. }
  376. WitnessVar::Uint64(_) => {
  377. debug!("Pushing Uint64 to stack index {}", stack.len());
  378. stack.push(StackVar::Witness(witness.clone()));
  379. }
  380. }
  381. }
  382. // TODO: Guard usize casts
  383. for opcode in &self.opcodes {
  384. match opcode.0 {
  385. Opcode::EcAdd => {
  386. debug!("Executing `EcAdd{:?}` opcode", opcode.1);
  387. let args = opcode.1.clone();
  388. let lhs = stack[args[0] as usize].to_ec_point();
  389. let rhs = stack[args[1] as usize].to_ec_point();
  390. let result = lhs.add(layouter.namespace(|| "EcAdd"), &rhs)?;
  391. debug!("Pushing result to stack index {}", stack.len());
  392. stack.push(StackVar::Witness(WitnessVar::EcPoint(result)));
  393. }
  394. Opcode::EcMul => {
  395. debug!("Executing `EcMul{:?}` opcode", opcode.1);
  396. let args = opcode.1.clone();
  397. let lhs = stack[args[0] as usize].to_scalar();
  398. let rhs = stack[args[1] as usize].to_fixed_point();
  399. let (result, _) = rhs.mul(layouter.namespace(|| "EcMul"), Some(lhs))?;
  400. debug!("Pushing result to stack index {}", stack.len());
  401. stack.push(StackVar::Witness(WitnessVar::EcPoint(result)));
  402. }
  403. Opcode::EcMulBase => {
  404. debug!("Executing `EcMulBase{:?}` opcode", opcode.1);
  405. let args = opcode.1.clone();
  406. let lhs = stack[args[0] as usize].to_base();
  407. let rhs = stack[args[1] as usize].to_fixed_point();
  408. let result = rhs.mul_base_field(layouter.namespace(|| "EcMulBase"), lhs)?;
  409. debug!("Pushing result to stack index {}", stack.len());
  410. stack.push(StackVar::Witness(WitnessVar::EcPoint(result)));
  411. }
  412. Opcode::EcMulShort => {
  413. debug!("Executing `EcMulShort{:?}` opcode", opcode.1);
  414. let args = opcode.1.clone();
  415. let lhs = stack[args[0] as usize].to_base();
  416. let rhs = stack[args[1] as usize].to_fixed_point();
  417. let (result, _) =
  418. rhs.mul_short(layouter.namespace(|| "EcMulShort"), (lhs, one))?;
  419. debug!("Pushing result to stack index {}", stack.len());
  420. stack.push(StackVar::Witness(WitnessVar::EcPoint(result)));
  421. }
  422. Opcode::EcGetX => {
  423. debug!("Executing `EcGetX{:?}` opcode", opcode.1);
  424. let args = opcode.1.clone();
  425. let point = stack[args[0] as usize].to_ec_point();
  426. let result = point.inner().x();
  427. debug!("Pushing result to stack index {}", stack.len());
  428. stack.push(StackVar::Cell(result));
  429. }
  430. Opcode::EcGetY => {
  431. debug!("Executing `EcGetY{:?}` opcode", opcode.1);
  432. let args = opcode.1.clone();
  433. let point = stack[args[0] as usize].to_ec_point();
  434. let result = point.inner().y();
  435. debug!("Pushing result to stack index {}", stack.len());
  436. stack.push(StackVar::Cell(result));
  437. }
  438. Opcode::PoseidonHash => {
  439. debug!("Executing `PoseidonHash{:?}` opcode", opcode.1);
  440. let args = opcode.1.clone();
  441. let mut poseidon_message: Vec<CellValue<pallas::Base>> = vec![];
  442. for idx in &args {
  443. let index = *idx as usize; // TODO: Guard this usize cast
  444. poseidon_message.push(stack[index].clone().into());
  445. }
  446. macro_rules! poseidon_hash {
  447. ($len:expr, $poseidon_hasher:ident, $poseidon_output:ident, $cell_output:ident) => {
  448. let $poseidon_hasher = PoseidonHash::<_, _, P128Pow5T3, _, 3, 2>::init(
  449. config.poseidon_chip(),
  450. layouter.namespace(|| "PoseidonHash ($len msgs) init"),
  451. ConstantLength::<$len>,
  452. )?;
  453. let $poseidon_output = $poseidon_hasher.hash(
  454. layouter.namespace(|| "PoseidonHash ($len msgs) hash"),
  455. poseidon_message.try_into().unwrap(),
  456. )?;
  457. let $cell_output: CellValue<pallas::Base> =
  458. $poseidon_output.inner().into();
  459. debug!("Pushing hash to stack index {}", stack.len());
  460. stack.push(StackVar::Cell($cell_output));
  461. };
  462. }
  463. // I can't find a better way to do this.
  464. match args.len() {
  465. 1 => {
  466. poseidon_hash!(1, poseidon_hasher, poseidon_output, cell_output);
  467. }
  468. 2 => {
  469. poseidon_hash!(2, poseidon_hasher, poseidon_output, cell_output);
  470. }
  471. 3 => {
  472. poseidon_hash!(3, poseidon_hasher, poseidon_output, cell_output);
  473. }
  474. 4 => {
  475. poseidon_hash!(4, poseidon_hasher, poseidon_output, cell_output);
  476. }
  477. 5 => {
  478. poseidon_hash!(5, poseidon_hasher, poseidon_output, cell_output);
  479. }
  480. 6 => {
  481. poseidon_hash!(6, poseidon_hasher, poseidon_output, cell_output);
  482. }
  483. 7 => {
  484. poseidon_hash!(7, poseidon_hasher, poseidon_output, cell_output);
  485. }
  486. 8 => {
  487. poseidon_hash!(8, poseidon_hasher, poseidon_output, cell_output);
  488. }
  489. _ => unimplemented!(),
  490. };
  491. }
  492. Opcode::CalculateMerkleRoot => {
  493. debug!("Executing `CalculateMerkleRoot{:?}` opcode", opcode.1);
  494. let args = opcode.1.clone();
  495. let leaf_pos = stack[args[0] as usize].clone().into();
  496. let merkle_path = stack[args[1] as usize].clone().into();
  497. let leaf = stack[args[2] as usize].clone().into();
  498. let path = MerklePath {
  499. chip_1: merkle_chip_1.clone(),
  500. chip_2: merkle_chip_2.clone(),
  501. domain: OrchardHashDomains::MerkleCrh,
  502. leaf_pos,
  503. path: merkle_path,
  504. };
  505. let root =
  506. path.calculate_root(layouter.namespace(|| "CalculateMerkleRoot"), leaf)?;
  507. debug!("Pushing hash to stack index {}", stack.len());
  508. stack.push(StackVar::Cell(root));
  509. }
  510. Opcode::ConstrainInstance => {
  511. debug!("Executing `ConstrainInstance{:?}` opcode", opcode.1);
  512. // TODO: Guard this usize cast
  513. let var = match stack[opcode.1[0] as usize] {
  514. StackVar::Cell(v) => v,
  515. _ => panic!("Incorrect stack variable type"),
  516. };
  517. layouter.constrain_instance(
  518. var.cell(),
  519. config.primary,
  520. public_inputs_offset,
  521. )?;
  522. public_inputs_offset += 1;
  523. }
  524. _ => unimplemented!(),
  525. }
  526. }
  527. // If we haven't exploded until now, we're golden.
  528. debug!("Exiting synthesize()");
  529. Ok(())
  530. }
  531. }