export_test_vectors/
vectors.rs

1use super::{Mode, ParamType};
2use ark_ff::{PrimeField, UniformRand as _};
3use ark_serialize::CanonicalSerialize as _;
4use mina_curves::pasta::Fp;
5use mina_poseidon::{
6    constants::{self, SpongeConstants},
7    pasta,
8    poseidon::{ArithmeticSponge as Poseidon, ArithmeticSpongeParams, Sponge as _},
9};
10use num_bigint::BigUint;
11use rand::Rng;
12use serde::Serialize;
13
14//
15// generate different test vectors depending on [ParamType]
16//
17
18//
19// structs
20//
21
22#[derive(Debug, Serialize)]
23pub struct TestVectors {
24    name: String,
25    test_vectors: Vec<TestVector>,
26}
27
28#[derive(Debug, Serialize)]
29pub struct TestVector {
30    input: Vec<String>,
31    output: String,
32}
33
34//
35// logic
36//
37
38/// Computes the poseidon hash of several field elements.
39/// Uses the 'basic' configuration with N states and M rounds.
40fn poseidon<SC: SpongeConstants>(input: &[Fp], params: &'static ArithmeticSpongeParams<Fp>) -> Fp {
41    let mut s = Poseidon::<Fp, SC>::new(params);
42    s.absorb(input);
43    s.squeeze()
44}
45
46/// generates a vector of `length` field elements
47fn rand_fields(rng: &mut impl Rng, length: u8) -> Vec<Fp> {
48    let mut fields = vec![];
49    for _ in 0..length {
50        let fe = Fp::rand(rng);
51        fields.push(fe)
52    }
53    fields
54}
55
56/// creates a set of test vectors
57pub fn generate(mode: Mode, param_type: ParamType) -> TestVectors {
58    let rng = &mut o1_utils::tests::make_test_rng(Some([0u8; 32]));
59    let mut test_vectors = vec![];
60
61    // generate inputs of different lengths
62    for length in 0..6 {
63        // generate input & hash
64        let input = rand_fields(rng, length);
65        let output = match param_type {
66            ParamType::Legacy => poseidon::<constants::PlonkSpongeConstantsLegacy>(
67                &input,
68                pasta::fp_legacy::static_params(),
69            ),
70            ParamType::Kimchi => poseidon::<constants::PlonkSpongeConstantsKimchi>(
71                &input,
72                pasta::fp_kimchi::static_params(),
73            ),
74        };
75
76        // serialize input & output
77        let input = input
78            .into_iter()
79            .map(|elem| {
80                let mut input_bytes = vec![];
81                elem.into_bigint()
82                    .serialize_uncompressed(&mut input_bytes)
83                    .expect("canonical serialiation should work");
84
85                match mode {
86                    Mode::Hex => hex::encode(&input_bytes),
87                    Mode::B10 => BigUint::from_bytes_le(&input_bytes).to_string(),
88                }
89            })
90            .collect();
91        let mut output_bytes = vec![];
92        output
93            .into_bigint()
94            .serialize_uncompressed(&mut output_bytes)
95            .expect("canonical serialization should work");
96
97        // add vector
98        test_vectors.push(TestVector {
99            input,
100            output: match mode {
101                Mode::Hex => hex::encode(&output_bytes),
102                Mode::B10 => BigUint::from_bytes_le(&output_bytes).to_string(),
103            },
104        })
105    }
106
107    let name = match param_type {
108        ParamType::Legacy => "legacy",
109        ParamType::Kimchi => "kimchi",
110    }
111    .into();
112
113    TestVectors { name, test_vectors }
114}
115
116#[cfg(test)]
117mod tests {
118
119    use super::*;
120
121    #[test]
122    fn poseidon_test_vectors_regression() {
123        use mina_poseidon::pasta;
124        let rng = &mut o1_utils::tests::make_test_rng(Some([0u8; 32]));
125
126        // Values are generated w.r.t. the following commit:
127        // 1494cf973d40fb276465929eb7db1952c5de7bdc
128        // (that still uses arkworks 0.3.0)
129
130        let expected_output_bytes_legacy = [
131            [
132                27, 50, 81, 182, 145, 45, 130, 237, 199, 139, 187, 10, 92, 136, 240, 198, 253, 225,
133                120, 27, 195, 230, 84, 18, 63, 166, 134, 42, 76, 99, 230, 23,
134            ],
135            [
136                233, 146, 98, 4, 142, 113, 119, 69, 253, 205, 96, 42, 59, 82, 126, 158, 124, 46,
137                91, 165, 137, 65, 88, 8, 78, 47, 46, 44, 177, 66, 100, 61,
138            ],
139            [
140                31, 143, 157, 47, 185, 84, 125, 2, 84, 161, 192, 39, 31, 244, 0, 66, 165, 153, 39,
141                232, 47, 208, 151, 215, 250, 114, 63, 133, 81, 232, 194, 58,
142            ],
143            [
144                153, 120, 16, 250, 143, 51, 135, 158, 104, 156, 128, 128, 33, 215, 241, 207, 48,
145                47, 48, 240, 7, 87, 84, 228, 61, 194, 247, 93, 118, 187, 57, 32,
146            ],
147            [
148                249, 48, 174, 91, 239, 32, 152, 227, 183, 25, 73, 233, 135, 140, 175, 86, 89, 137,
149                127, 59, 158, 177, 113, 31, 41, 106, 153, 207, 183, 64, 236, 63,
150            ],
151            [
152                70, 27, 110, 192, 143, 211, 169, 195, 112, 51, 239, 212, 9, 207, 84, 132, 147, 176,
153                3, 178, 245, 0, 219, 132, 93, 93, 31, 210, 255, 206, 27, 2,
154            ],
155        ];
156
157        let expected_output_bytes_kimchi = [
158            [
159                168, 235, 158, 224, 243, 0, 70, 48, 138, 187, 250, 93, 32, 175, 115, 200, 27, 189,
160                171, 194, 91, 69, 151, 133, 2, 77, 4, 82, 40, 190, 173, 47,
161            ],
162            [
163                194, 127, 92, 204, 27, 156, 169, 110, 191, 207, 34, 111, 254, 28, 202, 241, 89,
164                145, 245, 226, 223, 247, 32, 48, 223, 109, 141, 29, 230, 181, 28, 13,
165            ],
166            [
167                238, 26, 57, 207, 87, 2, 255, 206, 108, 78, 212, 92, 105, 193, 255, 227, 103, 185,
168                123, 134, 79, 154, 104, 138, 78, 128, 170, 185, 149, 74, 14, 10,
169            ],
170            [
171                252, 66, 64, 58, 146, 197, 79, 63, 196, 10, 116, 66, 72, 177, 170, 234, 252, 154,
172                82, 137, 234, 3, 117, 226, 73, 211, 32, 4, 150, 196, 133, 33,
173            ],
174            [
175                42, 33, 199, 187, 104, 139, 231, 56, 52, 166, 8, 70, 141, 53, 158, 96, 175, 246,
176                75, 186, 160, 9, 17, 203, 83, 113, 240, 208, 235, 33, 111, 41,
177            ],
178            [
179                133, 233, 196, 82, 62, 17, 13, 12, 173, 230, 192, 216, 56, 126, 197, 152, 164, 155,
180                205, 238, 73, 116, 220, 196, 21, 134, 120, 39, 171, 177, 119, 25,
181            ],
182        ];
183
184        let expected_output_0_hex_legacy =
185            "1b3251b6912d82edc78bbb0a5c88f0c6fde1781bc3e654123fa6862a4c63e617";
186        let expected_output_0_hex_kimchi =
187            "a8eb9ee0f30046308abbfa5d20af73c81bbdabc25b459785024d045228bead2f";
188
189        for param_type in [ParamType::Legacy, ParamType::Kimchi] {
190            let expected_output_bytes = match param_type {
191                ParamType::Legacy => &expected_output_bytes_legacy,
192                ParamType::Kimchi => &expected_output_bytes_kimchi,
193            };
194
195            for length in 0..6 {
196                // generate input & hash
197                let input = rand_fields(rng, length);
198                let output = match param_type {
199                    ParamType::Legacy => poseidon::<constants::PlonkSpongeConstantsLegacy>(
200                        &input,
201                        pasta::fp_legacy::static_params(),
202                    ),
203                    ParamType::Kimchi => poseidon::<constants::PlonkSpongeConstantsKimchi>(
204                        &input,
205                        pasta::fp_kimchi::static_params(),
206                    ),
207                };
208
209                let mut output_bytes = vec![];
210                output
211                    .into_bigint()
212                    .serialize_uncompressed(&mut output_bytes)
213                    .expect("canonical serialization should work");
214
215                assert!(output_bytes == expected_output_bytes[length as usize]);
216            }
217
218            let expected_output_0_hex = match param_type {
219                ParamType::Legacy => expected_output_0_hex_legacy,
220                ParamType::Kimchi => expected_output_0_hex_kimchi,
221            };
222
223            let test_vectors_hex = generate(Mode::Hex, param_type);
224            assert!(test_vectors_hex.test_vectors[0].output == expected_output_0_hex);
225        }
226    }
227}