poseidon.rs 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. use halo2::{
  2. circuit::{Layouter, SimpleFloorPlanner},
  3. dev::MockProver,
  4. plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Instance as InstanceColumn},
  5. };
  6. use halo2_gadgets::{
  7. poseidon::{Hash as PoseidonHash, Pow5T3Chip as PoseidonChip, Pow5T3Config as PoseidonConfig},
  8. primitives,
  9. primitives::poseidon::{ConstantLength, P128Pow5T3},
  10. utilities::{CellValue, UtilitiesInstructions, Var},
  11. };
  12. use pasta_curves::pallas;
  13. #[derive(Clone)]
  14. struct Config {
  15. primary: Column<InstanceColumn>,
  16. advices: [Column<Advice>; 5],
  17. poseidon_config: PoseidonConfig<pallas::Base>,
  18. }
  19. impl Config {
  20. fn poseidon_chip(&self) -> PoseidonChip<pallas::Base> {
  21. PoseidonChip::construct(self.poseidon_config.clone())
  22. }
  23. }
  24. #[derive(Default)]
  25. struct HashCircuit {
  26. a: Option<pallas::Base>,
  27. b: Option<pallas::Base>,
  28. c: Option<pallas::Base>,
  29. d: Option<pallas::Base>,
  30. }
  31. impl UtilitiesInstructions<pallas::Base> for HashCircuit {
  32. type Var = CellValue<pallas::Base>;
  33. }
  34. impl Circuit<pallas::Base> for HashCircuit {
  35. type Config = Config;
  36. type FloorPlanner = SimpleFloorPlanner;
  37. fn without_witnesses(&self) -> Self {
  38. Self::default()
  39. }
  40. fn configure(meta: &mut ConstraintSystem<pallas::Base>) -> Self::Config {
  41. let advices = [
  42. meta.advice_column(),
  43. meta.advice_column(),
  44. meta.advice_column(),
  45. meta.advice_column(),
  46. meta.advice_column(),
  47. ];
  48. let primary = meta.instance_column();
  49. meta.enable_equality(primary.into());
  50. for advice in advices.iter() {
  51. meta.enable_equality((*advice).into());
  52. }
  53. let lagrange_coeffs = [
  54. meta.fixed_column(),
  55. meta.fixed_column(),
  56. meta.fixed_column(),
  57. meta.fixed_column(),
  58. meta.fixed_column(),
  59. meta.fixed_column(),
  60. meta.fixed_column(),
  61. meta.fixed_column(),
  62. ];
  63. let rc_a = lagrange_coeffs[2..5].try_into().unwrap();
  64. let rc_b = lagrange_coeffs[5..8].try_into().unwrap();
  65. meta.enable_constant(lagrange_coeffs[0]);
  66. let poseidon_config = PoseidonChip::configure(
  67. meta,
  68. P128Pow5T3,
  69. advices[1..4].try_into().unwrap(),
  70. advices[4],
  71. rc_a,
  72. rc_b,
  73. );
  74. Config {
  75. primary,
  76. advices,
  77. poseidon_config,
  78. }
  79. }
  80. fn synthesize(
  81. &self,
  82. config: Self::Config,
  83. mut layouter: impl Layouter<pallas::Base>,
  84. ) -> Result<(), Error> {
  85. let a = self.load_private(layouter.namespace(|| "load a"), config.advices[0], self.a)?;
  86. let b = self.load_private(layouter.namespace(|| "load b"), config.advices[0], self.b)?;
  87. let c = self.load_private(layouter.namespace(|| "load c"), config.advices[0], self.c)?;
  88. let d = self.load_private(layouter.namespace(|| "load d"), config.advices[0], self.d)?;
  89. let hash = {
  90. let poseidon_message = [a, b, c, d];
  91. let poseidon_hasher = PoseidonHash::<_, _, P128Pow5T3, _, 3, 2>::init(
  92. config.poseidon_chip(),
  93. layouter.namespace(|| "Poseidon init"),
  94. ConstantLength::<4>,
  95. )?;
  96. let poseidon_output = poseidon_hasher.hash(
  97. layouter.namespace(|| "Poseidon hash (a, b)"),
  98. poseidon_message,
  99. )?;
  100. let poseidon_output: CellValue<pallas::Base> = poseidon_output.inner().into();
  101. poseidon_output
  102. };
  103. layouter.constrain_instance(hash.cell(), config.primary, 0)?;
  104. Ok(())
  105. }
  106. }
  107. fn main() {
  108. // The number of rows in our circuit cannot exceed 2^k
  109. let k: u32 = 9;
  110. let a = pallas::Base::from(1);
  111. let b = pallas::Base::from(2);
  112. let c = pallas::Base::from(3);
  113. let d = pallas::Base::from(4);
  114. let message = [a, b, c, d];
  115. let hash = primitives::poseidon::Hash::init(P128Pow5T3, ConstantLength::<4>).hash(message);
  116. let circuit = HashCircuit {
  117. a: Some(a),
  118. b: Some(b),
  119. c: Some(c),
  120. d: Some(d),
  121. };
  122. let public_inputs = vec![hash];
  123. let prover = MockProver::run(k, &circuit, vec![public_inputs]).unwrap();
  124. assert_eq!(prover.verify(), Ok(()));
  125. }