light_hasher/
hash_to_field_size.rs1#[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 let mut hashed_value = Keccak::hashv(slices.as_slice())?;
35 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 let mut hashed_value: [u8; 32] = Keccak::hashv(&slices).unwrap();
50 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 hashed_value[0] = 0;
66 hashed_value
67}
68
69pub 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 hashed_value[0] = 0;
84 Ok(hashed_value)
85}
86
87pub 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}