Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: saleemrashid/sha2-const
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: main
Choose a base ref
...
head repository: toucanlabs/sha2
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: main
Choose a head ref
Able to merge. These branches can be automatically merged.
  • 3 commits
  • 4 files changed
  • 2 contributors

Commits on Oct 17, 2023

  1. fix: stable version

    9bany committed Oct 17, 2023
    Copy the full SHA
    1d5a66a View commit details

Commits on Oct 19, 2023

  1. Merge pull request #1 from thebox-labs/fix-stable

    fix: stable version
    9bany authored Oct 19, 2023

    Verified

    This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
    Copy the full SHA
    1bde06f View commit details
  2. fix docs

    9bany committed Oct 19, 2023
    Copy the full SHA
    926fca4 View commit details
Showing with 63 additions and 37 deletions.
  1. +1 −2 README.md
  2. +2 −3 src/lib.rs
  3. +39 −22 src/sha.rs
  4. +21 −10 src/util.rs
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
# sha2-const

[![Build status](https://github.com/saleemrashid/sha2-const/workflows/CI/badge.svg)](https://github.com/saleemrashid/sha2-const/actions)
[![Crate](https://meritbadge.herokuapp.com/sha2-const)](https://crates.io/crates/sha2-const)
[![Build status](https://github.com/thebox-labs/sha2/workflows/CI/badge.svg)](https://github.com/thebox-labs/sha2/actions)
[![Documentation](https://docs.rs/sha2-const/badge.svg)](https://docs.rs/sha2-const)

`const fn` implementation of the SHA-2 family of hash functions.
5 changes: 2 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -41,7 +41,6 @@
//! "6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000"
//! );
//! ```
#![feature(const_mut_refs)]
#![no_std]

mod constants;
@@ -80,7 +79,7 @@ macro_rules! sha {
/// Add input data to the hash context.
#[must_use]
pub const fn update(mut self, input: &[u8]) -> Self {
self.inner.update(&input);
self.inner = self.inner.update(&input);
self
}

@@ -89,7 +88,7 @@ macro_rules! sha {
pub const fn finalize(self) -> [u8; Self::DIGEST_SIZE] {
let digest = self.inner.finalize();
let mut truncated = [0; Self::DIGEST_SIZE];
memcpy(&mut truncated, 0, &digest, 0, Self::DIGEST_SIZE);
truncated = memcpy(truncated, 0, &digest, 0, Self::DIGEST_SIZE);
truncated
}
}
61 changes: 39 additions & 22 deletions src/sha.rs
Original file line number Diff line number Diff line change
@@ -45,64 +45,79 @@ macro_rules! sha {
}

/// Add input data to the hash context.
pub(crate) const fn update(&mut self, input: &[u8]) {
let offset = self.offset;
pub(crate) const fn update(self, input: &[u8]) -> Self {
let Self {
mut state,
mut buffer,
mut offset,
mut length,
} = self;
let needed = Self::BLOCK_SIZE - offset;

if needed > input.len() {
memcpy(&mut self.buffer, offset, input, 0, input.len());
self.offset += input.len();
buffer = memcpy(buffer, offset, input, 0, input.len());
offset += input.len();
} else {
memcpy(&mut self.buffer, offset, input, 0, needed);
Self::compress(&mut self.state, &self.buffer, 0);
buffer = memcpy(buffer, offset, input, 0, needed);
state = Self::compress(state, &buffer, 0);

let mut i = needed;
loop {
let remain = input.len() - i;
if remain < Self::BLOCK_SIZE {
memcpy(&mut self.buffer, 0, input, i, remain);
self.offset = remain;
buffer = memcpy(buffer, 0, input, i, remain);
offset = remain;
break;
} else {
Self::compress(&mut self.state, input, i);
state = Self::compress(state, input, i);
i += Self::BLOCK_SIZE;
}
}
}

self.length += (input.len() as $length) * 8;
length += (input.len() as $length) * 8;
Self {
state,
buffer,
offset,
length,
}
}

pub(crate) const fn finalize(mut self) -> [u8; Self::DIGEST_SIZE] {
let mut offset = self.offset;
self.buffer[offset] = 0x80;
pub(crate) const fn finalize(self) -> [u8; Self::DIGEST_SIZE] {
let Self {
mut state,
mut buffer,
mut offset,
length,
} = self;
buffer[offset] = 0x80;
offset += 1;

if offset > Self::LENGTH_OFFSET {
memset(&mut self.buffer, offset, 0, Self::BLOCK_SIZE - offset);
Self::compress(&mut self.state, &self.buffer, 0);
buffer = memset(buffer, offset, 0, Self::BLOCK_SIZE - offset);
state = Self::compress(state, &buffer, 0);
offset = 0;
}

memset(&mut self.buffer, offset, 0, Self::LENGTH_OFFSET - offset);
$store_length(&mut self.buffer, Self::LENGTH_OFFSET, self.length);
Self::compress(&mut self.state, &self.buffer, 0);
buffer = memset(buffer, offset, 0, Self::LENGTH_OFFSET - offset);
buffer = $store_length(buffer, Self::LENGTH_OFFSET, length);
state = Self::compress(state, &buffer, 0);

let mut digest = [0; Self::DIGEST_SIZE];
let mut i = 0;
while i < self.state.len() {
$store_word(&mut digest, i * Self::WORD_SIZE, self.state[i]);
while i < state.len() {
digest = $store_word(digest, i * Self::WORD_SIZE, state[i]);
i += 1
}

digest
}

/// SHA compression function.
///
/// This function takes an `offset` because subslices are not supported in
/// `const fn`.
const fn compress(state: &mut [$word; 8], buffer: &[u8], offset: usize) {
const fn compress(mut state: [$word; 8], buffer: &[u8], offset: usize) -> [$word; 8] {
#[inline(always)]
const fn ch(x: $word, y: $word, z: $word) -> $word {
(x & y) ^ ((!x) & z)
@@ -181,6 +196,8 @@ macro_rules! sha {
state[5] = state[5].wrapping_add(f);
state[6] = state[6].wrapping_add(g);
state[7] = state[7].wrapping_add(h);

state
}
}
};
31 changes: 21 additions & 10 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -4,30 +4,37 @@
/// The source and destination must _not_ overlap. This function exists because
/// subslices are not supported in `const fn`.
#[inline(always)]
pub(crate) const fn memcpy(
dest: &mut [u8],
pub(crate) const fn memcpy<const N: usize>(
mut dest: [u8; N],
dest_offset: usize,
src: &[u8],
src_offset: usize,
n: usize,
) {
) -> [u8; N] {
let mut i = 0;
while i < n {
dest[dest_offset + i] = src[src_offset + i];
i += 1;
}
dest
}

/// Sets `n` bytes in `dest` (starting at `dest_offset`) to `val`.
///
/// This function exists because subslices are not supported in `const fn`.
#[inline(always)]
pub(crate) const fn memset(dest: &mut [u8], offset: usize, val: u8, n: usize) {
pub(crate) const fn memset<const N: usize>(
mut dest: [u8; N],
offset: usize,
val: u8,
n: usize,
) -> [u8; N] {
let mut i = 0;
while i < n {
dest[offset + i] = val;
i += 1;
}
dest
}

/// Loads an unsigned 32-bit big endian integer from `src` (starting at
@@ -67,27 +74,31 @@ pub(crate) const fn load_u64_be(src: &[u8], offset: usize) -> u64 {
///
/// This function exists because subslices are not supported in `const fn`.
#[inline(always)]
pub(crate) const fn store_u32_be(dest: &mut [u8], offset: usize, n: u32) {
pub(crate) const fn store_u32_be<const N: usize>(dest: [u8; N], offset: usize, n: u32) -> [u8; N] {
let bytes = u32::to_be_bytes(n);
memcpy(dest, offset, &bytes, 0, bytes.len());
memcpy(dest, offset, &bytes, 0, bytes.len())
}

/// Stores an unsigned 64-bit big endian integer into `dest` (starting at
/// `offset`).
///
/// This function exists because subslices are not supported in `const fn`.
#[inline(always)]
pub(crate) const fn store_u64_be(dest: &mut [u8], offset: usize, n: u64) {
pub(crate) const fn store_u64_be<const N: usize>(dest: [u8; N], offset: usize, n: u64) -> [u8; N] {
let bytes = u64::to_be_bytes(n);
memcpy(dest, offset, &bytes, 0, bytes.len());
memcpy(dest, offset, &bytes, 0, bytes.len())
}

/// Stores an unsigned 128-bit big endian integer into `dest` (starting at
/// `offset`).
///
/// This function exists because subslices are not supported in `const fn`.
#[inline(always)]
pub(crate) const fn store_u128_be(dest: &mut [u8], offset: usize, n: u128) {
pub(crate) const fn store_u128_be<const N: usize>(
dest: [u8; N],
offset: usize,
n: u128,
) -> [u8; N] {
let bytes = u128::to_be_bytes(n);
memcpy(dest, offset, &bytes, 0, bytes.len());
memcpy(dest, offset, &bytes, 0, bytes.len())
}