vm2.rs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441
  1. use std::collections::HashMap;
  2. use std::convert::TryInto;
  3. use halo2::{
  4. circuit::{Layouter, SimpleFloorPlanner},
  5. plonk,
  6. plonk::{Advice, Circuit, Column, ConstraintSystem, Instance as InstanceColumn, Selector},
  7. };
  8. use halo2_gadgets::{
  9. ecc::{
  10. chip::{EccChip, EccConfig},
  11. FixedPoint,
  12. },
  13. poseidon::{
  14. Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig,
  15. StateWord, Word,
  16. },
  17. primitives::poseidon::{ConstantLength, P128Pow5T3},
  18. utilities::{
  19. lookup_range_check::LookupRangeCheckConfig, CellValue, UtilitiesInstructions, Var,
  20. },
  21. };
  22. use pasta_curves::pallas;
  23. use crate::{
  24. arith_chip::{ArithmeticChip, ArithmeticChipConfig},
  25. constants::OrchardFixedBases,
  26. error::{Error, Result},
  27. };
  28. #[derive(Clone, Debug, PartialEq)]
  29. pub enum ZkType {
  30. Base,
  31. Scalar,
  32. EcPoint,
  33. EcFixedPoint,
  34. }
  35. type ArgIdx = usize;
  36. #[derive(Clone, Debug)]
  37. pub enum ZkFunctionCall {
  38. PoseidonHash(ArgIdx, ArgIdx),
  39. Add(ArgIdx, ArgIdx),
  40. ConstrainInstance(ArgIdx),
  41. EcMulShort(ArgIdx, ArgIdx),
  42. EcMul(ArgIdx, ArgIdx),
  43. EcAdd(ArgIdx, ArgIdx),
  44. EcGetX(ArgIdx),
  45. EcGetY(ArgIdx),
  46. }
  47. pub struct ZkBinary {
  48. pub constants: Vec<(String, ZkType)>,
  49. pub contracts: HashMap<String, ZkContract>,
  50. }
  51. #[derive(Clone, Debug)]
  52. pub struct ZkContract {
  53. pub witness: Vec<(String, ZkType)>,
  54. pub code: Vec<ZkFunctionCall>,
  55. }
  56. // These is the actual structures below which interpret the structures
  57. // deserialized above.
  58. #[derive(Clone, Debug)]
  59. pub struct MintConfig {
  60. pub primary: Column<InstanceColumn>,
  61. pub q_add: Selector,
  62. pub advices: [Column<Advice>; 10],
  63. pub ecc_config: EccConfig,
  64. pub poseidon_config: PoseidonConfig<pallas::Base>,
  65. pub arith_config: ArithmeticChipConfig,
  66. }
  67. impl MintConfig {
  68. pub fn ecc_chip(&self) -> EccChip<OrchardFixedBases> {
  69. EccChip::construct(self.ecc_config.clone())
  70. }
  71. pub fn poseidon_chip(&self) -> PoseidonChip<pallas::Base> {
  72. PoseidonChip::construct(self.poseidon_config.clone())
  73. }
  74. pub fn arithmetic_chip(&self) -> ArithmeticChip {
  75. ArithmeticChip::construct(self.arith_config.clone())
  76. }
  77. }
  78. #[derive(Clone, Debug)]
  79. pub struct ZkCircuit<'a> {
  80. pub const_fixed_points: HashMap<String, OrchardFixedBases>,
  81. pub constants: &'a Vec<(String, ZkType)>,
  82. pub contract: &'a ZkContract,
  83. // For each type create a separate stack
  84. pub witness_base: HashMap<String, Option<pallas::Base>>,
  85. pub witness_scalar: HashMap<String, Option<pallas::Scalar>>,
  86. }
  87. impl<'a> ZkCircuit<'a> {
  88. pub fn new(
  89. const_fixed_points: HashMap<String, OrchardFixedBases>,
  90. constants: &'a Vec<(String, ZkType)>,
  91. contract: &'a ZkContract,
  92. ) -> Self {
  93. let mut witness_base = HashMap::new();
  94. let mut witness_scalar = HashMap::new();
  95. for (name, type_id) in contract.witness.iter() {
  96. match type_id {
  97. ZkType::Base => {
  98. witness_base.insert(name.clone(), None);
  99. }
  100. ZkType::Scalar => {
  101. witness_scalar.insert(name.clone(), None);
  102. }
  103. _ => {
  104. unimplemented!();
  105. }
  106. }
  107. }
  108. Self {
  109. const_fixed_points,
  110. constants,
  111. contract,
  112. witness_base,
  113. witness_scalar,
  114. }
  115. }
  116. pub fn witness_base(&mut self, name: &str, value: pallas::Base) -> Result<()> {
  117. for (variable, type_id) in self.contract.witness.iter() {
  118. if name != variable {
  119. continue;
  120. }
  121. if *type_id != ZkType::Base {
  122. return Err(Error::InvalidParamType);
  123. }
  124. *self.witness_base.get_mut(name).unwrap() = Some(value);
  125. return Ok(());
  126. }
  127. return Err(Error::InvalidParamName);
  128. }
  129. pub fn witness_scalar(&mut self, name: &str, value: pallas::Scalar) -> Result<()> {
  130. for (variable, type_id) in self.contract.witness.iter() {
  131. if name != variable {
  132. continue;
  133. }
  134. if *type_id != ZkType::Scalar {
  135. return Err(Error::InvalidParamType);
  136. }
  137. *self.witness_scalar.get_mut(name).unwrap() = Some(value);
  138. return Ok(());
  139. }
  140. return Err(Error::InvalidParamName);
  141. }
  142. }
  143. impl<'a> UtilitiesInstructions<pallas::Base> for ZkCircuit<'a> {
  144. type Var = CellValue<pallas::Base>;
  145. }
  146. impl<'a> Circuit<pallas::Base> for ZkCircuit<'a> {
  147. type Config = MintConfig;
  148. type FloorPlanner = SimpleFloorPlanner;
  149. fn without_witnesses(&self) -> Self {
  150. Self {
  151. const_fixed_points: self.const_fixed_points.clone(),
  152. constants: self.constants,
  153. contract: &self.contract,
  154. witness_base: self
  155. .witness_base
  156. .keys()
  157. .map(|key| (key.clone(), None))
  158. .collect(),
  159. witness_scalar: self
  160. .witness_scalar
  161. .keys()
  162. .map(|key| (key.clone(), None))
  163. .collect(),
  164. }
  165. }
  166. fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
  167. let advices = [
  168. meta.advice_column(),
  169. meta.advice_column(),
  170. meta.advice_column(),
  171. meta.advice_column(),
  172. meta.advice_column(),
  173. meta.advice_column(),
  174. meta.advice_column(),
  175. meta.advice_column(),
  176. meta.advice_column(),
  177. meta.advice_column(),
  178. ];
  179. let q_add = meta.selector();
  180. let table_idx = meta.lookup_table_column();
  181. let primary = meta.instance_column();
  182. meta.enable_equality(primary.into());
  183. for advice in advices.iter() {
  184. meta.enable_equality((*advice).into());
  185. }
  186. let lagrange_coeffs = [
  187. meta.fixed_column(),
  188. meta.fixed_column(),
  189. meta.fixed_column(),
  190. meta.fixed_column(),
  191. meta.fixed_column(),
  192. meta.fixed_column(),
  193. meta.fixed_column(),
  194. meta.fixed_column(),
  195. ];
  196. let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
  197. let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
  198. meta.enable_constant(lagrange_coeffs[0]);
  199. let range_check = LookupRangeCheckConfig::configure(meta, advices[9], table_idx);
  200. let ecc_config = EccChip::<OrchardFixedBases>::configure(
  201. meta,
  202. advices,
  203. lagrange_coeffs,
  204. range_check.clone(),
  205. );
  206. let poseidon_config = PoseidonChip::configure(
  207. meta,
  208. P128Pow5T3,
  209. advices[6..9].try_into().unwrap(),
  210. advices[5],
  211. rc_a,
  212. rc_b,
  213. );
  214. let arith_config = ArithmeticChip::configure(meta);
  215. MintConfig {
  216. primary,
  217. q_add,
  218. advices,
  219. ecc_config,
  220. poseidon_config,
  221. arith_config,
  222. }
  223. }
  224. fn synthesize(
  225. &self,
  226. config: Self::Config,
  227. mut layouter: impl Layouter<pallas::Base>,
  228. ) -> std::result::Result<(), plonk::Error> {
  229. let ecc_chip = config.ecc_chip();
  230. let arith_chip = config.arithmetic_chip();
  231. let mut stack_base = Vec::new();
  232. let mut stack_scalar = Vec::new();
  233. let mut stack_ec_point = Vec::new();
  234. let mut stack_ec_fixed_point = Vec::new();
  235. // Load constants first onto the stacks
  236. for (variable, type_id) in self.constants.iter() {
  237. match *type_id {
  238. ZkType::Base => {
  239. unimplemented!();
  240. }
  241. ZkType::Scalar => {
  242. unimplemented!();
  243. }
  244. ZkType::EcPoint => {
  245. unimplemented!();
  246. }
  247. ZkType::EcFixedPoint => {
  248. let value = self.const_fixed_points[variable];
  249. stack_ec_fixed_point.push(value);
  250. }
  251. }
  252. }
  253. // Push the witnesses onto the stacks in order
  254. for (variable, type_id) in self.contract.witness.iter() {
  255. match *type_id {
  256. ZkType::Base => {
  257. let value = self.witness_base.get(variable).expect("witness base set");
  258. let value = self.load_private(
  259. layouter.namespace(|| "load pubkey x"),
  260. config.advices[0],
  261. *value,
  262. )?;
  263. stack_base.push(value.clone());
  264. }
  265. ZkType::Scalar => {
  266. let value = self.witness_scalar.get(variable).expect("witness base set");
  267. stack_scalar.push(value.clone());
  268. }
  269. ZkType::EcPoint => {
  270. unimplemented!();
  271. }
  272. ZkType::EcFixedPoint => {
  273. unimplemented!();
  274. }
  275. }
  276. }
  277. let mut current_instance_offset = 0;
  278. for func_call in self.contract.code.iter() {
  279. match func_call {
  280. ZkFunctionCall::PoseidonHash(lhs_idx, rhs_idx) => {
  281. assert!(*lhs_idx < stack_base.len());
  282. assert!(*rhs_idx < stack_base.len());
  283. let messages = [stack_base[*lhs_idx], stack_base[*rhs_idx]];
  284. let poseidon_message = layouter.assign_region(
  285. || "load message",
  286. |mut region| {
  287. let mut message_word = |i: usize| {
  288. let val = messages[i].value();
  289. let var = region.assign_advice(
  290. || format!("load message_{}", i),
  291. config.poseidon_config.state()[i],
  292. 0,
  293. || val.ok_or(plonk::Error::SynthesisError),
  294. )?;
  295. region.constrain_equal(var, messages[i].cell())?;
  296. Ok(Word::<_, _, P128Pow5T3, 3, 2>::from_inner(StateWord::new(
  297. var, val,
  298. )))
  299. };
  300. Ok([message_word(0)?, message_word(1)?])
  301. },
  302. )?;
  303. let poseidon_hasher = PoseidonHash::init(
  304. config.poseidon_chip(),
  305. layouter.namespace(|| "Poseidon init"),
  306. ConstantLength::<2>,
  307. )?;
  308. let poseidon_output = poseidon_hasher
  309. .hash(layouter.namespace(|| "poseidon hash"), poseidon_message)?;
  310. let poseidon_output: CellValue<pallas::Base> = poseidon_output.inner().into();
  311. stack_base.push(poseidon_output);
  312. }
  313. ZkFunctionCall::Add(lhs_idx, rhs_idx) => {
  314. assert!(*lhs_idx < stack_base.len());
  315. assert!(*rhs_idx < stack_base.len());
  316. let (lhs, rhs) = (stack_base[*lhs_idx], stack_base[*rhs_idx]);
  317. let output =
  318. arith_chip.add(layouter.namespace(|| "arithmetic add"), lhs, rhs)?;
  319. stack_base.push(output);
  320. }
  321. ZkFunctionCall::ConstrainInstance(arg_idx) => {
  322. assert!(*arg_idx < stack_base.len());
  323. let arg = stack_base[*arg_idx];
  324. layouter.constrain_instance(
  325. arg.cell(),
  326. config.primary,
  327. current_instance_offset,
  328. )?;
  329. current_instance_offset += 1;
  330. }
  331. ZkFunctionCall::EcMulShort(value_idx, point_idx) => {
  332. assert!(*value_idx < stack_base.len());
  333. let value = stack_base[*value_idx];
  334. assert!(*point_idx < stack_ec_fixed_point.len());
  335. let fixed_point = stack_ec_fixed_point[*point_idx];
  336. // This constant one is used for multiplication
  337. let one = self.load_private(
  338. layouter.namespace(|| "load constant one"),
  339. config.advices[0],
  340. Some(pallas::Base::one()),
  341. )?;
  342. // v * G_1
  343. let (result, _) = {
  344. let value_commit_v = FixedPoint::from_inner(ecc_chip.clone(), fixed_point);
  345. value_commit_v.mul_short(
  346. layouter.namespace(|| "[value] ValueCommitV"),
  347. (value, one),
  348. )?
  349. };
  350. stack_ec_point.push(result);
  351. }
  352. ZkFunctionCall::EcMul(value_idx, point_idx) => {
  353. assert!(*value_idx < stack_scalar.len());
  354. let value = stack_scalar[*value_idx];
  355. assert!(*point_idx < stack_ec_fixed_point.len());
  356. let fixed_point = stack_ec_fixed_point[*point_idx];
  357. let (result, _) = {
  358. let value_commit_r = FixedPoint::from_inner(ecc_chip.clone(), fixed_point);
  359. value_commit_r
  360. .mul(layouter.namespace(|| "[value_blind] ValueCommitR"), value)?
  361. };
  362. stack_ec_point.push(result);
  363. }
  364. ZkFunctionCall::EcAdd(lhs_idx, rhs_idx) => {
  365. assert!(*lhs_idx < stack_ec_point.len());
  366. assert!(*rhs_idx < stack_ec_point.len());
  367. let lhs = &stack_ec_point[*lhs_idx];
  368. let rhs = &stack_ec_point[*rhs_idx];
  369. let result = lhs.add(layouter.namespace(|| "valuecommit"), rhs)?;
  370. stack_ec_point.push(result);
  371. }
  372. ZkFunctionCall::EcGetX(arg_idx) => {
  373. assert!(*arg_idx < stack_ec_point.len());
  374. let arg = &stack_ec_point[*arg_idx];
  375. let x = arg.inner().x();
  376. stack_base.push(x);
  377. }
  378. ZkFunctionCall::EcGetY(arg_idx) => {
  379. assert!(*arg_idx < stack_ec_point.len());
  380. let arg = &stack_ec_point[*arg_idx];
  381. let y = arg.inner().y();
  382. stack_base.push(y);
  383. }
  384. }
  385. }
  386. // At this point we've enforced all of our public inputs.
  387. Ok(())
  388. }
  389. }