Skip to content

Commit

Permalink
Merge pull request #12 from colinnielsen/colinnielsen/v30-upgrade
Browse files Browse the repository at this point in the history
feat: upgrade to >v30 and remove unconstrained variants
  • Loading branch information
colinnielsen authored Nov 27, 2024
2 parents a0d1f88 + 9787de8 commit 2f883de
Show file tree
Hide file tree
Showing 4 changed files with 35 additions and 148 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/noir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- name: Install Nargo
uses: noir-lang/[email protected]
with:
toolchain: v0.19.0
toolchain: v0.36.0

- name: Run nargo test
run: |
Expand Down
2 changes: 1 addition & 1 deletion Nargo.toml
Original file line number Diff line number Diff line change
@@ -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"

Expand Down
17 changes: 8 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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`
Expand All @@ -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`
Expand All @@ -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`
Expand All @@ -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`
Expand All @@ -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
Expand Down
162 changes: 25 additions & 137 deletions src/lib.nr
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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);

Expand All @@ -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 {
Expand All @@ -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;
}
Expand All @@ -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);
Expand Down Expand Up @@ -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 {
Expand All @@ -207,38 +132,16 @@ 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)
}

#[test]
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];
Expand All @@ -253,40 +156,25 @@ 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)
}

#[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);
Expand Down

0 comments on commit 2f883de

Please sign in to comment.