diff --git a/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx b/docs/docs/noir/standard_library/cryptographic_primitives/hashes.mdx
index 7329880c7a7..efa52b2c3f2 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 26a9fa6c2c0..ef1cb0889d7 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 8ca6808568d..d856043fcfa 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 fd5340e2384..d4240ded8b3 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);
}