From e4aaeae038c73e6f455e2b49da364e0b023caac1 Mon Sep 17 00:00:00 2001 From: oleh Date: Wed, 23 Oct 2024 04:51:11 +0200 Subject: [PATCH] feat: add pack_bytes --- README.md | 13 ++++++++++++- src/array.nr | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a08b697..b07cf5c 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ Put this into your Nargo.toml. If you are using Noir: ```toml -nodash = { git = "https://github.com/olehmisar/nodash/", tag = "v0.35.3" } +nodash = { git = "https://github.com/olehmisar/nodash/", tag = "v0.35.4" } ``` The version of nodash matches the version of Noir. The patch version may be different if a bugfix or a new feature is added for the same version of Noir. E.g., nodash@v0.35.0 and nodash@v0.35.1 are compatible with noir@v0.35.0. @@ -137,3 +137,14 @@ use nodash::ArrayExtensions; assert([1, 2, 3].pad_end::<5>(0) == [1, 2, 3, 0, 0]); ``` + +### `pack_bytes` + +Packs `[u8; N]` into `[Field; N / 31 + 1]`. Useful, if you need to get a hash over bytes. I.e., `pedersen_hash(pack_bytes(bytes))` will be MUCH cheaper than `pedersen_hash(bytes)`. + +```rs +use nodash::pack_bytes; + +let bytes: [u8; 32] = [0; 32]; +let packed = pack_bytes(bytes); +``` diff --git a/src/array.nr b/src/array.nr index 215325c..5550145 100644 --- a/src/array.nr +++ b/src/array.nr @@ -39,6 +39,29 @@ impl crate::ArrayExtensions for [T; N] { } } +// TODO: write tests +pub fn pack_bytes(bytes: [u8; N]) -> [Field; N / 31 + 1] { + let bytes_padded = bytes.pad_end::<(N / 31 + 1) * 31>(N / 31 + 1) * 31>( 0); + let mut res = [0 as Field; N / 31 + 1]; + for i in 0..N / 31 + 1 { + let chunk = bytes_padded.slice::<31>(i * 31, i * 31 + 31); + res[i] = field_from_bytes(chunk); + } + res +} + +// copied from https://github.com/AztecProtocol/aztec-packages/blob/a2ed567ad42b237088c110ce12ce8212d5099da2/noir-projects/noir-protocol-circuits/crates/types/src/utils/field.nr#L4 +fn field_from_bytes(bytes: [u8; N]) -> Field { + assert(bytes.len() < 32, "field_from_bytes: N must be less than 32"); + let mut as_field = 0; + let mut offset = 1; + for i in 0..N { + as_field += (bytes[i] as Field) * offset; + offset *= 256; + } + as_field +} + mod tests { #[test] fn test_slice() {