snarkvm_circuit_algorithms/pedersen/
hash.rs

1// Copyright 2024 Aleo Network Foundation
2// This file is part of the snarkVM library.
3
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at:
7
8// http://www.apache.org/licenses/LICENSE-2.0
9
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use super::*;
17
18impl<E: Environment, const NUM_BITS: u8> Hash for Pedersen<E, NUM_BITS> {
19    type Input = Boolean<E>;
20    type Output = Field<E>;
21
22    /// Returns the Pedersen hash of the given input as a field element.
23    fn hash(&self, input: &[Self::Input]) -> Self::Output {
24        // Compute the Pedersen hash as an affine group element, and return the x-coordinate.
25        self.hash_uncompressed(input).to_x_coordinate()
26    }
27}
28
29impl<E: Environment, const NUM_BITS: u8> Metrics<dyn Hash<Input = Boolean<E>, Output = Field<E>>>
30    for Pedersen<E, NUM_BITS>
31{
32    type Case = Vec<Mode>;
33
34    #[inline]
35    fn count(case: &Self::Case) -> Count {
36        count!(Pedersen<E, NUM_BITS>, HashUncompressed<Input = Boolean<E>, Output = Group<E>>, case)
37    }
38}
39
40impl<E: Environment, const NUM_BITS: u8> OutputMode<dyn Hash<Input = Boolean<E>, Output = Field<E>>>
41    for Pedersen<E, NUM_BITS>
42{
43    type Case = Vec<Mode>;
44
45    #[inline]
46    fn output_mode(parameter: &Self::Case) -> Mode {
47        output_mode!(Pedersen<E, NUM_BITS>, HashUncompressed<Input = Boolean<E>, Output = Group<E>>, parameter)
48    }
49}
50
51#[cfg(all(test, feature = "console"))]
52mod tests {
53    use super::*;
54    use snarkvm_circuit_types::environment::Circuit;
55    use snarkvm_utilities::{TestRng, Uniform};
56
57    const ITERATIONS: u64 = 10;
58    const MESSAGE: &str = "PedersenCircuit0";
59    const NUM_BITS_MULTIPLIER: u8 = 8;
60
61    fn check_hash<const NUM_BITS: u8>(mode: Mode, rng: &mut TestRng) {
62        use console::Hash as H;
63
64        // Initialize the Pedersen hash.
65        let native = console::Pedersen::<<Circuit as Environment>::Network, NUM_BITS>::setup(MESSAGE);
66        let circuit = Pedersen::<Circuit, NUM_BITS>::constant(native.clone());
67
68        for i in 0..ITERATIONS {
69            // Sample a random input.
70            let input = (0..NUM_BITS).map(|_| bool::rand(rng)).collect::<Vec<bool>>();
71            // Compute the expected hash.
72            let expected = native.hash(&input).expect("Failed to hash native input");
73            // Prepare the circuit input.
74            let circuit_input: Vec<Boolean<_>> = Inject::new(mode, input);
75
76            Circuit::scope(format!("Pedersen {mode} {i}"), || {
77                // Perform the hash operation.
78                let candidate = circuit.hash(&circuit_input);
79                assert_eq!(expected, candidate.eject_value());
80
81                // Check constraint counts and output mode.
82                let modes = circuit_input.iter().map(|b| b.eject_mode()).collect::<Vec<_>>();
83                assert_count!(
84                    Pedersen<Circuit, NUM_BITS>,
85                    HashUncompressed<Input = Boolean<Circuit>, Output = Group<Circuit>>,
86                    &modes
87                );
88                assert_output_mode!(
89                    Pedersen<Circuit, NUM_BITS>,
90                    HashUncompressed<Input = Boolean<Circuit>, Output = Group<Circuit>>,
91                    &modes,
92                    candidate
93                );
94            });
95        }
96    }
97
98    #[test]
99    fn test_hash_constant() {
100        // Set the number of windows, and modulate the window size.
101        let mut rng = TestRng::default();
102        check_hash::<NUM_BITS_MULTIPLIER>(Mode::Constant, &mut rng);
103        check_hash::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
104        check_hash::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
105        check_hash::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
106        check_hash::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Constant, &mut rng);
107    }
108
109    #[test]
110    fn test_hash_public() {
111        // Set the number of windows, and modulate the window size.
112        let mut rng = TestRng::default();
113        check_hash::<NUM_BITS_MULTIPLIER>(Mode::Public, &mut rng);
114        check_hash::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
115        check_hash::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
116        check_hash::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
117        check_hash::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Public, &mut rng);
118    }
119
120    #[test]
121    fn test_hash_private() {
122        // Set the number of windows, and modulate the window size.
123        let mut rng = TestRng::default();
124        check_hash::<NUM_BITS_MULTIPLIER>(Mode::Private, &mut rng);
125        check_hash::<{ 2 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
126        check_hash::<{ 3 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
127        check_hash::<{ 4 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
128        check_hash::<{ 5 * NUM_BITS_MULTIPLIER }>(Mode::Private, &mut rng);
129    }
130}