Nova/src/provider/poseidon_transcript.rs
src/provider/poseidon_transcript.rsRaw
1#![allow(unused)]
2
3use crate::errors::NovaError;
4use crate::traits::PrimeFieldExt;
5use crate::traits::{Group, TranscriptEngineTrait, TranscriptReprTrait};
6use core::marker::PhantomData;
7use ff::{PrimeField, PrimeFieldBits};
8use generic_array::typenum::U24;
9use neptune::{
10 circuit2::Elt,
11 poseidon::PoseidonConstants,
12 sponge::{
13 api::{IOPattern, SpongeAPI, SpongeOp},
14 circuit::SpongeCircuit,
15 vanilla::{Mode, Sponge, SpongeTrait},
16 },
17 Strength,
18};
19
20use bellperson::{
21 gadgets::{
22 boolean::{AllocatedBit, Boolean},
23 num::AllocatedNum,
24 },
25 ConstraintSystem, SynthesisError,
26};
27
28// WARNING: all this is WIP. Current version is just to have something to use in SumCheck & Spartan
29// that fullfills Nova's TranscriptEngineTrait with Poseidon.
30/// Implements the Poseidon Transcript.
31pub struct PoseidonTranscript<'a, G: Group> {
32 sponge: Sponge<'a, G::Scalar, U24>,
33}
34impl<'a, G: Group> TranscriptEngineTrait<G> for PoseidonTranscript<'a, G> {
35 fn new(label: &'static [u8]) -> Self {
36 let constants: &'a PoseidonConstants<G::Scalar, U24> =
37 &Sponge::<'a, G::Scalar, U24>::duplex_constants();
38 let mut sponge: Sponge<'a, G::Scalar, U24> =
39 Sponge::<'a, G::Scalar, U24>::new_with_constants(&constants, Mode::Duplex);
40 Self { sponge }
41 }
42 fn squeeze(&mut self, label: &'static [u8]) -> Result<G::Scalar, NovaError> {
43 let acc = &mut ();
44 let hash = SpongeAPI::squeeze(&mut self.sponge, 1, acc);
45 Ok(hash[0])
46 }
47 fn absorb<T: TranscriptReprTrait<G>>(&mut self, label: &'static [u8], o: &T) {
48 let mut elements: Vec<G::Scalar> = Vec::with_capacity(1);
49 elements.push(G::Scalar::from_uniform(&o.to_transcript_bytes()));
50 let acc = &mut ();
51 // self.sponge.absorb(o, acc);
52 SpongeAPI::absorb(&mut self.sponge, 32, &elements, acc);
53 }
54 fn dom_sep(&mut self, bytes: &'static [u8]) {
55 unimplemented!();
56 }
57}
58
59// WIP version
60/// Implements Poseidon Transcript in Bellperson gadget system
61pub struct PoseidonTranscriptCircuit<'a, G: Group, CS: ConstraintSystem<G::Scalar>> {
62 sponge: SpongeCircuit<'a, G::Scalar, U24, CS>,
63}
64impl<'a, G: Group, CS: 'a + ConstraintSystem<G::Scalar, Root = CS>>
65 PoseidonTranscriptCircuit<'a, G, CS>
66{
67 // for the TranscriptCircuit, since there is no trait already defined in Nova's codebase, we can
68 // initiate it by passing the PoseidonConstants.
69 fn new(constants: &'a PoseidonConstants<G::Scalar, U24>) -> Self {
70 let sponge = SpongeCircuit::new_with_constants(&constants, Mode::Duplex);
71 Self { sponge }
72 }
73 fn squeeze(&mut self, mut cs: &'a mut CS) -> AllocatedNum<G::Scalar> {
74 let mut ns = cs.namespace(|| "ns");
75 let hash = neptune::sponge::api::SpongeAPI::squeeze(&mut self.sponge, 1, &mut ns);
76 let hash =
77 Elt::ensure_allocated(&hash[0], &mut ns.namespace(|| "ensure allocated"), true).unwrap();
78 hash
79 }
80 fn absorb(&mut self, mut cs: &'a mut CS, element: G::Scalar) {
81 let mut ns = cs.namespace(|| "ns");
82
83 let mut allocated_elements = Vec::with_capacity(1);
84 allocated_elements.push(Elt::Allocated(
85 AllocatedNum::alloc(&mut ns.namespace(|| format!("elt{}", 1)), || Ok(element)).unwrap(),
86 ));
87
88 neptune::sponge::api::SpongeAPI::absorb(
89 &mut self.sponge,
90 32,
91 allocated_elements.as_slice(),
92 &mut ns,
93 );
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100 use crate::provider::bn256_grumpkin::bn256;
101 use crate::{
102 bellperson::solver::SatisfyingAssignment, constants::NUM_CHALLENGE_BITS,
103 gadgets::utils::le_bits_to_num, traits::Group,
104 };
105 use ff::Field;
106 use rand::rngs::OsRng;
107
108 /*
109 fn test_poseidon_transcript_with<G: Group>()
110 where
111 // we can print the field elements we get from G's Base & Scalar fields,
112 // and compare their byte representations
113 <<G as Group>::Base as PrimeField>::Repr: std::fmt::Debug,
114 <<G as Group>::Scalar as PrimeField>::Repr: std::fmt::Debug,
115 <<G as Group>::Base as PrimeField>::Repr: PartialEq<<<G as Group>::Scalar as PrimeField>::Repr>,
116 {
117 // Check that the value computed inside the circuit is equal to the value computed outside the circuit
118 let mut csprng: OsRng = OsRng;
119 let constants: PoseidonConstants<G::Scalar, U24> = Sponge::<G::Scalar, U24>::duplex_constants();
120 let constants2: PoseidonConstants<G::Scalar, U24> =
121 Sponge::<G::Scalar, U24>::duplex_constants();
122 let num_absorbs = 32;
123 let mut transcript: PoseidonTranscript<'_, G> = PoseidonTranscript::new(b"poseidontranscript");
124 let mut transcript_gadget: PoseidonTranscriptCircuit<'_, G, SatisfyingAssignment<G>> =
125 PoseidonTranscriptCircuit::new(&constants2);
126
127 let mut cs: SatisfyingAssignment<G> = SatisfyingAssignment::new();
128 for i in 0..num_absorbs {
129 let num = G::Scalar::random(&mut csprng);
130 transcript.absorb(b"test", &num);
131 // let num_gadget =
132 // AllocatedNum::alloc(cs.namespace(|| format!("data {i}")), || Ok(num)).unwrap();
133 // num_gadget
134 // .inputize(&mut cs.namespace(|| format!("input {i}")))
135 // .unwrap();
136 transcript_gadget.absorb(&mut cs, num);
137 }
138 let num = transcript.squeeze(b"test");
139 let num2: AllocatedNum<G::Scalar> = transcript_gadget.squeeze(&mut cs);
140 assert_eq!(num.unwrap(), num2.get_value().unwrap());
141 // let num2_bits = transcript_gadget.squeeze(&mut cs).unwrap();
142 // let num2 = le_bits_to_num(&mut cs, &num2_bits).unwrap();
143 // assert_eq!(num.to_repr(), num2.get_value().unwrap().to_repr());
144 }
145
146 #[test]
147 fn test_poseidon_ro() {
148 test_poseidon_transcript_with::<pasta_curves::pallas::Point>();
149 // test_poseidon_ro_with::<bn256::Point>();
150 }
151 */
152}