poseidon.rs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. use std::convert::TryInto;
  2. use std::time::Instant;
  3. use halo2::{
  4. circuit::{floor_planner, Layouter},
  5. pasta::{vesta, Fp},
  6. plonk,
  7. plonk::{
  8. Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn, Selector,
  9. },
  10. poly::{commitment, Rotation},
  11. transcript::{Blake2bRead, Blake2bWrite},
  12. };
  13. use halo2_poseidon::{
  14. gadget::{Hash as PoseidonHash, Word},
  15. pow5t3::{Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig, StateWord},
  16. primitive::{ConstantLength, Hash, P128Pow5T3 as OrchardNullifier},
  17. };
  18. use halo2_utilities::{copy, CellValue, UtilitiesInstructions, Var};
  19. const K: u32 = 6;
  20. #[derive(Clone, Debug)]
  21. struct Config {
  22. primary: Column<InstanceColumn>,
  23. q_add: Selector,
  24. advices: [Column<Advice>; 10],
  25. poseidon_config: PoseidonConfig<Fp>,
  26. }
  27. #[derive(Default, Debug)]
  28. struct HashCircuit {
  29. a: Option<Fp>, // First input for hash
  30. b: Option<Fp>, // Second input for hash
  31. c: Option<Fp>, // c is summed with hash
  32. }
  33. impl UtilitiesInstructions<Fp> for HashCircuit {
  34. type Var = CellValue<Fp>;
  35. }
  36. impl Circuit<Fp> for HashCircuit {
  37. type Config = Config;
  38. type FloorPlanner = floor_planner::V1;
  39. fn without_witnesses(&self) -> Self {
  40. Self::default()
  41. }
  42. fn configure(meta: &mut ConstraintSystem<Fp>) -> Self::Config {
  43. // 10 advice columns
  44. let advices = [
  45. meta.advice_column(),
  46. meta.advice_column(),
  47. meta.advice_column(),
  48. meta.advice_column(),
  49. meta.advice_column(),
  50. meta.advice_column(),
  51. meta.advice_column(),
  52. meta.advice_column(),
  53. meta.advice_column(),
  54. meta.advice_column(),
  55. ];
  56. // Addition of two field elements: poseidon_hash(a, b) + c
  57. let q_add = meta.selector();
  58. meta.create_gate("poseidon_hash(a, b) + c", |meta| {
  59. let q_add = meta.query_selector(q_add);
  60. let sum = meta.query_advice(advices[6], Rotation::cur());
  61. let hash = meta.query_advice(advices[7], Rotation::cur());
  62. let c = meta.query_advice(advices[8], Rotation::cur());
  63. vec![q_add * (hash + c - sum)]
  64. });
  65. let primary = meta.instance_column();
  66. meta.enable_equality(primary.into());
  67. for advice in advices.iter() {
  68. meta.enable_equality((*advice).into());
  69. }
  70. let lagrange_coeffs = [
  71. meta.fixed_column(),
  72. meta.fixed_column(),
  73. meta.fixed_column(),
  74. meta.fixed_column(),
  75. meta.fixed_column(),
  76. meta.fixed_column(),
  77. meta.fixed_column(),
  78. meta.fixed_column(),
  79. ];
  80. let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
  81. let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
  82. meta.enable_constant(lagrange_coeffs[0]);
  83. let poseidon_config = PoseidonChip::configure(
  84. meta,
  85. OrchardNullifier,
  86. advices[6..9].try_into().unwrap(),
  87. advices[5],
  88. rc_a,
  89. rc_b,
  90. );
  91. Config {
  92. primary,
  93. q_add,
  94. advices,
  95. poseidon_config,
  96. }
  97. }
  98. fn synthesize(
  99. &self,
  100. config: Self::Config,
  101. mut layouter: impl Layouter<Fp>,
  102. ) -> Result<(), Error> {
  103. let a = self.load_private(layouter.namespace(|| "load a"), config.advices[0], self.a)?;
  104. let b = self.load_private(layouter.namespace(|| "load b"), config.advices[0], self.b)?;
  105. let c = self.load_private(layouter.namespace(|| "load c"), config.advices[0], self.c)?;
  106. let hash = {
  107. let message = [a, b];
  108. let poseidon_message = layouter.assign_region(
  109. || "load message",
  110. |mut region| {
  111. let mut message_word = |i: usize| {
  112. let value = message[i].value();
  113. let var = region.assign_advice(
  114. || format!("load message_{}", i),
  115. config.poseidon_config.state()[i],
  116. 0,
  117. || value.ok_or(Error::SynthesisError),
  118. )?;
  119. region.constrain_equal(var, message[i].cell())?;
  120. Ok(Word::<_, _, OrchardNullifier, 3, 2>::from_inner(
  121. StateWord::new(var, value),
  122. ))
  123. };
  124. Ok([message_word(0)?, message_word(1)?])
  125. },
  126. )?;
  127. let poseidon_hasher = PoseidonHash::init(
  128. //config.poseidon_chip(),
  129. PoseidonChip::construct(config.poseidon_config.clone()),
  130. layouter.namespace(|| "Poseidon init"),
  131. ConstantLength::<2>,
  132. )?;
  133. let poseidon_output = poseidon_hasher.hash(
  134. layouter.namespace(|| "Poseidon hash (a, b)"),
  135. poseidon_message,
  136. )?;
  137. let poseidon_output: CellValue<Fp> = poseidon_output.inner().into();
  138. poseidon_output
  139. };
  140. // Add hash output to c
  141. let scalar = layouter.assign_region(
  142. || " `scalar` = poseidon_hash(a, b) + c",
  143. |mut region| {
  144. config.q_add.enable(&mut region, 0)?;
  145. copy(&mut region, || "copy hash", config.advices[7], 0, &hash)?;
  146. copy(&mut region, || "copy c", config.advices[8], 0, &c)?;
  147. let scalar_val = hash.value().zip(c.value()).map(|(hash, c)| hash + c);
  148. let cell = region.assign_advice(
  149. || "poseidon_hash(a, b) + c",
  150. config.advices[6],
  151. 0,
  152. || scalar_val.ok_or(Error::SynthesisError),
  153. )?;
  154. Ok(CellValue::new(cell, scalar_val))
  155. },
  156. )?;
  157. layouter.constrain_instance(scalar.cell(), config.primary, 0)
  158. }
  159. }
  160. #[derive(Debug)]
  161. struct VerifyingKey {
  162. params: commitment::Params<vesta::Affine>,
  163. vk: plonk::VerifyingKey<vesta::Affine>,
  164. }
  165. impl VerifyingKey {
  166. fn build() -> Self {
  167. let params = commitment::Params::new(K);
  168. let circuit: HashCircuit = Default::default();
  169. let vk = plonk::keygen_vk(&params, &circuit).unwrap();
  170. VerifyingKey { params, vk }
  171. }
  172. }
  173. #[derive(Debug)]
  174. struct ProvingKey {
  175. params: commitment::Params<vesta::Affine>,
  176. pk: plonk::ProvingKey<vesta::Affine>,
  177. }
  178. impl ProvingKey {
  179. fn build() -> Self {
  180. let params = commitment::Params::new(K);
  181. let circuit: HashCircuit = Default::default();
  182. let vk = plonk::keygen_vk(&params, &circuit).unwrap();
  183. let pk = plonk::keygen_pk(&params, vk, &circuit).unwrap();
  184. ProvingKey { params, pk }
  185. }
  186. }
  187. #[derive(Clone, Debug)]
  188. struct Proof(Vec<u8>);
  189. impl AsRef<[u8]> for Proof {
  190. fn as_ref(&self) -> &[u8] {
  191. &self.0
  192. }
  193. }
  194. impl Proof {
  195. fn create(pk: &ProvingKey, circuits: &[HashCircuit], pubinputs: &[Fp]) -> Result<Self, Error> {
  196. let mut transcript = Blake2bWrite::<_, vesta::Affine, _>::init(vec![]);
  197. plonk::create_proof(
  198. &pk.params,
  199. &pk.pk,
  200. circuits,
  201. &[&[pubinputs]],
  202. &mut transcript,
  203. )?;
  204. Ok(Proof(transcript.finalize()))
  205. }
  206. fn verify(&self, vk: &VerifyingKey, pubinputs: &[Fp]) -> Result<(), plonk::Error> {
  207. let msm = vk.params.empty_msm();
  208. let mut transcript = Blake2bRead::init(&self.0[..]);
  209. let guard = plonk::verify_proof(&vk.params, &vk.vk, msm, &[&[pubinputs]], &mut transcript)?;
  210. let msm = guard.clone().use_challenges();
  211. if msm.eval() {
  212. Ok(())
  213. } else {
  214. Err(Error::ConstraintSystemFailure)
  215. }
  216. }
  217. // fn new(bytes: Vec<u8>) -> Self {
  218. // Proof(bytes)
  219. // }
  220. }
  221. fn main() {
  222. let a = Fp::from(13);
  223. let b = Fp::from(69);
  224. let c = Fp::from(42);
  225. let message = [a, b];
  226. let output = Hash::init(OrchardNullifier, ConstantLength::<2>).hash(message);
  227. let circuit = HashCircuit {
  228. a: Some(a),
  229. b: Some(b),
  230. c: Some(c),
  231. };
  232. let sum = output + c;
  233. // Correct:
  234. let public_inputs = vec![sum];
  235. // Incorrect:
  236. // let public_inputs = vec![sum + Fp::one()];
  237. let start = Instant::now();
  238. let vk = VerifyingKey::build();
  239. let pk = ProvingKey::build();
  240. println!("Setup: [{:?}]", start.elapsed());
  241. let start = Instant::now();
  242. let proof = Proof::create(&pk, &[circuit], &public_inputs).unwrap();
  243. println!("Prove: [{:?}]", start.elapsed());
  244. let start = Instant::now();
  245. assert!(proof.verify(&vk, &public_inputs).is_ok());
  246. println!("Verify: [{:?}]", start.elapsed());
  247. }