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
2 changes: 2 additions & 0 deletions src/lib.nr
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod sha256;
mod sha224;

pub use sha224::sha224_var;
pub use sha256::digest;
pub use sha256::sha256_var;
82 changes: 82 additions & 0 deletions src/sha224.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use crate::sha256::constants::HASH;

use crate::sha256::{__sha_var, finalize_sha256_blocks, partial_sha256_var_end, process_full_blocks};

use constants as sha224_constants;

pub(crate) mod constants;
mod tests;

// Variable size SHA-224 hash
pub fn sha224_var<let N: u32>(msg: [u8; N], message_size: u64) -> sha224_constants::HASH_SHA224 {
let message_size = message_size as u32;
assert(message_size <= N);

if std::runtime::is_unconstrained() {
// Safety: SHA224 is running as an unconstrained function.
unsafe {
__sha224_var(msg, message_size)
}
} else {
let (mut h, mut msg_block, mut msg_byte_ptr) =
process_full_blocks(msg, message_size, sha224_constants::INITIAL_STATE_SHA224);

let hash: HASH = finalize_sha256_blocks(msg, message_size, N, h, msg_block, msg_byte_ptr);
// Convert 32-byte hash to 28-byte hash for SHA-224
let mut hash_sha224: sha224_constants::HASH_SHA224 = [0; 28];
for i in 0..28 {
hash_sha224[i] = hash[i];
}
hash_sha224
}
}

// Variable size SHA-224 hash
unconstrained fn __sha224_var<let N: u32>(
msg: [u8; N],
message_size: u32,
) -> sha224_constants::HASH_SHA224 {
let hash = __sha_var(msg, message_size, sha224_constants::INITIAL_STATE_SHA224);
let mut hash_sha224: sha224_constants::HASH_SHA224 = [0; 28];
for i in 0..28 {
hash_sha224[i] = hash[i];
}
hash_sha224
}

/**
* Given some state of a partially computed sha256/sha224 hash and remaining preimage, complete the hash
* @notice used for traditional partial hashing
*
* @param N - the maximum length of the message to hash
* @param h - the intermediate hash state
* @param msg - the remaining preimage to hash
* @param message_size - the size of the current chunk
* @param real_message_size - the total size of the original preimage
* @return finalized sha24 hash
*/
pub fn partial_sha224_var_end<let N: u32>(
mut h: [u32; 8],
msg: [u8; N],
message_size: u32,
real_message_size: u32,
) -> sha224_constants::HASH_SHA224 {
let hash = partial_sha256_var_end(h, msg, message_size, real_message_size);
let mut hash_sha224: sha224_constants::HASH_SHA224 = [0; 28];
for i in 0..28 {
hash_sha224[i] = hash[i];
}
hash_sha224
}

mod equivalence_test {

#[test]
fn test_implementations_agree(msg: [u8; 100], message_size: u64) {
let message_size = message_size % 100;
// Safety: testing
let unconstrained_sha224 = unsafe { super::__sha224_var(msg, message_size as u32) };
let sha224 = super::sha224_var(msg, message_size);
assert_eq(sha224, unconstrained_sha224);
}
}
6 changes: 6 additions & 0 deletions src/sha224/constants.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
use crate::sha256::constants::STATE;
pub(crate) global INITIAL_STATE_SHA224: STATE =
[3238371032, 914150663, 812702999, 4144912697, 4290775857, 1750603025, 1694076839, 3204075428];

// The hash is 28 bytes.
pub(crate) type HASH_SHA224 = [u8; 28];
290 changes: 290 additions & 0 deletions src/sha224/tests.nr

Large diffs are not rendered by default.

44 changes: 26 additions & 18 deletions src/sha256.nr
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,29 @@ pub fn sha256_var<let N: u32>(msg: [u8; N], message_size: u64) -> HASH {
}
}

pub(crate) unconstrained fn __sha_var<let N: u32>(
msg: [u8; N],
message_size: u32,
initial_state: STATE,
) -> HASH {
let num_full_blocks = message_size / BLOCK_SIZE;
// Intermediate hash, starting with the canonical initial value
let mut h: STATE = initial_state;
// Pointer into msg_block on a 64 byte scale
for i in 0..num_full_blocks {
let (msg_block, _) = build_msg_block(msg, message_size, BLOCK_SIZE * i);
h = sha256_compression(msg_block, h);
}

// Handle setup of the final msg block.
// This case is only hit if the msg is less than the block size,
// or our message cannot be evenly split into blocks.

finalize_last_sha256_block(h, message_size, msg)
}

