snarkvm_console_algorithms/bhp/hasher/
mod.rs1mod hash_uncompressed;
17
18use crate::Blake2Xs;
19use snarkvm_console_types::prelude::*;
20use snarkvm_utilities::BigInteger;
21
22use std::sync::Arc;
23
24pub(super) const BHP_CHUNK_SIZE: usize = 3;
26pub(super) const BHP_LOOKUP_SIZE: usize = 1 << BHP_CHUNK_SIZE;
27
28#[derive(Clone, Debug, PartialEq)]
31pub struct BHPHasher<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> {
32 bases: Arc<Vec<Vec<Group<E>>>>,
34 bases_lookup: Arc<Vec<Vec<[Group<E>; BHP_LOOKUP_SIZE]>>>,
36 random_base: Arc<Vec<Group<E>>>,
38}
39
40impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> BHPHasher<E, NUM_WINDOWS, WINDOW_SIZE> {
41 const MAX_BITS: usize = NUM_WINDOWS as usize * WINDOW_SIZE as usize * BHP_CHUNK_SIZE;
43 const MIN_BITS: usize = WINDOW_SIZE as usize * BHP_CHUNK_SIZE;
45
46 pub fn setup(domain: &str) -> Result<Self> {
48 let mut maximum_window_size = 0;
50 let mut range = E::BigInteger::from(2_u64);
51 while range < E::Scalar::modulus_minus_one_div_two() {
52 range.muln(4); maximum_window_size += 1;
55 }
56 ensure!(WINDOW_SIZE <= maximum_window_size, "The maximum BHP window size is {maximum_window_size}");
57
58 let bases = (0..NUM_WINDOWS)
60 .map(|index| {
61 let (generator, _, _) = Blake2Xs::hash_to_curve::<E::Affine>(&format!(
63 "Aleo.BHP.{NUM_WINDOWS}.{WINDOW_SIZE}.{domain}.{index}"
64 ));
65 let mut base = Group::<E>::new(generator);
66 let mut powers = Vec::with_capacity(WINDOW_SIZE as usize);
68 for _ in 0..WINDOW_SIZE {
69 powers.push(base);
70 for _ in 0..4 {
71 base = base.double();
72 }
73 }
74 powers
75 })
76 .collect::<Vec<Vec<Group<E>>>>();
77 ensure!(bases.len() == NUM_WINDOWS as usize, "Incorrect number of BHP windows ({})", bases.len());
78 for window in &bases {
79 ensure!(window.len() == WINDOW_SIZE as usize, "Incorrect BHP window size ({})", window.len());
80 }
81
82 let bases_lookup = bases
84 .iter()
85 .map(|x| {
86 x.iter()
87 .map(|g| {
88 let mut lookup = [Group::<E>::zero(); BHP_LOOKUP_SIZE];
89 for (i, element) in lookup.iter_mut().enumerate().take(BHP_LOOKUP_SIZE) {
90 *element = *g;
91 if (i & 0x01) != 0 {
92 *element += g;
93 }
94 if (i & 0x02) != 0 {
95 *element += g.double();
96 }
97 if (i & 0x04) != 0 {
98 *element = element.neg();
99 }
100 }
101 lookup
102 })
103 .collect()
104 })
105 .collect::<Vec<Vec<[Group<E>; BHP_LOOKUP_SIZE]>>>();
106 ensure!(bases_lookup.len() == NUM_WINDOWS as usize, "Incorrect number of BHP lookups ({})", bases_lookup.len());
107 for window in &bases_lookup {
108 ensure!(window.len() == WINDOW_SIZE as usize, "Incorrect BHP lookup window size ({})", window.len());
109 }
110
111 let (generator, _, _) =
113 Blake2Xs::hash_to_curve::<E::Affine>(&format!("Aleo.BHP.{NUM_WINDOWS}.{WINDOW_SIZE}.{domain}.Randomizer"));
114 let mut base_power = Group::<E>::new(generator);
115 let mut random_base = Vec::with_capacity(Scalar::<E>::size_in_bits());
116 for _ in 0..Scalar::<E>::size_in_bits() {
117 random_base.push(base_power);
118 base_power = base_power.double();
119 }
120 ensure!(
121 random_base.len() == Scalar::<E>::size_in_bits(),
122 "Incorrect number of BHP random base powers ({})",
123 random_base.len()
124 );
125
126 Ok(Self { bases: Arc::new(bases), bases_lookup: Arc::new(bases_lookup), random_base: Arc::new(random_base) })
127 }
128
129 pub fn bases(&self) -> &Arc<Vec<Vec<Group<E>>>> {
131 &self.bases
132 }
133
134 pub fn random_base(&self) -> &Arc<Vec<Group<E>>> {
136 &self.random_base
137 }
138}