You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

260 lines
6.9 KiB

Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
Verifier circuit (#23) * ECC scalar multiplication (first draft) * fix clippy nits * start implementing the ro gadget: 1st design Poseidon + truncate * truncate to 128 bits * implement add + double in constraints * finish implementing constraints for ecc * cargo fmt * input of smul should be an array of bits * cleanup ro a bit. Make the challenge returned be a vec of allocated bits * switch to neptune 6.0 * start implementing high level circuit * incomplete version of the verifier circuit with many TODOS * optimize ecc ops. add i ==0 case to the circuit * fix 0/1 constants at the circuit * wrap CompressedGroupElement of Pallas and Vesta * cargo fmt * generate poseidon constants once instead of every time we call get_challenge * Implement RO-based poseidon to use outside of circuit. Reorganize the repo * add inner circuit to verification circuit * start adding folding of the io. there is an error in the first call to mult_mod * add test to check that bellperson-nonnative is compatible with nova * remove swap file * add another test that fails * add inputs to the circuits in tests * rename q to m in circuit.rs. add more tests in test_bellperson_non_native. change a in test_mult_mod to expose error * push test for equal_with_carried. fix the issue is src/r1cs.rs * cargo fmt + update the verifier circuit: add folding of X and update all hashes with X * make limb_width and n_limbs parameters * make params part of h1 * allocate the field order as constant. add check that z0 == zi when i == 0 * fix error in test_poseidon_ro * remove merge error * small fixes * small fixes to comments * clippy lints * small edits; rename tests * move inputize before from_num * _limbs --> _bn * _limbs --> _bn Co-authored-by: Ioanna <iontzialla@gmail.com>
2 years ago
  1. //! Poseidon Constants and Poseidon-based RO used in Nova
  2. use bellperson::{
  3. gadgets::{
  4. boolean::{AllocatedBit, Boolean},
  5. num::AllocatedNum,
  6. },
  7. ConstraintSystem, SynthesisError,
  8. };
  9. use ff::{PrimeField, PrimeFieldBits};
  10. use generic_array::typenum::{U25, U27, U31};
  11. use neptune::{
  12. circuit::poseidon_hash,
  13. poseidon::{Poseidon, PoseidonConstants},
  14. };
  15. #[cfg(test)]
  16. use neptune::Strength;
  17. /// All Poseidon Constants that are used in Nova
  18. #[derive(Clone)]
  19. pub struct NovaPoseidonConstants<F>
  20. where
  21. F: PrimeField,
  22. {
  23. constants25: PoseidonConstants<F, U25>,
  24. constants27: PoseidonConstants<F, U27>,
  25. constants31: PoseidonConstants<F, U31>,
  26. }
  27. #[cfg(test)]
  28. impl<F> NovaPoseidonConstants<F>
  29. where
  30. F: PrimeField,
  31. {
  32. /// Generate Poseidon constants for the arities that Nova uses
  33. pub fn new() -> Self {
  34. let constants25 = PoseidonConstants::<F, U25>::new_with_strength(Strength::Strengthened);
  35. let constants27 = PoseidonConstants::<F, U27>::new_with_strength(Strength::Strengthened);
  36. let constants31 = PoseidonConstants::<F, U31>::new_with_strength(Strength::Strengthened);
  37. Self {
  38. constants25,
  39. constants27,
  40. constants31,
  41. }
  42. }
  43. }
  44. /// A Poseidon-based RO to use outside circuits
  45. pub struct PoseidonRO<Scalar>
  46. where
  47. Scalar: PrimeField + PrimeFieldBits,
  48. {
  49. // Internal State
  50. state: Vec<Scalar>,
  51. // Constants for Poseidon
  52. constants: NovaPoseidonConstants<Scalar>,
  53. }
  54. impl<Scalar> PoseidonRO<Scalar>
  55. where
  56. Scalar: PrimeField + PrimeFieldBits,
  57. {
  58. #[allow(dead_code)]
  59. pub fn new(constants: NovaPoseidonConstants<Scalar>) -> Self {
  60. Self {
  61. state: Vec::new(),
  62. constants,
  63. }
  64. }
  65. #[allow(dead_code)]
  66. /// Flush the state of the RO
  67. pub fn flush_state(&mut self) {
  68. self.state = Vec::new();
  69. }
  70. /// Absorb a new number into the state of the oracle
  71. #[allow(dead_code)]
  72. pub fn absorb(&mut self, e: Scalar) {
  73. self.state.push(e);
  74. }
  75. fn hash_inner(&mut self) -> Scalar {
  76. match self.state.len() {
  77. 25 => {
  78. Poseidon::<Scalar, U25>::new_with_preimage(&self.state, &self.constants.constants25).hash()
  79. }
  80. 27 => {
  81. Poseidon::<Scalar, U27>::new_with_preimage(&self.state, &self.constants.constants27).hash()
  82. }
  83. 31 => {
  84. Poseidon::<Scalar, U31>::new_with_preimage(&self.state, &self.constants.constants31).hash()
  85. }
  86. _ => {
  87. panic!("Number of elements in the RO state does not match any of the arities used in Nova")
  88. }
  89. }
  90. }
  91. /// Compute a challenge by hashing the current state
  92. #[allow(dead_code)]
  93. pub fn get_challenge(&mut self) -> Scalar {
  94. let hash = self.hash_inner();
  95. // Only keep 128 bits
  96. let bits = hash.to_le_bits();
  97. let mut res = Scalar::zero();
  98. let mut coeff = Scalar::one();
  99. for bit in bits[0..128].into_iter() {
  100. if *bit {
  101. res += coeff;
  102. }
  103. coeff += coeff;
  104. }
  105. res
  106. }
  107. #[allow(dead_code)]
  108. pub fn get_hash(&mut self) -> Scalar {
  109. let hash = self.hash_inner();
  110. // Only keep 250 bits
  111. let bits = hash.to_le_bits();
  112. let mut res = Scalar::zero();
  113. let mut coeff = Scalar::one();
  114. for bit in bits[0..250].into_iter() {
  115. if *bit {
  116. res += coeff;
  117. }
  118. coeff += coeff;
  119. }
  120. res
  121. }
  122. }
  123. /// A Poseidon-based RO gadget to use inside the verifier circuit.
  124. pub struct PoseidonROGadget<Scalar>
  125. where
  126. Scalar: PrimeField + PrimeFieldBits,
  127. {
  128. // Internal state
  129. state: Vec<AllocatedNum<Scalar>>,
  130. constants: NovaPoseidonConstants<Scalar>,
  131. }
  132. impl<Scalar> PoseidonROGadget<Scalar>
  133. where
  134. Scalar: PrimeField + PrimeFieldBits,
  135. {
  136. /// Initialize the internal state and set the poseidon constants
  137. #[allow(dead_code)]
  138. pub fn new(constants: NovaPoseidonConstants<Scalar>) -> Self {
  139. Self {
  140. state: Vec::new(),
  141. constants,
  142. }
  143. }
  144. /// Flush the state of the RO
  145. pub fn flush_state(&mut self) {
  146. self.state = Vec::new();
  147. }
  148. /// Absorb a new number into the state of the oracle
  149. #[allow(dead_code)]
  150. pub fn absorb(&mut self, e: AllocatedNum<Scalar>) {
  151. self.state.push(e);
  152. }
  153. fn hash_inner<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
  154. where
  155. CS: ConstraintSystem<Scalar>,
  156. {
  157. let out = match self.state.len() {
  158. 25 => poseidon_hash(
  159. cs.namespace(|| "Poseidon hash"),
  160. self.state.clone(),
  161. &self.constants.constants25,
  162. )?,
  163. 27 => poseidon_hash(
  164. cs.namespace(|| "Poseidon hash"),
  165. self.state.clone(),
  166. &self.constants.constants27,
  167. )?,
  168. 31 => poseidon_hash(
  169. cs.namespace(|| "Poseidon hash"),
  170. self.state.clone(),
  171. &self.constants.constants31,
  172. )?,
  173. _ => {
  174. panic!("Number of elements in the RO state does not match any of the arities used in Nova")
  175. }
  176. };
  177. // return the hash as a vector of bits
  178. Ok(
  179. out
  180. .to_bits_le_strict(cs.namespace(|| "poseidon hash to boolean"))?
  181. .iter()
  182. .map(|boolean| match boolean {
  183. Boolean::Is(ref x) => x.clone(),
  184. _ => panic!("Wrong type of input. We should have never reached there"),
  185. })
  186. .collect(),
  187. )
  188. }
  189. /// Compute a challenge by hashing the current state
  190. #[allow(dead_code)]
  191. pub fn get_challenge<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
  192. where
  193. CS: ConstraintSystem<Scalar>,
  194. {
  195. let bits = self.hash_inner(cs.namespace(|| "hash"))?;
  196. // Only keep 128 bits
  197. Ok(bits[..128].into())
  198. }
  199. #[allow(dead_code)]
  200. pub fn get_hash<CS>(&mut self, mut cs: CS) -> Result<Vec<AllocatedBit>, SynthesisError>
  201. where
  202. CS: ConstraintSystem<Scalar>,
  203. {
  204. let bits = self.hash_inner(cs.namespace(|| "hash"))?;
  205. // Only keep 250 bits
  206. Ok(bits[..250].into())
  207. }
  208. }
  209. #[cfg(test)]
  210. mod tests {
  211. use super::*;
  212. type S = pasta_curves::pallas::Scalar;
  213. type G = pasta_curves::pallas::Point;
  214. use crate::{bellperson::solver::SatisfyingAssignment, gadgets::utils::le_bits_to_num};
  215. use ff::Field;
  216. use rand::rngs::OsRng;
  217. #[test]
  218. fn test_poseidon_ro() {
  219. // Check that the number computed inside the circuit is equal to the number computed outside the circuit
  220. let mut csprng: OsRng = OsRng;
  221. let constants = NovaPoseidonConstants::new();
  222. let mut ro: PoseidonRO<S> = PoseidonRO::new(constants.clone());
  223. let mut ro_gadget: PoseidonROGadget<S> = PoseidonROGadget::new(constants);
  224. let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
  225. for i in 0..31 {
  226. let num = S::random(&mut csprng);
  227. ro.absorb(num);
  228. let num_gadget =
  229. AllocatedNum::alloc(cs.namespace(|| format!("data {}", i)), || Ok(num)).unwrap();
  230. let _ = num_gadget
  231. .inputize(&mut cs.namespace(|| format!("input {}", i)))
  232. .unwrap();
  233. ro_gadget.absorb(num_gadget);
  234. }
  235. let num = ro.get_challenge();
  236. let num2_bits = ro_gadget.get_challenge(&mut cs).unwrap();
  237. let num2 = le_bits_to_num(&mut cs, num2_bits).unwrap();
  238. assert_eq!(num, num2.get_value().unwrap());
  239. }
  240. }