Skip to content

Commit

Permalink
chore!: Add as_array and remove _slice variants of hash functions (
Browse files Browse the repository at this point in the history
…#4675)

# Description

## Problem\*

Resolves an issue raised in a slack thread:

```rs
let slice1 = &[1, 2, 3];
let slice2 = slice1.pop_back().0.push_back(3);

assert(slice1 == slice2); // fails
```

## Summary\*

Removes `_slice` functions from the stdlib and adds `as_array` method to
convert a slice to an array.

## Additional Context

Currently failing because the pedersen hasher uses the pedersen_slice
variant.

## Documentation\*

Check one:
- [ ] No documentation needed.
- [x] Documentation included in this PR.
- [ ] **[For Experimental Features]** Documentation to be submitted in a
separate PR.

# PR Checklist\*

- [x] I have tested the changes locally.
- [x] I have formatted the changes with [Prettier](https://prettier.io/)
and/or `cargo fmt` on default settings.
  • Loading branch information
jfecher committed Apr 18, 2024
1 parent d5028a6 commit 8e39706
Show file tree
Hide file tree
Showing 15 changed files with 99 additions and 225 deletions.
25 changes: 25 additions & 0 deletions docs/docs/noir/concepts/data_types/slices.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,28 @@ fn main() {
assert(slice.len() == 2);
}
```

### as_array

Converts this slice into an array.

Make sure to specify the size of the resulting array.
Panics if the resulting array length is different than the slice's length.

```rust
fn as_array<N>(self) -> [T; N]
```

Example:

```rust
fn main() {
let slice = &[5, 6];

// Always specify the length of the resulting array!
let array: [Field; 2] = slice.as_array();

assert(array[0] == slice[0]);
assert(array[1] == slice[1]);
}
```
5 changes: 3 additions & 2 deletions docs/docs/noir/standard_library/containers/hashmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ Example:

```rust
// Create a mapping from Fields to u32s with a maximum length of 12
// using a pedersen hash
let mut map: HashMap<Field, u32, 12, BuildHasherDefault<Pedersen>> = HashMap::default();
// using a poseidon2 hasher
use dep::std::hash::poseidon2::Poseidon2Hasher;
let mut map: HashMap<Field, u32, 12, BuildHasherDefault<Poseidon2Hasher>> = HashMap::default();

map.insert(1, 2);
map.insert(3, 4);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import BlackBoxInfo from '@site/src/components/Notes/_blackbox.mdx';
## sha256

Given an array of bytes, returns the resulting sha256 hash.
See sha256_slice for a version that works directly on slices.

#include_code sha256 noir_stdlib/src/hash.nr rust

Expand All @@ -28,18 +27,9 @@ fn main() {

<BlackBoxInfo />

## sha256_slice

A version of sha256 specialized to slices:

#include_code sha256_slice noir_stdlib/src/hash.nr rust

<BlackBoxInfo />

## blake2s

Given an array of bytes, returns an array with the Blake2 hash
See blake2s_slice for a version that works directly on slices.

#include_code blake2s noir_stdlib/src/hash.nr rust

Expand All @@ -54,18 +44,9 @@ fn main() {

<BlackBoxInfo />

## blake2s_slice

A version of blake2s specialized to slices:

#include_code blake2s_slice noir_stdlib/src/hash.nr rust

<BlackBoxInfo />

## blake3

Given an array of bytes, returns an array with the Blake3 hash
See blake3_slice for a version that works directly on slices.

#include_code blake3 noir_stdlib/src/hash.nr rust

Expand All @@ -80,18 +61,9 @@ fn main() {

<BlackBoxInfo />

## blake3_slice

A version of blake3 specialized to slices:

#include_code blake3_slice noir_stdlib/src/hash.nr rust

<BlackBoxInfo />

## pedersen_hash

Given an array of Fields, returns the Pedersen hash.
See pedersen_hash_slice for a version that works directly on slices.

#include_code pedersen_hash noir_stdlib/src/hash.nr rust

Expand All @@ -101,18 +73,9 @@ example:

<BlackBoxInfo />

## pedersen_hash_slice

Given a slice of Fields, returns the Pedersen hash.

#include_code pedersen_hash_slice noir_stdlib/src/hash.nr rust

<BlackBoxInfo />

## pedersen_commitment

Given an array of Fields, returns the Pedersen commitment.
See pedersen_commitment_slice for a version that works directly on slices.

#include_code pedersen_commitment noir_stdlib/src/hash.nr rust

Expand All @@ -122,20 +85,11 @@ example:

<BlackBoxInfo />

## pedersen_commitment_slice

Given a slice of Fields, returns the Pedersen commitment.

#include_code pedersen_commitment_slice noir_stdlib/src/hash.nr rust

<BlackBoxInfo />

## keccak256

Given an array of bytes (`u8`), returns the resulting keccak hash as an array of
32 bytes (`[u8; 32]`). Specify a message_size to hash only the first
`message_size` bytes of the input. See keccak256_slice for a version that works
directly on slices.
`message_size` bytes of the input.

#include_code keccak256 noir_stdlib/src/hash.nr rust

Expand All @@ -145,15 +99,6 @@ example:

<BlackBoxInfo />

## keccak256_slice

Given a slice of bytes (`u8`), returns the resulting keccak hash as an array of
32 bytes (`[u8; 32]`).

#include_code keccak256_slice noir_stdlib/src/hash.nr rust

<BlackBoxInfo />

## poseidon

Given an array of Fields, returns a new Field with the Poseidon Hash. Mind that you need to specify
Expand Down
81 changes: 15 additions & 66 deletions noir_stdlib/src/hash.nr
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
mod poseidon;
mod mimc;
mod poseidon2;
mod pedersen;

use crate::default::Default;
use crate::uint128::U128;
Expand All @@ -12,36 +11,18 @@ pub fn sha256<N>(input: [u8; N]) -> [u8; 32]
// docs:end:sha256
{}

#[foreign(sha256)]
// docs:start:sha256_slice
pub fn sha256_slice(input: [u8]) -> [u8; 32]
// docs:end:sha256_slice
{}

#[foreign(blake2s)]
// docs:start:blake2s
pub fn blake2s<N>(input: [u8; N]) -> [u8; 32]
// docs:end:blake2s
{}

#[foreign(blake2s)]
// docs:start:blake2s_slice
pub fn blake2s_slice(input: [u8]) -> [u8; 32]
// docs:end:blake2s_slice
{}

#[foreign(blake3)]
// docs:start:blake3
pub fn blake3<N>(input: [u8; N]) -> [u8; 32]
// docs:end:blake3
{}

#[foreign(blake3)]
// docs:start:blake3_slice
pub fn blake3_slice(input: [u8]) -> [u8; 32]
// docs:end:blake3_slice
{}

// docs:start:pedersen_commitment
struct PedersenPoint {
x : Field,
Expand All @@ -53,60 +34,33 @@ pub fn pedersen_commitment<N>(input: [Field; N]) -> PedersenPoint {
pedersen_commitment_with_separator(input, 0)
}

// docs:start:pedersen_commitment_slice
pub fn pedersen_commitment_slice(input: [Field]) -> PedersenPoint {
pedersen_commitment_with_separator_slice(input, 0)
}
// docs:end:pedersen_commitment_slice

#[foreign(pedersen_commitment)]
pub fn __pedersen_commitment_with_separator<N>(input: [Field; N], separator: u32) -> [Field; 2] {}

#[foreign(pedersen_commitment)]
pub fn __pedersen_commitment_with_separator_slice(input: [Field], separator: u32) -> [Field; 2] {}

pub fn pedersen_commitment_with_separator<N>(input: [Field; N], separator: u32) -> PedersenPoint {
let values = __pedersen_commitment_with_separator(input, separator);
PedersenPoint { x: values[0], y: values[1] }
}

pub fn pedersen_commitment_with_separator_slice(input: [Field], separator: u32) -> PedersenPoint {
let values = __pedersen_commitment_with_separator_slice(input, separator);
PedersenPoint { x: values[0], y: values[1] }
}

// docs:start:pedersen_hash
pub fn pedersen_hash<N>(input: [Field; N]) -> Field
// docs:end:pedersen_hash
{
pedersen_hash_with_separator(input, 0)
}

// docs:start:pedersen_hash_slice
pub fn pedersen_hash_slice(input: [Field]) -> Field
// docs:end:pedersen_hash_slice
{
pedersen_hash_with_separator_slice(input, 0)
}

#[foreign(pedersen_hash)]
pub fn pedersen_hash_with_separator<N>(input: [Field; N], separator: u32) -> Field {}

#[foreign(pedersen_hash)]
pub fn pedersen_hash_with_separator_slice(input: [Field], separator: u32) -> Field {}

pub fn hash_to_field(inputs: [Field]) -> Field {
let mut inputs_as_bytes = &[];
let mut sum = 0;

for input in inputs {
let input_bytes = input.to_le_bytes(32);
for i in 0..32 {
inputs_as_bytes = inputs_as_bytes.push_back(input_bytes[i]);
}
let input_bytes: [u8; 32] = input.to_le_bytes(32).as_array();
sum += crate::field::bytes32_to_field(blake2s(input_bytes));
}

let hashed_input = blake2s_slice(inputs_as_bytes);
crate::field::bytes32_to_field(hashed_input)
sum
}

#[foreign(keccak256)]
Expand All @@ -115,12 +69,6 @@ pub fn keccak256<N>(input: [u8; N], message_size: u32) -> [u8; 32]
// docs:end:keccak256
{}

#[foreign(keccak256)]
// docs:start:keccak256_slice
pub fn keccak256_slice(input: [u8], message_size: u32) -> [u8; 32]
// docs:end:keccak256_slice
{}

#[foreign(poseidon2_permutation)]
pub fn poseidon2_permutation<N>(_input: [Field; N], _state_length: u32) -> [Field; N] {}

Expand All @@ -140,7 +88,7 @@ trait Hash{
trait Hasher{
fn finish(self) -> Field;

fn write(&mut self, input: [Field]);
fn write(&mut self, input: Field);
}

// BuildHasher is a factory trait, responsible for production of specific Hasher.
Expand Down Expand Up @@ -170,49 +118,49 @@ where

impl Hash for Field {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self]);
H::write(state, self);
}
}

impl Hash for u8 {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self as Field]);
H::write(state, self as Field);
}
}

impl Hash for u32 {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self as Field]);
H::write(state, self as Field);
}
}

impl Hash for u64 {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self as Field]);
H::write(state, self as Field);
}
}

impl Hash for i8 {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self as Field]);
H::write(state, self as Field);
}
}

impl Hash for i32 {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self as Field]);
H::write(state, self as Field);
}
}

impl Hash for i64 {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self as Field]);
H::write(state, self as Field);
}
}

impl Hash for bool {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self as Field]);
H::write(state, self as Field);
}
}

Expand All @@ -222,7 +170,8 @@ impl Hash for () {

impl Hash for U128 {
fn hash<H>(self, state: &mut H) where H: Hasher{
H::write(state, &[self.lo as Field, self.hi as Field]);
H::write(state, self.lo as Field);
H::write(state, self.hi as Field);
}
}

Expand Down

0 comments on commit 8e39706

Please sign in to comment.