Skip to content

Commit b93ab37

Browse files
authored
Merge pull request #2177 from ljedrz/perf/fewer_bhp_allocs
Fewer BHP allocations
2 parents b93295c + 941a065 commit b93ab37

File tree

5 files changed

+39
-23
lines changed

5 files changed

+39
-23
lines changed

algorithms/src/snark/varuna/ahp/matrices.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ use snarkvm_fields::{Field, PrimeField};
2727
use snarkvm_utilities::{cfg_iter, cfg_iter_mut, serialize::*};
2828

2929
use anyhow::{anyhow, ensure, Result};
30-
use itertools::Itertools;
3130
use std::collections::BTreeMap;
3231

3332
#[cfg(not(feature = "serial"))]

circuit/algorithms/src/bhp/hash_uncompressed.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,32 @@ impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> HashUncompres
3838
// Initialize a variable to store the hash from the current iteration.
3939
let mut digest = Group::zero();
4040

41+
// Prepare a reusable vector for the preimage.
42+
let mut preimage = Vec::with_capacity(num_hasher_bits);
43+
4144
// Compute the hash of the input.
4245
for (i, input_bits) in input.chunks(max_input_bits_per_iteration).enumerate() {
4346
// Determine if this is the first iteration.
44-
let preimage = match i == 0 {
47+
match i == 0 {
4548
// Construct the first iteration as: [ 0...0 || DOMAIN || LENGTH(INPUT) || INPUT[0..BLOCK_SIZE] ].
4649
true => {
4750
// Initialize a vector for the hash preimage.
48-
let mut preimage = Vec::with_capacity(num_hasher_bits);
4951
preimage.extend(self.domain.clone());
5052
U64::constant(console::U64::new(input.len() as u64)).write_bits_le(&mut preimage);
5153
preimage.extend_from_slice(input_bits);
52-
preimage
5354
}
5455
// Construct the subsequent iterations as: [ PREVIOUS_HASH[0..DATA_BITS] || INPUT[I * BLOCK_SIZE..(I + 1) * BLOCK_SIZE] ].
5556
false => {
5657
// Initialize a vector for the hash preimage.
57-
let mut preimage = Vec::with_capacity(num_hasher_bits);
5858
digest.to_x_coordinate().write_bits_le(&mut preimage);
5959
preimage.truncate(num_data_bits);
6060
preimage.extend_from_slice(input_bits);
61-
preimage
6261
}
63-
};
62+
}
6463
// Hash the preimage for this iteration.
6564
digest = self.hasher.hash_uncompressed(&preimage);
65+
// Clear the preimage vector for the next iteration.
66+
preimage.clear();
6667
}
6768

6869
digest

circuit/algorithms/src/bhp/hasher/hash_uncompressed.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
use super::*;
1616

17+
use std::borrow::Cow;
18+
1719
impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> HashUncompressed
1820
for BHPHasher<E, NUM_WINDOWS, WINDOW_SIZE>
1921
{
@@ -31,18 +33,27 @@ impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> HashUncompres
3133
}
3234

3335
// Ensure the input size is within the parameter size.
34-
let mut input = input.to_vec();
35-
match input.len() <= Self::MAX_BITS {
36+
let input = match input.len() <= Self::MAX_BITS {
3637
true => {
3738
// Pad the input to a multiple of `BHP_CHUNK_SIZE` for hashing.
3839
if input.len() % BHP_CHUNK_SIZE != 0 {
40+
// Compute the number of padding bits.
3941
let padding = BHP_CHUNK_SIZE - (input.len() % BHP_CHUNK_SIZE);
40-
input.resize(input.len() + padding, Boolean::constant(false));
41-
assert_eq!(input.len() % BHP_CHUNK_SIZE, 0, "Input must be a multiple of {BHP_CHUNK_SIZE}");
42+
// Pad the input with `false` bits.
43+
let mut padded_input = Vec::with_capacity(input.len() + padding);
44+
padded_input.extend_from_slice(input);
45+
padded_input.resize(input.len() + padding, Boolean::constant(false));
46+
// Ensure the input is a multiple of `BHP_CHUNK_SIZE`.
47+
assert_eq!(padded_input.len() % BHP_CHUNK_SIZE, 0, "Input must be a multiple of {BHP_CHUNK_SIZE}");
48+
// Return the padded input.
49+
Cow::Owned(padded_input)
50+
} else {
51+
// Return the input as a borrowed slice.
52+
Cow::Borrowed(input)
4253
}
4354
}
4455
false => E::halt(format!("Inputs to this BHP cannot exceed {} bits", Self::MAX_BITS)),
45-
}
56+
};
4657