// Helper function to finalize the message block with padding and length
unconstrained fn finalize_last_sha256_block<let N: u32>(
pub(crate) unconstrained fn finalize_last_sha256_block<let N: u32>(
mut h: STATE,
message_size: u32,
msg: [u8; N],
Expand Down Expand Up @@ -82,23 +103,10 @@ unconstrained fn finalize_last_sha256_block<let N: u32>(

// Variable size SHA-256 hash
unconstrained fn __sha256_var<let N: u32>(msg: [u8; N], message_size: u32) -> HASH {
let num_full_blocks = message_size / BLOCK_SIZE;
// Intermediate hash, starting with the canonical initial value
let mut h: STATE = INITIAL_STATE;
// Pointer into msg_block on a 64 byte scale
for i in 0..num_full_blocks {
let (msg_block, _) = build_msg_block(msg, message_size, BLOCK_SIZE * i);
h = sha256_compression(msg_block, h);
}

// Handle setup of the final msg block.
// This case is only hit if the msg is less than the block size,
// or our message cannot be evenly split into blocks.

finalize_last_sha256_block(h, message_size, msg)
__sha_var(msg, message_size, INITIAL_STATE)
}

fn process_full_blocks<let N: u32>(
pub(crate) fn process_full_blocks<let N: u32>(
msg: [u8; N],
message_size: u32,
mut h: STATE,
Expand Down Expand Up @@ -133,7 +141,7 @@ fn process_full_blocks<let N: u32>(

// Take `BLOCK_SIZE` number of bytes from `msg` starting at `msg_start`.
// Returns the block and the length that has been copied rather than padded with zeros.
unconstrained fn build_msg_block<let N: u32>(
pub(crate) unconstrained fn build_msg_block<let N: u32>(
msg: [u8; N],
message_size: u32,
msg_start: u32,
Expand Down Expand Up @@ -487,7 +495,7 @@ fn hash_final_block(msg_block: MSG_BLOCK, mut state: STATE) -> HASH {
out_h
}

fn finalize_sha256_blocks<let N: u32>(
pub(crate) fn finalize_sha256_blocks<let N: u32>(
msg: [u8; N],
message_size: u32,
total_len: u32,
Expand Down
15 changes: 0 additions & 15 deletions src/sha256/constants.nr
Original file line number Diff line number Diff line change
Expand Up @@ -40,18 +40,3 @@ pub(crate) type STATE = [u32; 8];

pub(crate) global INITIAL_STATE: STATE =
[1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225];

pub(crate) mod test_inputs {
pub(crate) global DATA: [u8; 192] = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112,
113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130,
131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148,
149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166,
167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
185, 186, 187, 188, 189, 190, 191,
];
}
6 changes: 3 additions & 3 deletions src/sha256/tests.nr
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use super::{
partial_sha256_var_end, partial_sha256_var_interstitial, set_item_byte_then_zeros,
set_item_zeros, sha256, sha256_var,
};
use super::constants::{INITIAL_STATE, INT_BLOCK, test_inputs::DATA};
use super::constants::{INITIAL_STATE, INT_BLOCK};

#[export]
fn test_sha256_1(input: [u8; 1], len: u64) -> [u8; 32] {
Expand All @@ -26,7 +26,7 @@ fn test_sha256_512(input: [u8; 512], len: u64) -> [u8; 32] {
}

#[test]
fn empty_sha() {
fn empty_sha256() {
let input = [];
let result = [
0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14, 0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9,
Expand Down Expand Up @@ -353,7 +353,7 @@ fn fuzz_test_partial_hash(data: [u8; 192]) {
data1[i] = data[data0.len() + i];
}
let state = partial_sha256_var_interstitial(INITIAL_STATE, data0, 128);
let hash = partial_sha256_var_end(state, data1, data1.len(), DATA.len());
let hash = partial_sha256_var_end(state, data1, data1.len(), data.len());
let correct_hash = sha256_var(data, data.len() as u64);
assert_eq(hash, correct_hash);
}
Expand Down