snarkvm_console_algorithms/keccak/
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::*;
17use snarkvm_utilities::{bits_from_bytes_le, bytes_from_bits_le};
18
19impl<const TYPE: u8, const VARIANT: usize> Hash for Keccak<TYPE, VARIANT> {
20    type Input = bool;
21    type Output = Vec<bool>;
22
23    /// Returns the Keccak hash of the given input as bits.
24    #[inline]
25    fn hash(&self, input: &[Self::Input]) -> Result<Self::Output> {
26        let result = match (TYPE, VARIANT) {
27            (0, 224) => bits_from_bytes_le(&keccak_224_native(&bytes_from_bits_le(input))).collect(),
28            (0, 256) => bits_from_bytes_le(&keccak_256_native(&bytes_from_bits_le(input))).collect(),
29            (0, 384) => bits_from_bytes_le(&keccak_384_native(&bytes_from_bits_le(input))).collect(),
30            (0, 512) => bits_from_bytes_le(&keccak_512_native(&bytes_from_bits_le(input))).collect(),
31            (1, 224) => bits_from_bytes_le(&sha3_224_native(&bytes_from_bits_le(input))).collect(),
32            (1, 256) => bits_from_bytes_le(&sha3_256_native(&bytes_from_bits_le(input))).collect(),
33            (1, 384) => bits_from_bytes_le(&sha3_384_native(&bytes_from_bits_le(input))).collect(),
34            (1, 512) => bits_from_bytes_le(&sha3_512_native(&bytes_from_bits_le(input))).collect(),
35            _ => unreachable!("Invalid Keccak type and variant"),
36        };
37        Ok(result)
38    }
39}
40
41/// Computes the Keccak-224 hash of the given preimage as bytes.
42fn keccak_224_native(preimage: &[u8]) -> [u8; 28] {
43    let mut keccak = TinyKeccak::v224();
44    keccak.update(preimage);
45
46    let mut hash = [0u8; 28];
47    keccak.finalize(&mut hash);
48    hash
49}
50
51/// Computes the Keccak-256 hash of the given preimage as bytes.
52fn keccak_256_native(preimage: &[u8]) -> [u8; 32] {
53    let mut keccak = TinyKeccak::v256();
54    keccak.update(preimage);
55
56    let mut hash = [0u8; 32];
57    keccak.finalize(&mut hash);
58    hash
59}
60
61/// Computes the Keccak-384 hash of the given preimage as bytes.
62fn keccak_384_native(preimage: &[u8]) -> [u8; 48] {
63    let mut keccak = TinyKeccak::v384();
64    keccak.update(preimage);
65
66    let mut hash = [0u8; 48];
67    keccak.finalize(&mut hash);
68    hash
69}
70
71/// Computes the Keccak-512 hash of the given preimage as bytes.
72fn keccak_512_native(preimage: &[u8]) -> [u8; 64] {
73    let mut keccak = TinyKeccak::v512();
74    keccak.update(preimage);
75
76    let mut hash = [0u8; 64];
77    keccak.finalize(&mut hash);
78    hash
79}
80
81/// Computes the SHA3-224 hash of the given preimage as bytes.
82fn sha3_224_native(preimage: &[u8]) -> [u8; 28] {
83    let mut keccak = TinySha3::v224();
84    keccak.update(preimage);
85
86    let mut hash = [0u8; 28];
87    keccak.finalize(&mut hash);
88    hash
89}
90
91/// Computes the SHA3-256 hash of the given preimage as bytes.
92fn sha3_256_native(preimage: &[u8]) -> [u8; 32] {
93    let mut keccak = TinySha3::v256();
94    keccak.update(preimage);
95
96    let mut hash = [0u8; 32];
97    keccak.finalize(&mut hash);
98    hash
99}
100
101/// Computes the SHA3-384 hash of the given preimage as bytes.
102fn sha3_384_native(preimage: &[u8]) -> [u8; 48] {
103    let mut keccak = TinySha3::v384();
104    keccak.update(preimage);
105
106    let mut hash = [0u8; 48];
107    keccak.finalize(&mut hash);
108    hash
109}
110
111/// Computes the SHA3-512 hash of the given preimage as bytes.
112fn sha3_512_native(preimage: &[u8]) -> [u8; 64] {
113    let mut keccak = TinySha3::v512();
114    keccak.update(preimage);
115
116    let mut hash = [0u8; 64];
117    keccak.finalize(&mut hash);
118    hash
119}
120
121#[cfg(test)]
122mod tests {
123    use super::*;
124    use crate::Rng;
125    use snarkvm_utilities::{bits_from_bytes_le, bytes_from_bits_le};
126
127    macro_rules! check_equivalence {
128        ($console:expr, $native:expr) => {
129            let rng = &mut TestRng::default();
130
131            let mut input_sizes = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 16, 32, 64, 128, 256, 512, 1024];
132            input_sizes.extend((0..100).map(|_| rng.gen_range(1..1024)));
133
134            for num_inputs in input_sizes {
135                println!("Checking equivalence for {num_inputs} inputs");
136
137                // Prepare the preimage.
138                let input = (0..num_inputs).map(|_| Uniform::rand(rng)).collect::<Vec<bool>>();
139
140                // Compute the native hash.
141                let expected = $native(&bytes_from_bits_le(&input));
142                let expected = bits_from_bytes_le(&expected).collect::<Vec<_>>();
143
144                // Compute the console hash.
145                let candidate = $console.hash(&input).unwrap();
146                assert_eq!(expected, candidate);
147            }
148        };
149    }
150
151    #[test]
152    fn test_keccak_224_equivalence() {
153        check_equivalence!(Keccak224::default(), keccak_224_native);
154    }
155
156    #[test]
157    fn test_keccak_256_equivalence() {
158        check_equivalence!(Keccak256::default(), keccak_256_native);
159    }
160
161    #[test]
162    fn test_keccak_384_equivalence() {
163        check_equivalence!(Keccak384::default(), keccak_384_native);
164    }
165
166    #[test]
167    fn test_keccak_512_equivalence() {
168        check_equivalence!(Keccak512::default(), keccak_512_native);
169    }
170
171    #[test]
172    fn test_sha3_224_equivalence() {
173        check_equivalence!(Sha3_224::default(), sha3_224_native);
174    }
175
176    #[test]
177    fn test_sha3_256_equivalence() {
178        check_equivalence!(Sha3_256::default(), sha3_256_native);
179    }
180
181    #[test]
182    fn test_sha3_384_equivalence() {
183        check_equivalence!(Sha3_384::default(), sha3_384_native);
184    }
185
186    #[test]
187    fn test_sha3_512_equivalence() {
188        check_equivalence!(Sha3_512::default(), sha3_512_native);
189    }
190}