light_hasher/
hash_to_field_size.rs

1#[cfg(feature = "alloc")]
2use borsh::BorshSerialize;
3use tinyvec::ArrayVec;
4
5#[cfg(feature = "alloc")]
6use crate::Vec;
7use crate::{keccak::Keccak, Hasher, HasherError};
8
9pub const HASH_TO_FIELD_SIZE_SEED: u8 = u8::MAX;
10
11pub trait HashToFieldSize {
12    fn hash_to_field_size(&self) -> Result<[u8; 32], HasherError>;
13}
14
15#[cfg(feature = "alloc")]
16impl<T> HashToFieldSize for T
17where
18    T: BorshSerialize,
19{
20    fn hash_to_field_size(&self) -> Result<[u8; 32], HasherError> {
21        let borsh_vec = self.try_to_vec().map_err(|_| HasherError::BorshError)?;
22        #[cfg(all(debug_assertions, feature = "std"))]
23        {
24            if std::env::var("RUST_BACKTRACE").is_ok() {
25                println!(
26                    "#[hash] hash_to_field_size borsh try_to_vec {:?}",
27                    borsh_vec
28                );
29            }
30        }
31        let bump_seed = [HASH_TO_FIELD_SIZE_SEED];
32        let slices = [borsh_vec.as_slice(), bump_seed.as_slice()];
33        // Keccak::hashv is fallible (trait-unified), propagate errors instead of panicking.
34        let mut hashed_value = Keccak::hashv(slices.as_slice())?;
35        // Truncates to 31 bytes so that value is less than bn254 Fr modulo
36        // field size.
37        hashed_value[0] = 0;
38        Ok(hashed_value)
39    }
40}
41
42#[cfg(feature = "alloc")]
43pub fn hashv_to_bn254_field_size_be(bytes: &[&[u8]]) -> [u8; 32] {
44    let mut slices = Vec::with_capacity(bytes.len() + 1);
45    bytes.iter().for_each(|x| slices.push(*x));
46    let bump_seed = [HASH_TO_FIELD_SIZE_SEED];
47    slices.push(bump_seed.as_slice());
48    // SAFETY: cannot panic Hasher::hashv returns an error because Poseidon can panic.
49    let mut hashed_value: [u8; 32] = Keccak::hashv(&slices).unwrap();
50    // Truncates to 31 bytes so that value is less than bn254 Fr modulo
51    // field size.
52    hashed_value[0] = 0;
53    hashed_value
54}
55
56#[cfg(feature = "alloc")]
57pub fn hashv_to_bn254_field_size_be_array(bytes: &[[u8; 32]]) -> [u8; 32] {
58    let mut slices = Vec::with_capacity(bytes.len() + 1);
59    bytes.iter().for_each(|x| slices.push(x.as_slice()));
60    let bump_seed = [HASH_TO_FIELD_SIZE_SEED];
61    slices.push(bump_seed.as_slice());
62    let mut hashed_value: [u8; 32] = Keccak::hashv(&slices).unwrap();
63    // Truncates to 31 bytes so that value is less than bn254 Fr modulo
64    // field size.
65    hashed_value[0] = 0;
66    hashed_value
67}
68
69/// MAX_SLICES - 1 is usable.
70pub fn hashv_to_bn254_field_size_be_const_array<const MAX_SLICES: usize>(
71    bytes: &[&[u8]],
72) -> Result<[u8; 32], HasherError> {
73    let bump_seed = [HASH_TO_FIELD_SIZE_SEED];
74    let mut slices = ArrayVec::<[&[u8]; MAX_SLICES]>::new();
75    if bytes.len() > MAX_SLICES - 1 {
76        return Err(HasherError::InvalidInputLength(MAX_SLICES, bytes.len()));
77    }
78    bytes.iter().for_each(|x| slices.push(*x));
79    slices.push(bump_seed.as_slice());
80    let mut hashed_value: [u8; 32] = Keccak::hashv(&slices)?;
81    // Truncates to 31 bytes so that value is less than bn254 Fr modulo
82    // field size.
83    hashed_value[0] = 0;
84    Ok(hashed_value)
85}
86
87/// Hashes the provided `bytes` with Keccak256 and ensures the result fits
88/// in the BN254 field by truncating the resulting hash to 31 bytes.
89///
90/// # Examples
91///
92/// ```
93/// # #[cfg(feature = "keccak")]
94/// # use light_hasher::hash_to_field_size::hash_to_bn254_field_size_be;
95/// #
96/// # #[cfg(feature = "keccak")]
97/// hash_to_bn254_field_size_be(&[0u8; 32]);
98/// ```
99pub fn hash_to_bn254_field_size_be(bytes: &[u8]) -> [u8; 32] {
100    hashv_to_bn254_field_size_be_const_array::<2>(&[bytes]).unwrap()
101}
102
103#[cfg(all(not(target_os = "solana"), feature = "poseidon"))]
104pub fn is_smaller_than_bn254_field_size_be(bytes: &[u8; 32]) -> bool {
105    use ark_ff::PrimeField;
106    use num_bigint::BigUint;
107    let bigint = BigUint::from_bytes_be(bytes);
108    bigint < ark_bn254::Fr::MODULUS.into()
109}