diff --git a/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx b/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx index 7329880c7a..efa52b2c3f 100644 --- a/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx +++ b/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx @@ -13,18 +13,21 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx'; ## sha256 Given an array of bytes, returns the resulting sha256 hash. +Specify a message_size to hash only the first `message_size` bytes of the input. #include_code sha256 noir_stdlib/src/hash.nr rust example: +#include_code sha256_var test_programs/execution_success/sha256/src/main.nr rust ```rust fn main() { let x = [163, 117, 178, 149]; // some random bytes - let hash = std::hash::sha256(x); + let hash = std::sha256::sha256_var(x, 4); } ``` + ## blake2s diff --git a/noir_stdlib/src/hash.nr b/noir_stdlib/src/hash.nr index 26a9fa6c2c..ef1cb0889d 100644 --- a/noir_stdlib/src/hash.nr +++ b/noir_stdlib/src/hash.nr @@ -4,6 +4,7 @@ mod poseidon2; use crate::default::Default; use crate::uint128::U128; +use crate::sha256::{digest, sha256_var}; #[foreign(sha256)] // docs:start:sha256 diff --git a/noir_stdlib/src/sha256.nr b/noir_stdlib/src/sha256.nr index 8ca6808568..d856043fcf 100644 --- a/noir_stdlib/src/sha256.nr +++ b/noir_stdlib/src/sha256.nr @@ -17,19 +17,42 @@ fn msg_u8_to_u32(msg: [u8; 64]) -> [u32; 16] { } // SHA-256 hash function pub fn digest(msg: [u8; N]) -> [u8; 32] { + sha256_var(msg, N) +} + +fn hash_final_block(msg_block: [u8; 64], mut state: [u32; 8]) -> [u8; 32] { + let mut out_h: [u8; 32] = [0; 32]; // Digest as sequence of bytes + + // Hash final padded block + state = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), state); + + // Return final hash as byte array + for j in 0..8 { + let h_bytes = (state[7 - j] as Field).to_le_bytes(4); + for k in 0..4 { + out_h[31 - 4*j - k] = h_bytes[k]; + } + } + + out_h +} + +// Variable size SHA-256 hash +pub fn sha256_var(msg: [u8; N], message_size: u64) -> [u8; 32] { let mut msg_block: [u8; 64] = [0; 64]; let mut h: [u32; 8] = [1779033703, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635, 1541459225]; // Intermediate hash, starting with the canonical initial value - let mut out_h: [u8; 32] = [0; 32]; // Digest as sequence of bytes let mut i: u64 = 0; // Message byte pointer for k in 0..N { - // Populate msg_block - msg_block[i] = msg[k]; - i = i + 1; - if i == 64 { - // Enough to hash block - h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); + if k < message_size { + // Populate msg_block + msg_block[i] = msg[k]; + i = i + 1; + if i == 64 { + // Enough to hash block + h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); - i = 0; + i = 0; + } } } // Pad the rest such that we have a [u32; 2] block at the end representing the length @@ -53,7 +76,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { i = 0; } - let len = 8 * msg.len(); + let len = 8 * message_size; let len_bytes = (len as Field).to_le_bytes(8); for _i in 0..64 { // In any case, fill blocks up with zeros until the last 64 (i.e. until i = 56). @@ -67,16 +90,5 @@ pub fn digest(msg: [u8; N]) -> [u8; 32] { i += 8; } } - // Hash final padded block - h = crate::hash::sha256_compression(msg_u8_to_u32(msg_block), h); - - // Return final hash as byte array - for j in 0..8 { - let h_bytes = (h[7 - j] as Field).to_le_bytes(4); - for k in 0..4 { - out_h[31 - 4*j - k] = h_bytes[k]; - } - } - - out_h + hash_final_block(msg_block, h) } diff --git a/test_programs/execution_success/sha256/src/main.nr b/test_programs/execution_success/sha256/src/main.nr index fd5340e238..d4240ded8b 100644 --- a/test_programs/execution_success/sha256/src/main.nr +++ b/test_programs/execution_success/sha256/src/main.nr @@ -14,6 +14,8 @@ use dep::std; fn main(x: Field, result: [u8; 32]) { // We use the `as` keyword here to denote the fact that we want to take just the first byte from the x Field // The padding is taken care of by the program - let digest = std::hash::sha256([x as u8]); + // docs:start:sha256_var + let digest = std::hash::sha256_var([x as u8], 1); + // docs:end:sha256_var assert(digest == result); }