Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions pkgs/pow/src/blake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
use crate::consts::blake::{BLOCK, CB, IV, SIGMA};
use crate::util::buffer::{Buffer, Compress};
use crate::util::impl_digest;
use crate::util::memops::load_u64_le;
use crate::util::memops::load_u64s_be;

use digest::{FixedOutput, Output, Update};

Expand Down Expand Up @@ -72,13 +72,6 @@ fn advance_counter(t0: &mut u64, t1: &mut u64) {
}
}

/// Loads one block as sixteen message words in the byte order used by the
/// compression function.
#[inline]
fn load_message(block: &[u8]) -> [u64; 16] {
core::array::from_fn(|i| load_u64_le(block, i).swap_bytes())
}

/// Chaining value and the 128-bit count of bits compressed so far.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
struct Core {
Expand All @@ -91,7 +84,7 @@ impl Compress<BLOCK> for Core {
#[cfg_attr(not(debug_assertions), inline(always))]
fn compress(&mut self, block: &[u8; BLOCK]) {
advance_counter(&mut self.t0, &mut self.t1);
compress(&mut self.h, &load_message(block), self.t0, self.t1);
compress(&mut self.h, &load_u64s_be(block), self.t0, self.t1);
}
}

Expand Down Expand Up @@ -142,14 +135,14 @@ impl FixedOutput for Blake512 {
block[111] |= 0x01;
block[112..120].copy_from_slice(&th.to_be_bytes());
block[120..].copy_from_slice(&tl.to_be_bytes());
compress(h, &load_message(block), t0, t1);
compress(h, &load_u64s_be(block), t0, t1);
} else {
compress(h, &load_message(block), t0, t1);
compress(h, &load_u64s_be(block), t0, t1);
let mut last = [0u8; BLOCK];
last[111] = 0x01;
last[112..120].copy_from_slice(&th.to_be_bytes());
last[120..].copy_from_slice(&tl.to_be_bytes());
compress(h, &load_message(&last), 0, 0);
compress(h, &load_u64s_be(&last), 0, 0);
}

for (bytes, word) in out.chunks_exact_mut(8).zip(h) {
Expand Down
32 changes: 10 additions & 22 deletions pkgs/pow/src/consts/blake.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,14 @@
//

//! Blake-512 constants.
//!
//! IV values are the SHA-512 initial hash values (fractional parts of the
//! square roots of the first 8 primes). Round constants are the first 1024 bits
//! of the fractional part of pi. The sigma permutation table is from the Blake
//! specification (Table 2).

use crate::util::const_array;

/// Block size in bytes.
pub(crate) const BLOCK: usize = 128;

/// Blake-512 initial hash values (SHA-512 IV).
/// Blake-512 IV, equal to the SHA-512 IV. Each word holds the first 64
/// fractional bits of the square root of one of the first 8 primes.
#[rustfmt::skip]
pub(crate) static IV: [u64; 8] = [
0x6a09e667f3bcc908, 0xbb67ae8584caa73b,
Expand All @@ -23,7 +21,7 @@ pub(crate) static IV: [u64; 8] = [
0x1f83d9abfb41bd6b, 0x5be0cd19137e2179,
];

/// Round constants (first 1024 bits of the fractional part of pi).
/// Round constants, the first 1024 fractional bits of pi.
#[rustfmt::skip]
pub(crate) static CB: [u64; 16] = [
0x243f6a8885a308d3, 0x13198a2e03707344,
Expand All @@ -36,9 +34,9 @@ pub(crate) static CB: [u64; 16] = [
0x0801f2e2858efc16, 0x636920d871574e69,
];

/// Message-word permutation schedule (10 unique rows, then rows 0..6 again for rounds 10..15).
/// Ten distinct message-word permutations (BLAKE 1.3 Table 2.1).
#[rustfmt::skip]
pub(crate) static SIGMA: [[usize; 16]; 16] = [
static SIGMA_ROWS: [[usize; 16]; 10] = [
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
Expand All @@ -49,25 +47,15 @@ pub(crate) static SIGMA: [[usize; 16]; 16] = [
[13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10],
[ 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5],
[10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0],
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15],
[14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3],
[11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4],
[ 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8],
[ 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13],
[ 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9],
];

/// Message-word permutation schedule, with round `r` using row `r mod 10`.
pub(crate) static SIGMA: [[usize; 16]; 16] = const_array!([0; 16]; 16; |r| SIGMA_ROWS[r % 10]);

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn sigma_rows_10_15_repeat_0_5() {
for r in 0..6 {
assert_eq!(SIGMA[r], SIGMA[10 + r]);
}
}

#[test]
fn sigma_is_permutation() {
for row in &SIGMA {
Expand Down
113 changes: 46 additions & 67 deletions pkgs/pow/src/consts/cubehash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,65 +6,48 @@

//! CubeHash-16/32-512 constants.

use crate::util::const_array;

/// Block size in bytes.
pub(crate) const BLOCK: usize = 32;

// Permutation tables for the fused round pair
//
// The 32 x u32 state is conceptually a 5-D binary-indexed array x\[d,i,j,k,l\]
// with flat index `16d + 8i + 4j + 2k + l`.
//
// Each round performs: add into upper half, rotate, swap, XOR, twice with
// different rotation amounts (7, 11) and swap axes.
//
// Each phase of add-rotate does:
// upper[ADD_DST[n]] += lower[ADD_SRC[n]];
// lower[ADD_SRC[n]] = rotl(lower[ADD_SRC[n]], rot);
// The 32-word state is a binary-indexed array `x[d, i, j, k, l]` with flat
// index `16d + 8i + 4j + 2k + l`. A round adds the lower half into the upper
// half, rotates, swaps an axis and xors, twice over with rotations 7 and 11.
//
// Each phase of XOR does:
// lower[XOR_DST[n]] ^= upper[XOR_SRC[n]];
//
// Phase 1 (both rounds):
// straight -- dst[n] = src[n] = n.
//
// Phase 2 add:
// incorporates step-3 (i-swap) and step-5 (j-swap).
//
static ADD2_SRC: [usize; 16] = [8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7];
#[rustfmt::skip]
static ADD2_DST: [usize; 16] = [ 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13];

/// Phase-2 XOR: incorporates step-8 (k-swap) and step-10 (l-swap).
#[rustfmt::skip]
static XOR2_DST: [usize; 16] = [12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3];
#[rustfmt::skip]
static XOR2_SRC: [usize; 16] = [ 2, 3, 0, 1, 6, 7, 4, 5, 10, 11, 8, 9, 14, 15, 12, 13];

/// Odd-round phase-1 add: accumulated permutation from even round's deferred swaps.
#[rustfmt::skip]
static ODD_ADD1_SRC: [usize; 16] = [12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3];
#[rustfmt::skip]
static ODD_ADD1_DST: [usize; 16] = [ 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12];

/// Odd-round phase-1 XOR: deferred-swap accumulation.
#[rustfmt::skip]
static ODD_XOR1_DST: [usize; 16] = [ 4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11];
#[rustfmt::skip]
static ODD_XOR1_SRC: [usize; 16] = [ 3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12];

/// Odd-round phase-2 add: fully accumulated permutation (cancels back to identity after XOR).
#[rustfmt::skip]
static ODD_ADD2_SRC: [usize; 16] = [ 4, 5, 6, 7, 0, 1, 2, 3, 12, 13, 14, 15, 8, 9, 10, 11];
#[rustfmt::skip]
static ODD_ADD2_DST: [usize; 16] = [ 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14];

/// Odd-round phase-2 XOR: identity (all swaps cancelled).
#[rustfmt::skip]
static ODD_XOR2_DST: [usize; 16] = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
#[rustfmt::skip]
static ODD_XOR2_SRC: [usize; 16] = [ 1, 0, 3, 2, 5, 4, 7, 6, 9, 8, 11, 10, 13, 12, 15, 14];

/// Add-and-rotate: `upper[dst[n]] += lower[src[n]]; lower[src[n]] <<<= rot`.
// The swaps flip i then j in the lower half and k then l in the upper half.
// Each table flips the indices of the swaps in effect for its half.

/// Phase 2 add of the even round, after the i and k swaps.
static ADD2_SRC: [usize; 16] = xor_mask(8);
static ADD2_DST: [usize; 16] = xor_mask(2);

/// Phase 2 xor of the even round, after the j swap joins i in the lower half.
static XOR2_DST: [usize; 16] = xor_mask(12);
static XOR2_SRC: [usize; 16] = xor_mask(2);

/// Phase 1 add of the odd round, after the l swap joins k in the upper half.
static ODD_ADD1_SRC: [usize; 16] = xor_mask(12);
static ODD_ADD1_DST: [usize; 16] = xor_mask(3);

/// Phase 1 xor of the odd round, after a second i swap cancels the first.
static ODD_XOR1_DST: [usize; 16] = xor_mask(4);
static ODD_XOR1_SRC: [usize; 16] = xor_mask(3);

/// Phase 2 add of the odd round, after a second k swap cancels the first.
static ODD_ADD2_SRC: [usize; 16] = xor_mask(4);
static ODD_ADD2_DST: [usize; 16] = xor_mask(1);

/// Upper source of the odd round's phase 2 xor, after a second j swap clears
/// the lower half. The final l swap then clears the upper half.
static ODD_XOR2_SRC: [usize; 16] = xor_mask(1);

/// Index permutation `n -> n ^ mask`, flipping the coordinates set in `mask`.
const fn xor_mask(mask: usize) -> [usize; 16] {
const_array!(0; 16; |n| n ^ mask)
}

/// Runs `upper[dst[n]] += lower[src[n]]; lower[src[n]] <<<= rot` for every `n`.
const fn add_rotate(s: &mut [u32; 32], rot: u32, src: &[usize; 16], dst: &[usize; 16]) {
let mut n = 0;
while n < 16 {
Expand All @@ -74,7 +57,7 @@ const fn add_rotate(s: &mut [u32; 32], rot: u32, src: &[usize; 16], dst: &[usize
}
}

/// XOR: `lower[dst[n]] ^= upper[src[n]]`.
/// Runs `lower[dst[n]] ^= upper[src[n]]` for every `n`.
const fn xor_phase(s: &mut [u32; 32], dst: &[usize; 16], src: &[usize; 16]) {
let mut n = 0;
while n < 16 {
Expand All @@ -83,28 +66,24 @@ const fn xor_phase(s: &mut [u32; 32], dst: &[usize; 16], src: &[usize; 16]) {
}
}

/// Identity permutation for phase-1 of even rounds.
#[rustfmt::skip]
static IDENTITY: [usize; 16] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
/// Identity permutation, for a half with no swap in effect.
static IDENTITY: [usize; 16] = xor_mask(0);

/// Applies one pair of CubeHash rounds (even + odd) in place.
///
/// The even round defers its 4 swap steps (i, j, k, l coordinate flips) into
/// the index permutations of subsequent add/XOR operations. The odd round
/// compensates, returning the state to canonical layout. Together they advance
/// the state by exactly 2 rounds.
/// No word moves for an axis swap. Each swap instead flips the indices of
/// every later step, and as each swap is its own inverse, the odd round's
/// swaps cancel those of the even round.
pub(super) const fn round_pair(s: &mut [u32; 32]) {
// Even round
add_rotate(s, 7, &IDENTITY, &IDENTITY);
xor_phase(s, &ADD2_SRC, &IDENTITY); // step-3 swap folded into XOR destinations
xor_phase(s, &ADD2_SRC, &IDENTITY);
add_rotate(s, 11, &ADD2_SRC, &ADD2_DST);
xor_phase(s, &XOR2_DST, &XOR2_SRC);

// Odd round (accumulated permutation from even round's deferred swaps)
add_rotate(s, 7, &ODD_ADD1_SRC, &ODD_ADD1_DST);
xor_phase(s, &ODD_XOR1_DST, &ODD_XOR1_SRC);
add_rotate(s, 11, &ODD_ADD2_SRC, &ODD_ADD2_DST);
xor_phase(s, &ODD_XOR2_DST, &ODD_XOR2_SRC);
xor_phase(s, &IDENTITY, &ODD_XOR2_SRC);
}

/// CubeHash-16/32-512 IV, const-derived from parameters.
Expand Down
Loading
Loading