Skip to content

Commit

Permalink
refactor: Make Digest::LEN an associated const
Browse files Browse the repository at this point in the history
Deprecate `digest::DIGEST_LENGTH`.
  • Loading branch information
jan-ferdinand committed Jun 21, 2024
1 parent 60ed2b2 commit cb53ad6
Show file tree
Hide file tree
Showing 5 changed files with 50 additions and 42 deletions.
23 changes: 12 additions & 11 deletions twenty-first/benches/tip5.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use rand::{thread_rng, Rng};
use rayon::prelude::{IntoParallelRefIterator, ParallelIterator};
use twenty_first::math::b_field_element::BFieldElement;
use twenty_first::math::digest::DIGEST_LENGTH;
use criterion::criterion_group;
use criterion::criterion_main;
use criterion::BenchmarkId;
use criterion::Criterion;
use rand::random;
use rayon::prelude::*;

use twenty_first::math::other::random_elements;
use twenty_first::math::tip5::Tip5;
use twenty_first::util_types::algebraic_hasher::AlgebraicHasher;
use twenty_first::prelude::*;

fn bench_10(c: &mut Criterion) {
let mut group = c.benchmark_group("tip5/hash_10");

let size = 10;
group.sample_size(100);

let single_element: [BFieldElement; 10] = thread_rng().gen();
let single_element: [BFieldElement; 10] = random();
group.bench_function(BenchmarkId::new("Tip5 / Hash 10", size), |bencher| {
bencher.iter(|| Tip5::hash_10(&single_element));
});
Expand All @@ -22,8 +23,8 @@ fn bench_10(c: &mut Criterion) {
fn bench_pair(c: &mut Criterion) {
let mut group = c.benchmark_group("tip5/hash_pair");

let left = thread_rng().gen();
let right = thread_rng().gen();
let left = random();
let right = random();

group.bench_function(BenchmarkId::new("Tip5 / Hash Pair", "pair"), |bencher| {
bencher.iter(|| Tip5::hash_pair(left, right));
Expand Down Expand Up @@ -59,7 +60,7 @@ fn bench_parallel(c: &mut Criterion) {
elements
.par_iter()
.map(Tip5::hash_10)
.collect::<Vec<[BFieldElement; DIGEST_LENGTH]>>()
.collect::<Vec<[BFieldElement; Digest::LEN]>>()
});
});
}
Expand Down
4 changes: 2 additions & 2 deletions twenty-first/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use thiserror::Error;

pub use crate::math::bfield_codec::BFieldCodecError;
pub use crate::math::bfield_codec::PolynomialBFieldCodecError;
use crate::prelude::tip5::DIGEST_LENGTH;
use crate::prelude::tip5::Digest;
use crate::prelude::x_field_element::EXTENSION_DEGREE;
use crate::prelude::BFieldElement;
pub use crate::util_types::merkle_tree::MerkleTreeError;
Expand Down Expand Up @@ -36,7 +36,7 @@ pub enum TryFromXFieldElementError {
#[derive(Debug, Clone, Eq, PartialEq, Error)]
#[non_exhaustive]
pub enum TryFromDigestError {
#[error("expected {DIGEST_LENGTH} elements for digest, but got {0}")]
#[error("expected {} elements for digest, but got {0}", Digest::LEN)]
InvalidLength(usize),

#[error("invalid `BFieldElement`")]
Expand Down
37 changes: 23 additions & 14 deletions twenty-first/src/math/digest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,16 @@ use crate::error::TryFromHexDigestError;
use crate::math::b_field_element::BFieldElement;
use crate::util_types::algebraic_hasher::AlgebraicHasher;

#[deprecated(since = "0.42.0", note = "use `Digest::LEN` instead")]
pub const DIGEST_LENGTH: usize = 5;

/// The result of hashing a sequence of elements, for example using [Tip5].
/// Sometimes called a “hash”.
///
/// [Tip5]: crate::prelude::tip5::Tip5
// note: Serialize and Deserialize have custom implementations below
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, BFieldCodec, Arbitrary)]
pub struct Digest(pub [BFieldElement; DIGEST_LENGTH]);
pub struct Digest(pub [BFieldElement; Digest::LEN]);

impl GetSize for Digest {
fn get_stack_size() -> usize {
Expand Down Expand Up @@ -55,13 +60,17 @@ impl Ord for Digest {
}

impl Digest {
pub const BYTES: usize = DIGEST_LENGTH * BFieldElement::BYTES;
/// The number of [elements](BFieldElement) in a digest.
pub const LEN: usize = 5;

pub fn values(self) -> [BFieldElement; DIGEST_LENGTH] {
/// The number of bytes in a digest.
pub const BYTES: usize = Self::LEN * BFieldElement::BYTES;

pub fn values(self) -> [BFieldElement; Self::LEN] {
self.0
}

pub const fn new(digest: [BFieldElement; DIGEST_LENGTH]) -> Self {
pub const fn new(digest: [BFieldElement; Self::LEN]) -> Self {
Self(digest)
}

Expand All @@ -74,7 +83,7 @@ impl Digest {

impl Default for Digest {
fn default() -> Self {
Self([BFieldElement::ZERO; DIGEST_LENGTH])
Self([BFieldElement::ZERO; Self::LEN])
}
}

Expand All @@ -86,10 +95,10 @@ impl fmt::Display for Digest {

impl Distribution<Digest> for Standard {
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Digest {
// FIXME: impl Fill for [BFieldElement] to rng.fill() a [BFieldElement; DIGEST_LENGTH].
// FIXME: impl Fill for [BFieldElement] to rng.fill() a [BFieldElement; Digest::LEN].
let elements = rng
.sample_iter(Standard)
.take(DIGEST_LENGTH)
.take(Digest::LEN)
.collect_vec()
.try_into()
.unwrap();
Expand Down Expand Up @@ -193,7 +202,7 @@ impl TryFrom<BigUint> for Digest {

fn try_from(value: BigUint) -> Result<Self, Self::Error> {
let mut remaining = value;
let mut digest_innards = [BFieldElement::ZERO; DIGEST_LENGTH];
let mut digest_innards = [BFieldElement::ZERO; Self::LEN];
let modulus: BigUint = BFieldElement::P.into();
for digest_element in digest_innards.iter_mut() {
let element = u64::try_from(remaining.clone() % modulus.clone()).unwrap();
Expand All @@ -214,7 +223,7 @@ impl From<Digest> for BigUint {
let Digest(digest_innards) = digest;
let mut ret = BigUint::zero();
let modulus: BigUint = BFieldElement::P.into();
for i in (0..DIGEST_LENGTH).rev() {
for i in (0..Digest::LEN).rev() {
ret *= modulus.clone();
let digest_element: BigUint = digest_innards[i].value().into();
ret += digest_element;
Expand All @@ -230,7 +239,7 @@ impl Digest {
/// way to hash a digest in the virtual machine.
#[deprecated(since = "0.42.0", note = "use `AlgebraicHasher::hash_pair` instead")]
pub fn hash<H: AlgebraicHasher>(self) -> Digest {
H::hash_pair(self, Digest::new([BFieldElement::ZERO; DIGEST_LENGTH]))
H::hash_pair(self, Digest::new([BFieldElement::ZERO; Self::LEN]))
}

/// Encode digest as hex
Expand Down Expand Up @@ -270,7 +279,7 @@ impl<'de> Deserialize<'de> for Digest {
let bytes = hex::decode(hex_string).map_err(serde::de::Error::custom)?;
Ok(Self::try_from(&bytes as &[u8]).map_err(serde::de::Error::custom)?)
} else {
Ok(Self::new(<[BFieldElement; DIGEST_LENGTH]>::deserialize(
Ok(Self::new(<[BFieldElement; Self::LEN]>::deserialize(
deserializer,
)?))
}
Expand Down Expand Up @@ -302,7 +311,7 @@ pub(crate) mod digest_tests {
/// Test helper struct for corrupting digests. Primarily used for negative tests.
#[derive(Debug, Clone, PartialEq, Eq, test_strategy::Arbitrary)]
pub(crate) struct DigestCorruptor {
#[strategy(vec(0..DIGEST_LENGTH, 1..DIGEST_LENGTH))]
#[strategy(vec(0..Digest::LEN, 1..=Digest::LEN))]
#[filter(#corrupt_indices.iter().all_unique())]
corrupt_indices: Vec<usize>,

Expand Down Expand Up @@ -451,11 +460,11 @@ pub(crate) mod digest_tests {

#[test]
fn digest_ordering() {
let val0 = Digest::new([bfe!(0); DIGEST_LENGTH]);
let val0 = Digest::new(bfe_array![0; Digest::LEN]);
let val1 = Digest::new(bfe_array![14, 0, 0, 0, 0]);
assert!(val1 > val0);

let val2 = Digest::new([bfe!(14); DIGEST_LENGTH]);
let val2 = Digest::new(bfe_array![14; Digest::LEN]);
assert!(val2 > val1);
assert!(val2 > val0);

Expand Down
19 changes: 9 additions & 10 deletions twenty-first/src/math/tip5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ use serde::Serialize;

use crate::math::b_field_element::BFieldElement;
pub use crate::math::digest::Digest;
pub use crate::math::digest::DIGEST_LENGTH;
use crate::math::mds::generated_function;
use crate::util_types::algebraic_hasher::AlgebraicHasher;
use crate::util_types::algebraic_hasher::Domain;
Expand Down Expand Up @@ -562,7 +561,7 @@ impl Tip5 {
/// hash_10
/// Hash 10 elements, or two digests. There is no padding because
/// the input length is fixed.
pub fn hash_10(input: &[BFieldElement; 10]) -> [BFieldElement; DIGEST_LENGTH] {
pub fn hash_10(input: &[BFieldElement; 10]) -> [BFieldElement; Digest::LEN] {
let mut sponge = Self::new(Domain::FixedLength);

// absorb once
Expand All @@ -571,19 +570,19 @@ impl Tip5 {
sponge.permutation();

// squeeze once
sponge.state[..DIGEST_LENGTH].try_into().unwrap()
sponge.state[..Digest::LEN].try_into().unwrap()
}
}

impl AlgebraicHasher for Tip5 {
fn hash_pair(left: Digest, right: Digest) -> Digest {
let mut sponge = Self::new(Domain::FixedLength);
sponge.state[..DIGEST_LENGTH].copy_from_slice(&left.values());
sponge.state[DIGEST_LENGTH..2 * DIGEST_LENGTH].copy_from_slice(&right.values());
sponge.state[..Digest::LEN].copy_from_slice(&left.values());
sponge.state[Digest::LEN..2 * Digest::LEN].copy_from_slice(&right.values());

sponge.permutation();

let digest_values = sponge.state[..DIGEST_LENGTH].try_into().unwrap();
let digest_values = sponge.state[..Digest::LEN].try_into().unwrap();
Digest::new(digest_values)
}
}
Expand Down Expand Up @@ -791,15 +790,15 @@ pub(crate) mod tip5_tests {
#[test]
fn hash10_test_vectors() {
let mut preimage = [BFieldElement::ZERO; RATE];
let mut digest: [BFieldElement; DIGEST_LENGTH];
let mut digest: [BFieldElement; Digest::LEN];
for i in 0..6 {
digest = Tip5::hash_10(&preimage);
println!(
"{:?} -> {:?}",
preimage.iter().map(|b| b.value()).collect_vec(),
digest.iter().map(|b| b.value()).collect_vec()
);
preimage[i..DIGEST_LENGTH + i].copy_from_slice(&digest);
preimage[i..Digest::LEN + i].copy_from_slice(&digest);
}
digest = Tip5::hash_10(&preimage);
println!(
Expand All @@ -826,7 +825,7 @@ pub(crate) mod tip5_tests {

#[test]
fn hash_varlen_test_vectors() {
let mut digest_sum = [BFieldElement::ZERO; DIGEST_LENGTH];
let mut digest_sum = [BFieldElement::ZERO; Digest::LEN];
for i in 0..20 {
let preimage = (0..i).map(BFieldElement::new).collect_vec();
let digest = Tip5::hash_varlen(&preimage);
Expand Down Expand Up @@ -866,7 +865,7 @@ pub(crate) mod tip5_tests {
sponge.pad_and_absorb_all(preimage);
let squeeze_result = sponge.squeeze();

Digest::new((&squeeze_result[..DIGEST_LENGTH]).try_into().unwrap())
Digest::new((&squeeze_result[..Digest::LEN]).try_into().unwrap())
}

#[test]
Expand Down
9 changes: 4 additions & 5 deletions twenty-first/src/util_types/algebraic_hasher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use num_traits::ConstZero;
use crate::math::b_field_element::BFieldElement;
use crate::math::bfield_codec::BFieldCodec;
use crate::math::digest::Digest;
use crate::math::digest::DIGEST_LENGTH;
use crate::math::x_field_element::XFieldElement;
use crate::math::x_field_element::EXTENSION_DEGREE;

Expand Down Expand Up @@ -78,7 +77,7 @@ pub trait AlgebraicHasher: Sponge {
sponge.pad_and_absorb_all(input);
let produce: [BFieldElement; RATE] = sponge.squeeze();

Digest::new((&produce[..DIGEST_LENGTH]).try_into().unwrap())
Digest::new((&produce[..Digest::LEN]).try_into().unwrap())
}

/// Produce `num_indices` random integer values in the range `[0, upper_bound)`. The
Expand Down Expand Up @@ -136,7 +135,7 @@ mod algebraic_hasher_tests {
use rand_distr::Distribution;
use rand_distr::Standard;

use crate::math::digest::DIGEST_LENGTH;
use crate::math::digest::Digest;
use crate::math::tip5::Tip5;
use crate::math::x_field_element::EXTENSION_DEGREE;

Expand Down Expand Up @@ -183,8 +182,8 @@ mod algebraic_hasher_tests {
encode_prop(XFieldElement::ZERO, xfe_max);

// Digest
let digest_zero = Digest::new([BFieldElement::ZERO; DIGEST_LENGTH]);
let digest_max = Digest::new([bfe_max; DIGEST_LENGTH]);
let digest_zero = Digest::new([BFieldElement::ZERO; Digest::LEN]);
let digest_max = Digest::new([bfe_max; Digest::LEN]);
encode_prop(digest_zero, digest_max);

// u128
Expand Down

0 comments on commit cb53ad6

Please sign in to comment.