vm.rs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. use bellman::{
  2. gadgets::{
  3. boolean::{AllocatedBit, Boolean},
  4. multipack, num, Assignment,
  5. },
  6. groth16, Circuit, ConstraintSystem, SynthesisError,
  7. };
  8. use bls12_381::Bls12;
  9. use bls12_381::Scalar;
  10. use ff::{Field, PrimeField};
  11. use group::Curve;
  12. use rand::rngs::OsRng;
  13. use std::ops::{Add, AddAssign, MulAssign, Neg, SubAssign};
  14. use std::time::Instant;
  15. pub struct ZKVirtualMachine {
  16. pub ops: Vec<CryptoOperation>,
  17. pub aux: Vec<Scalar>,
  18. pub alloc: Vec<(AllocType, VariableIndex)>,
  19. pub constraints: Vec<ConstraintInstruction>,
  20. pub params: Option<groth16::Parameters<Bls12>>,
  21. pub verifying_key: Option<groth16::PreparedVerifyingKey<Bls12>>,
  22. pub constants: Vec<Scalar>,
  23. }
  24. type VariableIndex = usize;
  25. pub enum VariableRef {
  26. Aux(VariableIndex),
  27. Local(VariableIndex),
  28. }
  29. pub enum CryptoOperation {
  30. Set(VariableRef, VariableRef),
  31. Mul(VariableRef, VariableRef),
  32. Add(VariableRef, VariableRef),
  33. Sub(VariableRef, VariableRef),
  34. Load(VariableRef, VariableIndex),
  35. Divide(VariableRef, VariableRef),
  36. Double(VariableRef),
  37. Square(VariableRef),
  38. Invert(VariableRef),
  39. UnpackBits(VariableRef, VariableRef, VariableRef),
  40. Local,
  41. }
  42. #[derive(Clone)]
  43. pub enum AllocType {
  44. Private,
  45. Public,
  46. }
  47. #[derive(Clone)]
  48. pub enum ConstraintInstruction {
  49. Lc0Add(VariableIndex),
  50. Lc1Add(VariableIndex),
  51. Lc2Add(VariableIndex),
  52. Lc0Sub(VariableIndex),
  53. Lc1Sub(VariableIndex),
  54. Lc2Sub(VariableIndex),
  55. Lc0AddOne,
  56. Lc1AddOne,
  57. Lc2AddOne,
  58. Lc0SubOne,
  59. Lc1SubOne,
  60. Lc2SubOne,
  61. Lc0AddCoeff(VariableIndex, VariableIndex),
  62. Lc1AddCoeff(VariableIndex, VariableIndex),
  63. Lc2AddCoeff(VariableIndex, VariableIndex),
  64. Lc0AddOneCoeff(VariableIndex),
  65. Lc1AddOneCoeff(VariableIndex),
  66. Lc2AddOneCoeff(VariableIndex),
  67. Enforce,
  68. LcCoeffReset,
  69. LcCoeffDouble,
  70. }
  71. #[derive(Debug)]
  72. pub enum ZKVMError {
  73. DivisionByZero,
  74. MalformedRange,
  75. }
  76. impl ZKVirtualMachine {
  77. pub fn initialize(
  78. &mut self,
  79. params: &Vec<(VariableIndex, Scalar)>,
  80. ) -> std::result::Result<(), ZKVMError> {
  81. // Resize array
  82. self.aux = vec![Scalar::zero(); self.alloc.len()];
  83. // Copy over the parameters
  84. for (index, value) in params {
  85. //println!("Setting {} to {:?}", index, value);
  86. self.aux[*index] = *value;
  87. }
  88. let mut local_stack: Vec<Scalar> = Vec::new();
  89. for op in &self.ops {
  90. match op {
  91. CryptoOperation::Set(self_, other) => {
  92. let other = match other {
  93. VariableRef::Aux(index) => self.aux[*index].clone(),
  94. VariableRef::Local(index) => local_stack[*index].clone(),
  95. };
  96. let self_ = match self_ {
  97. VariableRef::Aux(index) => &mut self.aux[*index],
  98. VariableRef::Local(index) => &mut local_stack[*index],
  99. };
  100. *self_ = other;
  101. }
  102. CryptoOperation::Mul(self_, other) => {
  103. let other = match other {
  104. VariableRef::Aux(index) => self.aux[*index].clone(),
  105. VariableRef::Local(index) => local_stack[*index].clone(),
  106. };
  107. let self_ = match self_ {
  108. VariableRef::Aux(index) => &mut self.aux[*index],
  109. VariableRef::Local(index) => &mut local_stack[*index],
  110. };
  111. self_.mul_assign(other);
  112. }
  113. CryptoOperation::Add(self_, other) => {
  114. let other = match other {
  115. VariableRef::Aux(index) => self.aux[*index].clone(),
  116. VariableRef::Local(index) => local_stack[*index].clone(),
  117. };
  118. let self_ = match self_ {
  119. VariableRef::Aux(index) => &mut self.aux[*index],
  120. VariableRef::Local(index) => &mut local_stack[*index],
  121. };
  122. self_.add_assign(other);
  123. }
  124. CryptoOperation::Sub(self_, other) => {
  125. let other = match other {
  126. VariableRef::Aux(index) => self.aux[*index].clone(),
  127. VariableRef::Local(index) => local_stack[*index].clone(),
  128. };
  129. let self_ = match self_ {
  130. VariableRef::Aux(index) => &mut self.aux[*index],
  131. VariableRef::Local(index) => &mut local_stack[*index],
  132. };
  133. self_.sub_assign(other);
  134. }
  135. CryptoOperation::Load(self_, const_index) => {
  136. let self_ = match self_ {
  137. VariableRef::Aux(index) => &mut self.aux[*index],
  138. VariableRef::Local(index) => &mut local_stack[*index],
  139. };
  140. *self_ = self.constants[*const_index];
  141. }
  142. CryptoOperation::Divide(self_, other) => {
  143. let other = match other {
  144. VariableRef::Aux(index) => self.aux[*index].clone(),
  145. VariableRef::Local(index) => local_stack[*index].clone(),
  146. };
  147. let self_ = match self_ {
  148. VariableRef::Aux(index) => &mut self.aux[*index],
  149. VariableRef::Local(index) => &mut local_stack[*index],
  150. };
  151. let ret = other.invert().map(|other| *self_ * other);
  152. if bool::from(ret.is_some()) {
  153. *self_ = ret.unwrap();
  154. } else {
  155. return Err(ZKVMError::DivisionByZero);
  156. }
  157. }
  158. CryptoOperation::Double(self_) => {
  159. let self_ = match self_ {
  160. VariableRef::Aux(index) => &mut self.aux[*index],
  161. VariableRef::Local(index) => &mut local_stack[*index],
  162. };
  163. *self_ = self_.double();
  164. }
  165. CryptoOperation::Square(self_) => {
  166. let self_ = match self_ {
  167. VariableRef::Aux(index) => &mut self.aux[*index],
  168. VariableRef::Local(index) => &mut local_stack[*index],
  169. };
  170. *self_ = self_.square();
  171. }
  172. CryptoOperation::Invert(self_) => {
  173. let self_ = match self_ {
  174. VariableRef::Aux(index) => &mut self.aux[*index],
  175. VariableRef::Local(index) => &mut local_stack[*index],
  176. };
  177. if self_.is_zero() {
  178. return Err(ZKVMError::DivisionByZero);
  179. } else {
  180. *self_ = self_.invert().unwrap();
  181. }
  182. }
  183. CryptoOperation::UnpackBits(value, start, end) => {
  184. let value = match value {
  185. VariableRef::Aux(index) => self.aux[*index].clone(),
  186. VariableRef::Local(index) => local_stack[*index].clone(),
  187. };
  188. let (self_, start_index, end_index) = match start {
  189. VariableRef::Aux(start_index) => match end {
  190. VariableRef::Aux(end_index) => (&mut self.aux, start_index, end_index),
  191. VariableRef::Local(end_index) => {
  192. return Err(ZKVMError::MalformedRange);
  193. }
  194. },
  195. VariableRef::Local(start_index) => match end {
  196. VariableRef::Aux(end_index) => {
  197. return Err(ZKVMError::MalformedRange);
  198. }
  199. VariableRef::Local(end_index) => {
  200. (&mut local_stack, start_index, end_index)
  201. }
  202. },
  203. };
  204. if start_index > end_index {
  205. return Err(ZKVMError::MalformedRange);
  206. }
  207. if (end_index + 1) - start_index != 256 {
  208. return Err(ZKVMError::MalformedRange);
  209. }
  210. if *end_index >= self_.len() {
  211. return Err(ZKVMError::MalformedRange);
  212. }
  213. for (i, bit) in value.to_le_bits().into_iter().cloned().enumerate() {
  214. match bit {
  215. true => self_[start_index + i] = Scalar::one(),
  216. false => self_[start_index + i] = Scalar::zero(),
  217. }
  218. }
  219. }
  220. CryptoOperation::Local => {
  221. local_stack.push(Scalar::zero());
  222. }
  223. }
  224. }
  225. Ok(())
  226. }
  227. pub fn public(&self) -> Vec<Scalar> {
  228. let mut publics = Vec::new();
  229. for (alloc_type, index) in &self.alloc {
  230. match alloc_type {
  231. AllocType::Private => {}
  232. AllocType::Public => {
  233. let scalar = self.aux[*index].clone();
  234. publics.push(scalar);
  235. }
  236. }
  237. }
  238. publics
  239. }
  240. pub fn setup(&mut self) {
  241. let start = Instant::now();
  242. // Create parameters for our circuit. In a production deployment these would
  243. // be generated securely using a multiparty computation.
  244. self.params = Some({
  245. let circuit = ZKVMCircuit {
  246. aux: vec![None; self.aux.len()],
  247. alloc: self.alloc.clone(),
  248. constraints: self.constraints.clone(),
  249. constants: self.constants.clone(),
  250. };
  251. groth16::generate_random_parameters::<Bls12, _, _>(circuit, &mut OsRng).unwrap()
  252. });
  253. println!("Setup: [{:?}]", start.elapsed());
  254. self.verifying_key = Some(groth16::prepare_verifying_key(
  255. &self.params.as_ref().unwrap().vk,
  256. ))
  257. }
  258. pub fn prove(&self) -> groth16::Proof<Bls12> {
  259. let aux = self.aux.iter().map(|scalar| Some(scalar.clone())).collect();
  260. // Create an instance of our circuit (with the preimage as a witness).
  261. let circuit = ZKVMCircuit {
  262. aux,
  263. alloc: self.alloc.clone(),
  264. constraints: self.constraints.clone(),
  265. constants: self.constants.clone(),
  266. };
  267. let start = Instant::now();
  268. // Create a Groth16 proof with our parameters.
  269. let proof =
  270. groth16::create_random_proof(circuit, self.params.as_ref().unwrap(), &mut OsRng)
  271. .unwrap();
  272. println!("Prove: [{:?}]", start.elapsed());
  273. proof
  274. }
  275. pub fn verify(&self, proof: &groth16::Proof<Bls12>, public_values: &Vec<Scalar>) -> bool {
  276. let start = Instant::now();
  277. let is_passed =
  278. groth16::verify_proof(self.verifying_key.as_ref().unwrap(), proof, public_values)
  279. .is_ok();
  280. println!("Verify: [{:?}]", start.elapsed());
  281. is_passed
  282. }
  283. }
  284. pub struct ZKVMCircuit {
  285. aux: Vec<Option<bls12_381::Scalar>>,
  286. alloc: Vec<(AllocType, VariableIndex)>,
  287. constraints: Vec<ConstraintInstruction>,
  288. constants: Vec<Scalar>,
  289. }
  290. impl Circuit<bls12_381::Scalar> for ZKVMCircuit {
  291. fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
  292. self,
  293. cs: &mut CS,
  294. ) -> Result<(), SynthesisError> {
  295. let mut variables = Vec::new();
  296. for (alloc_type, index) in &self.alloc {
  297. match alloc_type {
  298. AllocType::Private => {
  299. let var = cs.alloc(|| "private alloc", || Ok(*self.aux[*index].get()?))?;
  300. variables.push(var);
  301. }
  302. AllocType::Public => {
  303. let var = cs.alloc_input(|| "public alloc", || Ok(*self.aux[*index].get()?))?;
  304. variables.push(var);
  305. }
  306. }
  307. }
  308. let mut coeff = bls12_381::Scalar::one();
  309. let mut lc0 = bellman::LinearCombination::<Scalar>::zero();
  310. let mut lc1 = bellman::LinearCombination::<Scalar>::zero();
  311. let mut lc2 = bellman::LinearCombination::<Scalar>::zero();
  312. for constraint in self.constraints {
  313. match constraint {
  314. ConstraintInstruction::Lc0Add(index) => {
  315. lc0 = lc0 + (coeff, variables[index]);
  316. }
  317. ConstraintInstruction::Lc1Add(index) => {
  318. lc1 = lc1 + (coeff, variables[index]);
  319. }
  320. ConstraintInstruction::Lc2Add(index) => {
  321. lc2 = lc2 + (coeff, variables[index]);
  322. }
  323. ConstraintInstruction::Lc0Sub(index) => {
  324. lc0 = lc0 - (coeff, variables[index]);
  325. }
  326. ConstraintInstruction::Lc1Sub(index) => {
  327. lc1 = lc1 - (coeff, variables[index]);
  328. }
  329. ConstraintInstruction::Lc2Sub(index) => {
  330. lc2 = lc2 - (coeff, variables[index]);
  331. }
  332. ConstraintInstruction::Lc0AddOne => {
  333. lc0 = lc0 + CS::one();
  334. }
  335. ConstraintInstruction::Lc1AddOne => {
  336. lc1 = lc1 + CS::one();
  337. }
  338. ConstraintInstruction::Lc2AddOne => {
  339. lc2 = lc2 + CS::one();
  340. }
  341. ConstraintInstruction::Lc0SubOne => {
  342. lc0 = lc0 - CS::one();
  343. }
  344. ConstraintInstruction::Lc1SubOne => {
  345. lc1 = lc1 - CS::one();
  346. }
  347. ConstraintInstruction::Lc2SubOne => {
  348. lc2 = lc2 - CS::one();
  349. }
  350. ConstraintInstruction::Lc0AddCoeff(const_index, index) => {
  351. lc0 = lc0 + (self.constants[const_index], variables[index]);
  352. }
  353. ConstraintInstruction::Lc1AddCoeff(const_index, index) => {
  354. lc1 = lc1 + (self.constants[const_index], variables[index]);
  355. }
  356. ConstraintInstruction::Lc2AddCoeff(const_index, index) => {
  357. lc2 = lc2 + (self.constants[const_index], variables[index]);
  358. }
  359. ConstraintInstruction::Lc0AddOneCoeff(const_index) => {
  360. lc0 = lc0 + (self.constants[const_index], CS::one());
  361. }
  362. ConstraintInstruction::Lc1AddOneCoeff(const_index) => {
  363. lc1 = lc1 + (self.constants[const_index], CS::one());
  364. }
  365. ConstraintInstruction::Lc2AddOneCoeff(const_index) => {
  366. lc2 = lc2 + (self.constants[const_index], CS::one());
  367. }
  368. ConstraintInstruction::Enforce => {
  369. cs.enforce(
  370. || "constraint",
  371. |_| lc0.clone(),
  372. |_| lc1.clone(),
  373. |_| lc2.clone(),
  374. );
  375. coeff = bls12_381::Scalar::one();
  376. lc0 = bellman::LinearCombination::<Scalar>::zero();
  377. lc1 = bellman::LinearCombination::<Scalar>::zero();
  378. lc2 = bellman::LinearCombination::<Scalar>::zero();
  379. }
  380. ConstraintInstruction::LcCoeffReset => {
  381. coeff = bls12_381::Scalar::one();
  382. }
  383. ConstraintInstruction::LcCoeffDouble => {
  384. coeff = coeff.double();
  385. }
  386. }
  387. }
  388. Ok(())
  389. }
  390. }