4758
// Declare the 1 constant field element.
4859
let one = Field::one();

console/algorithms/src/bhp/hash_uncompressed.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -38,31 +38,31 @@ impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> HashUncompres
3838
// Initialize a variable to store the hash from the current iteration.
3939
let mut digest = Group::<E>::zero();
4040

41+
// Prepare a reusable vector for the preimage.
42+
let mut preimage = Vec::with_capacity(num_hasher_bits);
43+
4144
// Compute the hash of the input.
4245
for (i, input_bits) in input.chunks(max_input_bits_per_iteration).enumerate() {
4346
// Determine if this is the first iteration.
44-
let preimage = match i == 0 {
47+
match i == 0 {
4548
// Construct the first iteration as: [ 0...0 || DOMAIN || LENGTH(INPUT) || INPUT[0..BLOCK_SIZE] ].
4649
true => {
4750
// Initialize a vector for the hash preimage.
48-
let mut preimage = Vec::with_capacity(num_hasher_bits);
4951
preimage.extend(&self.domain);
5052
(input.len() as u64).write_bits_le(&mut preimage);
5153
preimage.extend(input_bits);
52-
preimage
5354
}
5455
// Construct the subsequent iterations as: [ PREVIOUS_HASH[0..DATA_BITS] || INPUT[I * BLOCK_SIZE..(I + 1) * BLOCK_SIZE] ].
5556
false => {
5657
// Initialize a vector for the hash preimage.
57-
let mut preimage = Vec::with_capacity(num_hasher_bits);
5858
digest.to_x_coordinate().write_bits_le(&mut preimage);
5959
preimage.truncate(num_data_bits);
6060
preimage.extend(input_bits);
61-
preimage
6261
}
63-
};
62+
}
6463
// Hash the preimage for this iteration.
6564
digest = self.hasher.hash_uncompressed(&preimage)?;
65+
preimage.clear();
6666
}
6767

6868
Ok(digest)

console/algorithms/src/bhp/hasher/hash_uncompressed.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414

1515
use super::*;
1616

17+
use std::borrow::Cow;
18+
1719
impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> HashUncompressed
1820
for BHPHasher<E, NUM_WINDOWS, WINDOW_SIZE>
1921
{
@@ -36,12 +38,15 @@ impl<E: Environment, const NUM_WINDOWS: u8, const WINDOW_SIZE: u8> HashUncompres
3638
);
3739

3840
// Pad the input to a multiple of `BHP_CHUNK_SIZE` for hashing.
39-
let mut input = input.to_vec();
40-
if input.len() % BHP_CHUNK_SIZE != 0 {
41+
let input = if input.len() % BHP_CHUNK_SIZE != 0 {
4142
let padding = BHP_CHUNK_SIZE - (input.len() % BHP_CHUNK_SIZE);
42-
input.resize(input.len() + padding, false);
43-
ensure!((input.len() % BHP_CHUNK_SIZE) == 0, "Input must be a multiple of {BHP_CHUNK_SIZE}");
44-
}
43+
let mut padded_input = vec![false; input.len() + padding];
44+
padded_input[..input.len()].copy_from_slice(input);
45+
ensure!((padded_input.len() % BHP_CHUNK_SIZE) == 0, "Input must be a multiple of {BHP_CHUNK_SIZE}");
46+
Cow::Owned(padded_input)
47+
} else {
48+
Cow::Borrowed(input)
49+
};
4550

4651
// Compute sum of h_i^{sum of (1-2*c_{i,j,2})*(1+c_{i,j,0}+2*c_{i,j,1})*2^{4*(j-1)} for all j in segment}
4752
// for all i. Described in section 5.4.1.7 in the Zcash protocol specification.

0 commit comments

Comments
 (0)