From ff1577cc8b8f1366258611a7942101802400974a Mon Sep 17 00:00:00 2001 From: Colin Nielsen <33375223+colinnielsen@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:32:24 -0500 Subject: [PATCH 1/3] feat: upgrade to >v30 and remove unconstrained variants --- Nargo.toml | 2 +- src/lib.nr | 162 +++++++++-------------------------------------------- 2 files changed, 26 insertions(+), 138 deletions(-) diff --git a/Nargo.toml b/Nargo.toml index 70d0d5f..2fb8703 100644 --- a/Nargo.toml +++ b/Nargo.toml @@ -1,7 +1,7 @@ [package] name = "noir_array_helpers" authors = ["@colinnielsen"] -compiler_version = ">=0.19.0" +compiler_version = ">=0.30.0" notes = "AMDG" type = "lib" diff --git a/src/lib.nr b/src/lib.nr index e03b60a..02f3f27 100644 --- a/src/lib.nr +++ b/src/lib.nr @@ -1,49 +1,19 @@ -use dep::std; - -fn u8_32s_to_u64_16( - arr_a: [u8; 32], - arr_b: [u8; 32], -) -> [u64; 16] { +pub fn u8_32s_to_u64_16(arr_a: [u8; 32], arr_b: [u8; 32]) -> [u64; 16] { let mut combined_u64: [u64; 16] = [0; 16]; - - for i in 0..4 { - let mut value: u64 = 0; - for j in 0..8 { - value |= (arr_a[i*8+j] as u64) << ((56 - j*8) as u64); - } - combined_u64[i] = value; - } - for i in 4..8 { - let mut value: u64 = 0; - for j in 0..8 { - value |= (arr_b[(i-4)*8+j] as u64) << ((56 - j*8) as u64); - } - combined_u64[i] = value; - } - - combined_u64 -} -unconstrained -fn u8_32s_to_u64_16_unconstrained( - arr_a: [u8; 32], - arr_b: [u8; 32], -) -> [u64; 16] { - let mut combined_u64: [u64; 16] = [0; 16]; - for i in 0..4 { let mut value: u64 = 0; for j in 0..8 { - value |= (arr_a[i*8+j] as u64) << ((56 - j*8) as u64); + value |= (arr_a[i * 8 + j] as u64) << ((56 - j * 8) as u8); } - combined_u64[i] = value; + combined_u64[i] = value; } for i in 4..8 { let mut value: u64 = 0; for j in 0..8 { - value |= (arr_b[(i-4)*8+j] as u64) << ((56 - j*8) as u64); + value |= (arr_b[(i - 4) * 8 + j] as u64) << ((56 - j * 8) as u8); } - combined_u64[i] = value; + combined_u64[i] = value; } combined_u64 @@ -52,10 +22,12 @@ fn u8_32s_to_u64_16_unconstrained( #[test] fn test_u8_32s_to_u64_16() { let arr_a: [u8; 32] = [ - 131,24,83,91,84,16,93,74,122,174,96,192,143,196,95,150,135,24,27,79,223,198,37,189,26,117,63,167,57,127,237,117 + 131, 24, 83, 91, 84, 16, 93, 74, 122, 174, 96, 192, 143, 196, 95, 150, 135, 24, 27, 79, 223, + 198, 37, 189, 26, 117, 63, 167, 57, 127, 237, 117, ]; let arr_b: [u8; 32] = [ - 53,71,241,28,168,105,102,70,242,243,172,176,142,49,1,106,250,194,62,99,12,93,17,245,159,97,254,245,123,13,42,165 + 53, 71, 241, 28, 168, 105, 102, 70, 242, 243, 172, 176, 142, 49, 1, 106, 250, 194, 62, 99, + 12, 93, 17, 245, 159, 97, 254, 245, 123, 13, 42, 165, ]; let out = u8_32s_to_u64_16(arr_a, arr_b); @@ -78,27 +50,7 @@ fn test_u8_32s_to_u64_16() { // the above output is the hex "0x8318535b54105d4a7aae60c08fc45f9687181b4fdfc625bd1a753fa7397fed753547f11ca8696646f2f3acb08e31016afac23e630c5d11f59f61fef57b0d2aa5" } -fn u8_32_to_u8_64( - arr_a: [u8; 32], - arr_b: [u8; 32], -) -> [u8; 64] { - let mut combined: [u8; 64] = [0; 64]; - - for i in 0..32 { - combined[i] = arr_a[i]; - } - for i in 0..32 { - combined[i + 32] = arr_b[i]; - } - - combined -} - -unconstrained -fn u8_32_to_u8_64_unconstrained( - arr_a: [u8; 32], - arr_b: [u8; 32], -) -> [u8; 64] { +pub fn u8_32_to_u8_64(arr_a: [u8; 32], arr_b: [u8; 32]) -> [u8; 64] { let mut combined: [u8; 64] = [0; 64]; for i in 0..32 { @@ -111,34 +63,13 @@ fn u8_32_to_u8_64_unconstrained( combined } - -fn u64_4_to_u8_32( - array: [u64; 4] -) -> [u8; 32] { +pub fn u64_4_to_u8_32(array: [u64; 4]) -> [u8; 32] { let mut output: [u8; 32] = [0; 32]; let mut output_index = 0; for num_idx in 0..4 { for bit_pos in 0..8 { - let shift_amount: u64 = 56 - (bit_pos * 8) as u64; - output[output_index] = ((array[num_idx] >> shift_amount) & 255) as u8; - output_index += 1; - } - } - - output -} - -unconstrained -fn u64_4_to_u8_32_unconstrained( - array: [u64; 4] -) -> [u8; 32] { - let mut output: [u8; 32] = [0; 32]; - let mut output_index = 0; - - for num_idx in 0..4 { - for bit_pos in 0..8 { - let shift_amount: u64 = 56 - (bit_pos * 8) as u64; + let shift_amount = 56 - (bit_pos * 8); output[output_index] = ((array[num_idx] >> shift_amount) & 255) as u8; output_index += 1; } @@ -149,13 +80,9 @@ fn u64_4_to_u8_32_unconstrained( #[test] fn test_u64_4_to_u8_32() { - let hash: [u64; 4] = [ - 999647796417551690, - 8840109498736861078, - 9734560624431998397, - 1906500004718046581 - ]; - + let hash: [u64; 4] = + [999647796417551690, 8840109498736861078, 9734560624431998397, 1906500004718046581]; + let arr_out = u64_4_to_u8_32(hash); assert(arr_out[0] == 13); @@ -194,9 +121,7 @@ fn test_u64_4_to_u8_32() { /// @dev this method is used to convert a u8 array to a u160 (which is not supported by Noir, so it's represented as a Field) /// @dev will throw on Field overflow -fn u8_to_u160( - array: [u8] -) -> Field { +pub fn u8_to_u160(array: [u8]) -> Field { let mut addr: Field = 0; for i in 0..20 { @@ -207,30 +132,7 @@ fn u8_to_u160( addr } -unconstrained -fn u8_to_u160_unconstrained( - array: [u8] -) -> Field { - let mut addr: Field = 0; - - for i in 0..20 { - // only take the last 20 bytes of the hash - addr = (addr * 256) + (array[i] as Field); - } - - addr -} - -fn u8_to_eth_address( - array: [u8] -) -> Field { - u8_to_u160(array) -} - -unconstrained -fn u8_to_eth_address_unconstrained( - array: [u8] -) -> Field { +pub fn u8_to_eth_address(array: [u8]) -> Field { u8_to_u160(array) } @@ -238,7 +140,8 @@ fn u8_to_eth_address_unconstrained( fn test_u8_32_to_u160() { // keccak hash of hardhat 0 address pub key (0xc1ffd3cfee2d9e5cd67643f8f39fd6e51aad88f6f4ce6ab8827279cfffb92266) as u8 array let hashed_pub_key = [ - 193,255,211,207,238,45,158,92,214,118,67,248,243,159,214,229,26,173,136,246,244,206,106,184,130,114,121,207,255,185,34,102 + 193, 255, 211, 207, 238, 45, 158, 92, 214, 118, 67, 248, 243, 159, 214, 229, 26, 173, 136, + 246, 244, 206, 106, 184, 130, 114, 121, 207, 255, 185, 34, 102, ]; let mut right_20_bytes: [u8] = [0; 20]; @@ -253,31 +156,14 @@ fn test_u8_32_to_u160() { assert(addr == 0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266); // hardhat address 0 } -fn split_u8_64( - arr: [u8; 64] -) -> ([u8; 32], [u8; 32]) { - let mut arr_a: [u8; 32] = [0; 32]; - let mut arr_b: [u8; 32] = [0; 32]; - - for i in 0..32 { - arr_a[i] = arr[i]; - arr_b[i] = arr[i + 32]; - }; - - (arr_a, arr_b) -} - -unconstrained -fn split_u8_64_unconstrained( - arr: [u8; 64] -) -> ([u8; 32], [u8; 32]) { +pub fn split_u8_64(arr: [u8; 64]) -> ([u8; 32], [u8; 32]) { let mut arr_a: [u8; 32] = [0; 32]; let mut arr_b: [u8; 32] = [0; 32]; for i in 0..32 { arr_a[i] = arr[i]; arr_b[i] = arr[i + 32]; - }; + } (arr_a, arr_b) } @@ -285,8 +171,10 @@ fn split_u8_64_unconstrained( #[test] fn test_split_u8_64() { let u8_64 = [ - 193,255,211,207,238,45,158,92,214,118,67,248,243,159,214,229,26,173,136,246,244,206,106,184,130,114,121,207,255,185,34,102, - 193,255,211,207,238,45,158,92,214,118,67,248,243,159,214,229,26,173,136,246,244,206,106,184,130,114,121,207,255,185,34,102 + 193, 255, 211, 207, 238, 45, 158, 92, 214, 118, 67, 248, 243, 159, 214, 229, 26, 173, 136, + 246, 244, 206, 106, 184, 130, 114, 121, 207, 255, 185, 34, 102, 193, 255, 211, 207, 238, 45, + 158, 92, 214, 118, 67, 248, 243, 159, 214, 229, 26, 173, 136, 246, 244, 206, 106, 184, 130, + 114, 121, 207, 255, 185, 34, 102, ]; let (arr_a, arr_b) = split_u8_64(u8_64); From d6c3b46e76e383333b0610cbdfca05488ae88e07 Mon Sep 17 00:00:00 2001 From: Colin Nielsen <33375223+colinnielsen@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:35:53 -0500 Subject: [PATCH 2/3] ci: update noir CI version --- .github/workflows/noir.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/noir.yml b/.github/workflows/noir.yml index 253c1b6..8fb538a 100644 --- a/.github/workflows/noir.yml +++ b/.github/workflows/noir.yml @@ -19,7 +19,7 @@ jobs: - name: Install Nargo uses: noir-lang/noirup@v0.1.3 with: - toolchain: v0.19.0 + toolchain: v0.36.0 - name: Run nargo test run: | From 9787de8a37fe64bc8f1597f4013e0a827bb58c86 Mon Sep 17 00:00:00 2001 From: Colin Nielsen <33375223+colinnielsen@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:57:28 -0500 Subject: [PATCH 3/3] update readme --- README.md | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 9f4e621..ad5da92 100644 --- a/README.md +++ b/README.md @@ -4,13 +4,20 @@ **Noir Array Helpers** is a Noir function library to manipulate arrays. This library serves a kitchen sink for various array functions the Noir community finds useful. +## WARNING! + +| **It is not recommended to use versions of this library < `v0.30.0`** + +This library was related to a vulnerability in [ecrecover](https://github.com/colinnielsen/ecrecover-noir) found by @olehmisar. +Vulnerability details can be found [here](https://gist.github.com/olehmisar/4cfe6128eaac2bfbe1fa8eb46f0116d6). + ## Installation In your `Nargo.toml` file, add the following dependency: ```toml [dependencies] -array_helpers = { tag = "v0.19.0", git = "https://github.com/colinnielsen/noir-array-helpers" } +array_helpers = { tag = "v0.30.0", git = "https://github.com/colinnielsen/noir-array-helpers" } ``` then `use` it in your circuits: @@ -48,15 +55,12 @@ let eth_addr_u8: [u8;20] = [...]; Here are the methods available in the library: -**NOTE**: this lib ships with constrained and unconstrained versions of each function, and are post-fixed with `_unconstrained`. (unconstrained is not currently implemented as of Noir v0.6.0, but will allow you to optimize your gate count if you do not need to constrain the computation of the function) - ### `split_u8_64` Splits an array of `u8` values, with a length of 64, into two arrays of `u8` values, each with a length of 32. ```rust fn split_u8_64(arr: [u8; 64]) -> ([u8; 32], [u8; 32]) -fn split_u8_64_unconstrained(arr: [u8; 64]) -> ([u8; 32], [u8; 32]) ``` ### `u8_32_to_u8_64` @@ -65,7 +69,6 @@ Combines two arrays of `u8` values, each of length 32, into a single array of `u ```rust fn u8_32_to_u8_64(arr_a: [u8; 32], arr_b: [u8; 32]) -> [u8; 64] -fn u8_32_to_u8_64_unconstrained(arr_a: [u8; 32], arr_b: [u8; 32]) -> [u8; 64] ``` ### `u8_to_u160` @@ -76,10 +79,8 @@ Converts an array of `u8` values to a `Field` value, representing a u160 value. ```rust fn u8_to_u160(array: [u8]) -> Field -fn u8_to_u160_unconstrained(array: [u8]) -> Field fn u8_to_eth_address(array: [u8]) -> Field -fn u8_to_eth_address_unconstrained(array: [u8]) -> Field ``` ### `u8_32s_to_u64_16` @@ -88,7 +89,6 @@ Converts two arrays of `u8` values, each of length 32, to a single array of `u64 ```rust fn u8_32s_to_u64_16(arr_a: [u8; 32], arr_b: [u8; 32]) -> [u64; 16] -fn u8_32s_to_u64_16_unconstrained(arr_a: [u8; 32], arr_b: [u8; 32]) -> [u64; 16] ``` ### `u64_4_to_u8_32` @@ -97,7 +97,6 @@ Converts an array of `u64` values, with a length of 4, to an array of `u8` value ```rust fn u64_4_to_u8_32(array: [u64; 4]) -> [u8; 32] -fn u64_4_to_u8_32_unconstrained(array: [u64; 4]) -> [u8; 32] ``` ## License