From 489f889ae29a34e470275f601cdea95d80b50698 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 28 May 2024 12:06:09 +0200 Subject: [PATCH 01/14] feat: migrate to new padding rule --- assembly/src/assembler/instruction/crypto_ops.rs | 11 ++++++----- core/Cargo.toml | 2 +- processor/src/host/mod.rs | 2 -- stdlib/asm/crypto/hashes/native.masm | 10 +++++----- stdlib/asm/mem.masm | 15 ++++++++------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/assembly/src/assembler/instruction/crypto_ops.rs b/assembly/src/assembler/instruction/crypto_ops.rs index d59867fe5b..47ce8c29dd 100644 --- a/assembly/src/assembler/instruction/crypto_ops.rs +++ b/assembly/src/assembler/instruction/crypto_ops.rs @@ -1,5 +1,5 @@ use super::SpanBuilder; -use vm_core::{AdviceInjector, Operation::*}; +use vm_core::{AdviceInjector, Felt, Operation::*}; // HASHING // ================================================================================================ @@ -26,14 +26,15 @@ use vm_core::{AdviceInjector, Operation::*}; pub(super) fn hash(span: &mut SpanBuilder) { #[rustfmt::skip] let ops = [ - // add 4 elements to the stack to be used as the capacity elements for the RPO permutation - Pad, Incr, Pad, Pad, Pad, + // add 4 elements to the stack to be used as the capacity elements for the RPO permutation. + // Since we are hashing 4 field elements, the first capacity element is set to 4. + Push(Felt::from(4_u32)), Pad, Pad, Pad, // swap capacity elements such that they are below the elements to be hashed SwapW, - // Duplicate capacity elements in the rate portion of the stack - Dup7, Dup7, Dup7, Dup7, + // add 4 ZERO elements for the second half of the rate portion + Pad, Dup7, Dup7, Dup7, // Apply a hashing permutation on the top 12 elements in the stack HPerm, diff --git a/core/Cargo.toml b/core/Cargo.toml index 261c9066f5..78460f9772 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -29,7 +29,7 @@ std = [ [dependencies] math = { package = "winter-math", version = "0.9", default-features = false } #miden-crypto = { version = "0.9", default-features = false } -miden-crypto = { git = "https://github.com/0xPolygonMiden/crypto", branch = "next", default-features = false } +miden-crypto = { git = "https://github.com/0xPolygonMiden/crypto", branch = "al-rpo-new-padding-rule", default-features = false } miden-formatting = { version = "0.1", default-features = false } thiserror = { version = "1.0", git = "https://github.com/bitwalker/thiserror", branch = "no-std", default-features = false } winter-utils = { package = "winter-utils", version = "0.9", default-features = false } diff --git a/processor/src/host/mod.rs b/processor/src/host/mod.rs index 13574f11e4..b54553dc55 100644 --- a/processor/src/host/mod.rs +++ b/processor/src/host/mod.rs @@ -1,5 +1,3 @@ -use std::println; - use super::{ExecutionError, Felt, ProcessState}; use crate::MemAdviceProvider; use vm_core::{crypto::merkle::MerklePath, AdviceInjector, DebugOptions, Word}; diff --git a/stdlib/asm/crypto/hashes/native.masm b/stdlib/asm/crypto/hashes/native.masm index 1cd8ac3355..4e8d572aaf 100644 --- a/stdlib/asm/crypto/hashes/native.masm +++ b/stdlib/asm/crypto/hashes/native.masm @@ -54,8 +54,8 @@ end #! Input: [start_addr, end_addr, ...] #! Output: [H, ...] #! Cycles: -#! even words: 48 cycles + 3 * words -#! odd words: 60 cycles + 3 * words +#! even words: 50 cycles + 3 * words +#! odd words: 62 cycles + 3 * words export.hash_memory # enforce `start_addr < end_addr` dup.1 dup.1 u32assert2 u32gt assert @@ -72,8 +72,8 @@ export.hash_memory movup.2 # stack: [start_addr, end_addr, is_odd, ...] - # prepare hasher state (12 cycles) - dup.2 push.0.0.0 padw padw + # prepare hasher state (14 cycles) + dup.2 mul.4 push.0.0.0 padw padw # stack: [C, B, A, start_addr, end_addr, is_odd, ...] # (4 + 3 * words cycles) @@ -89,7 +89,7 @@ export.hash_memory dup.13 mem_loadw # set the padding (9 cycles) - swapw dropw push.1.0.0.0 + swapw dropw push.0.0.0.0 # (1 cycles) hperm diff --git a/stdlib/asm/mem.masm b/stdlib/asm/mem.masm index f81508faf4..e4117a609f 100644 --- a/stdlib/asm/mem.masm +++ b/stdlib/asm/mem.masm @@ -84,8 +84,8 @@ end #! Input: [num_words, write_ptr, ...] #! Output: [HASH, write_ptr', ...] #! Cycles: -#! even num_words: 48 + 9 * num_words / 2 -#! odd num_words: 65 + 9 * round_down(num_words / 2) +#! even num_words: 50 + 9 * num_words / 2 +#! odd num_words: 67 + 9 * round_down(num_words / 2) export.pipe_words_to_memory.0 # check if there is an odd number of words (6 cycles) dup is_odd @@ -99,10 +99,11 @@ export.pipe_words_to_memory.0 sub dup.1 add swap # => [write_ptr, end_ptr, needs_padding, ...] - # Prepare the capacity word. For rescue prime optimized the first element is - # set to `1` when padding is used and `0` otherwse, this is determined by the - # `needs_padding` flag. (4 cycles) - dup.2 push.0.0.0 + # Prepare the capacity word. We use the padding rule which sets the first capacity + # element to `len % 8` where `len` is the length of the hashed sequence. Since `len % 8` + # is either equal to 0 or 4, this is determined by the `needs_padding` flag multiplied + # by 4. (6 cycles) + dup.2 mul.4 push.0.0.0 # => [A, write_ptr, end_ptr, needs_padding, ...] # set initial hasher state (8 cycles) @@ -141,7 +142,7 @@ export.pipe_words_to_memory.0 # => [B', A, write_ptr+1, ...] # Push padding word (4 cycles) - push.1.0.0.0 + push.0.0.0.0 # => [C, B', A, write_ptr+1, ...] # Run RPO permutation (1 cycles) From 1ce5c00676f978ba49cfa07dcc476e6be6b9cb31 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 28 May 2024 12:55:07 +0200 Subject: [PATCH 02/14] fix: clippy --- core/src/operations/mod.rs | 2 +- stdlib/docs/crypto/hashes/native.md | 2 +- stdlib/docs/mem.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/operations/mod.rs b/core/src/operations/mod.rs index 0bef6cbc01..4f22c5ab4c 100644 --- a/core/src/operations/mod.rs +++ b/core/src/operations/mod.rs @@ -129,7 +129,7 @@ pub enum Operation { /// /// The top 4 elements of the stack are expected to be arranged as follows (form the top): /// - least significant bit of the exponent in the previous trace if there's an expacc call, - /// otherwise ZERO + /// otherwise ZERO /// - exponent of base number `a` for this turn /// - accumulated power of base number `a` so far /// - number which needs to be shifted to the right diff --git a/stdlib/docs/crypto/hashes/native.md b/stdlib/docs/crypto/hashes/native.md index db8dc41628..5fbdec4796 100644 --- a/stdlib/docs/crypto/hashes/native.md +++ b/stdlib/docs/crypto/hashes/native.md @@ -4,4 +4,4 @@ Prepares the top of the stack with the hasher initial state.

This pro | ----------- | ------------- | | state_to_digest | Given the hasher state, returns the hash output

Input: [C, B, A, ...]
Ouptut: [HASH, ...]
Where: For the native RPO hasher HASH is B.
Cycles: 9
| | hash_memory_even | Hashes the memory `start_addr` to `end_addr`.

This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite
loop. `end_addr` is not inclusive.

Stack transition:
Input: [C, B, A, start_addr, end_addr, ...]
Output: [C', B', A', end_addr, end_addr ...]
Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1`

Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output.
| -| hash_memory | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

Stack transition:
Input: [start_addr, end_addr, ...]
Output: [H, ...]
Cycles:
even words: 48 cycles + 3 * words
odd words: 60 cycles + 3 * words
| +| hash_memory | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

Stack transition:
Input: [start_addr, end_addr, ...]
Output: [H, ...]
Cycles:
even words: 50 cycles + 3 * words
odd words: 62 cycles + 3 * words
| diff --git a/stdlib/docs/mem.md b/stdlib/docs/mem.md index 4aa67c46b7..2013c68546 100644 --- a/stdlib/docs/mem.md +++ b/stdlib/docs/mem.md @@ -4,5 +4,5 @@ | ----------- | ------------- | | memcopy | Copies `n` words from `read_ptr` to `write_ptr`.

Stack transition looks as follows:
[n, read_ptr, write_ptr, ...] -> [...]
cycles: 15 + 16n
| | pipe_double_words_to_memory | Copies an even number of words from the advice_stack to memory.

Input: [C, B, A, write_ptr, end_ptr, ...]
Output: [C, B, A, write_ptr, ...]

Where:
- The words C, B, and A are the RPO hasher state
- A is the capacity
- C,B are the rate portion of the state
- The value `words = end_ptr - write_ptr` must be positive and even

Cycles: 10 + 9 * word_pairs
| -| pipe_words_to_memory | Copies an arbitrary number of words from the advice stack to memory

Input: [num_words, write_ptr, ...]
Output: [HASH, write_ptr', ...]
Cycles:
even num_words: 48 + 9 * num_words / 2
odd num_words: 65 + 9 * round_down(num_words / 2)
| +| pipe_words_to_memory | Copies an arbitrary number of words from the advice stack to memory

Input: [num_words, write_ptr, ...]
Output: [HASH, write_ptr', ...]
Cycles:
even num_words: 50 + 9 * num_words / 2
odd num_words: 67 + 9 * round_down(num_words / 2)
| | pipe_preimage_to_memory | Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment.

Input: [num_words, write_ptr, COM, ...]
Output: [write_ptr', ...]
Cycles:
even num_words: 58 + 9 * num_words / 2
odd num_words: 75 + 9 * round_down(num_words / 2)
| From 47ed024f2a3e894b4d0f5215eea420f428903921 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 29 May 2024 14:28:30 +0200 Subject: [PATCH 03/14] fix: update namings and optimize masm code --- .../src/assembler/instruction/crypto_ops.rs | 8 ++-- stdlib/asm/collections/mmr.masm | 6 +-- .../crypto/hashes/{native.masm => rpo.masm} | 26 ++++++------ stdlib/asm/mem.masm | 24 ++++++----- stdlib/docs/crypto/hashes/native.md | 7 ---- stdlib/docs/crypto/hashes/rpo.md | 7 ++++ stdlib/docs/mem.md | 4 +- stdlib/tests/crypto/native.rs | 42 +++++++++---------- stdlib/tests/mem/mod.rs | 2 + 9 files changed, 65 insertions(+), 61 deletions(-) rename stdlib/asm/crypto/hashes/{native.masm => rpo.masm} (80%) delete mode 100644 stdlib/docs/crypto/hashes/native.md create mode 100644 stdlib/docs/crypto/hashes/rpo.md diff --git a/assembly/src/assembler/instruction/crypto_ops.rs b/assembly/src/assembler/instruction/crypto_ops.rs index 47ce8c29dd..7852a432ac 100644 --- a/assembly/src/assembler/instruction/crypto_ops.rs +++ b/assembly/src/assembler/instruction/crypto_ops.rs @@ -14,10 +14,10 @@ use vm_core::{AdviceInjector, Felt, Operation::*}; /// To perform the operation we do the following: /// 1. Prepare the stack with 12 elements for HPERM by pushing 4 more elements for the capacity, /// then reordering the stack and pushing an additional 4 elements so that the stack looks like: -/// [0, 0, 0, 1, a3, a2, a1, a0, 0, 0, 0, 1, ...]. The first capacity element is set to ONE as -/// we are hashing a number of elements which is not a multiple of the rate width. We also set -/// the next element in the rate after `A` to ONE. All other capacity and rate elements are set -/// to ZERO, in accordance with the RPO rules. +/// [0, 0, 0, 0, a3, a2, a1, a0, 0, 0, 0, 4, ...]. The first capacity element is set to Felt(4) +/// as we are hashing a number of elements which is equal to 4 modulo the rate width, while the +/// other capacity elements are set to ZERO. A sequence of 4 ZERO elements is used as padding. +/// The padding rule used follows the one described in this [work](https://eprint.iacr.org/2023/1045). /// 2. Append the HPERM operation, which performs a permutation of RPO on the top 12 elements and /// leaves the an output of [D, C, B, ...] on the stack. C is our 1-to-1 has result. /// 3. Drop D and B to achieve our result [C, ...] diff --git a/stdlib/asm/collections/mmr.masm b/stdlib/asm/collections/mmr.masm index 3f50adfb09..04f6c627a3 100644 --- a/stdlib/asm/collections/mmr.masm +++ b/stdlib/asm/collections/mmr.masm @@ -1,5 +1,5 @@ use.std::mem -use.std::crypto::hashes::native +use.std::crypto::hashes::rpo use.std::math::u64 #! Loads the leaf at the absolute `pos` in the MMR. @@ -196,8 +196,8 @@ export.pack # hash the memory contents (25 + 3 * num_peaks) padw padw padw - exec.native::hash_memory_even - exec.native::state_to_digest + exec.rpo::absorb_double_words_from_memory + exec.rpo::squeeze_digest # => [HASH, peaks_end, peaks_end, mmr_ptr, ...] # prepare stack for adv.insert_mem (4 cycles) diff --git a/stdlib/asm/crypto/hashes/native.masm b/stdlib/asm/crypto/hashes/rpo.masm similarity index 80% rename from stdlib/asm/crypto/hashes/native.masm rename to stdlib/asm/crypto/hashes/rpo.masm index 4e8d572aaf..4913020310 100644 --- a/stdlib/asm/crypto/hashes/native.masm +++ b/stdlib/asm/crypto/hashes/rpo.masm @@ -10,13 +10,13 @@ export.init_no_padding padw padw padw end -#! Given the hasher state, returns the hash output +#! Given the hasher state, returns the hash output. #! #! Input: [C, B, A, ...] #! Ouptut: [HASH, ...] -#! Where: For the native RPO hasher HASH is B. +#! where: For the native RPO hasher HASH is B. #! Cycles: 9 -export.state_to_digest +export.squeeze_digest # drop the first rate word (4 cycles) dropw @@ -38,7 +38,7 @@ end #! Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1` #! #! Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output. -export.hash_memory_even +export.absorb_double_words_from_memory dup.13 dup.13 neq # (4 cycles ) while.true mem_stream hperm # (2 cycles) @@ -54,8 +54,8 @@ end #! Input: [start_addr, end_addr, ...] #! Output: [H, ...] #! Cycles: -#! even words: 50 cycles + 3 * words -#! odd words: 62 cycles + 3 * words +#! even words: 49 cycles + 3 * words +#! odd words: 61 cycles + 3 * words export.hash_memory # enforce `start_addr < end_addr` dup.1 dup.1 u32assert2 u32gt assert @@ -77,25 +77,25 @@ export.hash_memory # stack: [C, B, A, start_addr, end_addr, is_odd, ...] # (4 + 3 * words cycles) - exec.hash_memory_even + exec.absorb_double_words_from_memory # (1 cycles) movup.14 # handle the odd element, if any (12 cycles) if.true - # start_addr and end_addr are equal after calling `hash_memory_even`, and both point - # to the last element. Load the last word (2 cycles) - dup.13 mem_loadw + # start_addr and end_addr are equal after calling `absorb_double_words_from_memory`, and both point + # to the last element. Load the last word (6 cycles) + dropw dup.9 mem_loadw - # set the padding (9 cycles) - swapw dropw push.0.0.0.0 + # set the padding (4 cycles) + padw # (1 cycles) hperm end - exec.state_to_digest + exec.squeeze_digest # drop start_addr/end_addr (4 cycles) movup.4 drop movup.4 drop diff --git a/stdlib/asm/mem.masm b/stdlib/asm/mem.masm index e4117a609f..d984dc4968 100644 --- a/stdlib/asm/mem.masm +++ b/stdlib/asm/mem.masm @@ -1,3 +1,5 @@ +use.std::crypto::hashes::rpo + # ===== MEMORY FUNCTIONS ========================================================================== #! Copies `n` words from `read_ptr` to `write_ptr`. @@ -82,10 +84,10 @@ end #! Copies an arbitrary number of words from the advice stack to memory #! #! Input: [num_words, write_ptr, ...] -#! Output: [HASH, write_ptr', ...] +#! Output: [C, B, A, write_ptr', ...] #! Cycles: -#! even num_words: 50 + 9 * num_words / 2 -#! odd num_words: 67 + 9 * round_down(num_words / 2) +#! even num_words: 41 + 9 * num_words / 2 +#! odd num_words: 58 + 9 * round_down(num_words / 2) export.pipe_words_to_memory.0 # check if there is an odd number of words (6 cycles) dup is_odd @@ -142,17 +144,13 @@ export.pipe_words_to_memory.0 # => [B', A, write_ptr+1, ...] # Push padding word (4 cycles) - push.0.0.0.0 + padw # => [C, B', A, write_ptr+1, ...] # Run RPO permutation (1 cycles) hperm # => [C', B', A', write_ptr+1, ...] end - - # The RPO result is word B, discard the unused portion of the rate and the capacity. (9 cycles) - dropw swapw dropw - # => [rpo_hash, write_ptr', ...] end #! Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment. @@ -160,12 +158,16 @@ end #! Input: [num_words, write_ptr, COM, ...] #! Output: [write_ptr', ...] #! Cycles: -#! even num_words: 58 + 9 * num_words / 2 -#! odd num_words: 75 + 9 * round_down(num_words / 2) +#! even num_words: 67 + 9 * num_words / 2 +#! odd num_words: 84 + 9 * round_down(num_words / 2) export.pipe_preimage_to_memory.0 # Copies the advice stack data to memory exec.pipe_words_to_memory - # => [HASH, write_ptr', COM, ...] + # => [C, B, A, write_ptr', COM, ...] + + # Leave only the digest on the stack + exec.rpo::squeeze_digest + # => [B, write_ptr', COM, ...] # Save the write_ptr (2 cycles) movup.4 movdn.8 diff --git a/stdlib/docs/crypto/hashes/native.md b/stdlib/docs/crypto/hashes/native.md deleted file mode 100644 index 5fbdec4796..0000000000 --- a/stdlib/docs/crypto/hashes/native.md +++ /dev/null @@ -1,7 +0,0 @@ -Prepares the top of the stack with the hasher initial state.

This procedures does not handle padding, therefore, the user is expected to
consume an amount of data which is a multiple of the rate (2 words).

Input: []
Ouptut: [PERM, PERM, PERM, ...]
Cycles: 12
-## std::crypto::hashes::native -| Procedure | Description | -| ----------- | ------------- | -| state_to_digest | Given the hasher state, returns the hash output

Input: [C, B, A, ...]
Ouptut: [HASH, ...]
Where: For the native RPO hasher HASH is B.
Cycles: 9
| -| hash_memory_even | Hashes the memory `start_addr` to `end_addr`.

This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite
loop. `end_addr` is not inclusive.

Stack transition:
Input: [C, B, A, start_addr, end_addr, ...]
Output: [C', B', A', end_addr, end_addr ...]
Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1`

Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output.
| -| hash_memory | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

Stack transition:
Input: [start_addr, end_addr, ...]
Output: [H, ...]
Cycles:
even words: 50 cycles + 3 * words
odd words: 62 cycles + 3 * words
| diff --git a/stdlib/docs/crypto/hashes/rpo.md b/stdlib/docs/crypto/hashes/rpo.md new file mode 100644 index 0000000000..cbeb54b721 --- /dev/null +++ b/stdlib/docs/crypto/hashes/rpo.md @@ -0,0 +1,7 @@ +Prepares the top of the stack with the hasher initial state.

This procedures does not handle padding, therefore, the user is expected to
consume an amount of data which is a multiple of the rate (2 words).

Input: []
Ouptut: [PERM, PERM, PERM, ...]
Cycles: 12
+## std::crypto::hashes::rpo +| Procedure | Description | +| ----------- | ------------- | +| squeeze_digest | Given the hasher state, returns the hash output.

Input: [C, B, A, ...]
Ouptut: [HASH, ...]
where: For the native RPO hasher HASH is B.
Cycles: 9
| +| absorb_double_words_from_memory | Hashes the memory `start_addr` to `end_addr`.

This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite
loop. `end_addr` is not inclusive.

Stack transition:
Input: [C, B, A, start_addr, end_addr, ...]
Output: [C', B', A', end_addr, end_addr ...]
Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1`

Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output.
| +| hash_memory | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

Stack transition:
Input: [start_addr, end_addr, ...]
Output: [H, ...]
Cycles:
even words: 49 cycles + 3 * words
odd words: 61 cycles + 3 * words
| diff --git a/stdlib/docs/mem.md b/stdlib/docs/mem.md index 2013c68546..8267ca28e1 100644 --- a/stdlib/docs/mem.md +++ b/stdlib/docs/mem.md @@ -4,5 +4,5 @@ | ----------- | ------------- | | memcopy | Copies `n` words from `read_ptr` to `write_ptr`.

Stack transition looks as follows:
[n, read_ptr, write_ptr, ...] -> [...]
cycles: 15 + 16n
| | pipe_double_words_to_memory | Copies an even number of words from the advice_stack to memory.

Input: [C, B, A, write_ptr, end_ptr, ...]
Output: [C, B, A, write_ptr, ...]

Where:
- The words C, B, and A are the RPO hasher state
- A is the capacity
- C,B are the rate portion of the state
- The value `words = end_ptr - write_ptr` must be positive and even

Cycles: 10 + 9 * word_pairs
| -| pipe_words_to_memory | Copies an arbitrary number of words from the advice stack to memory

Input: [num_words, write_ptr, ...]
Output: [HASH, write_ptr', ...]
Cycles:
even num_words: 50 + 9 * num_words / 2
odd num_words: 67 + 9 * round_down(num_words / 2)
| -| pipe_preimage_to_memory | Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment.

Input: [num_words, write_ptr, COM, ...]
Output: [write_ptr', ...]
Cycles:
even num_words: 58 + 9 * num_words / 2
odd num_words: 75 + 9 * round_down(num_words / 2)
| +| pipe_words_to_memory | Copies an arbitrary number of words from the advice stack to memory

Input: [num_words, write_ptr, ...]
Output: [C, B, A, write_ptr', ...]
Cycles:
even num_words: 41 + 9 * num_words / 2
odd num_words: 58 + 9 * round_down(num_words / 2)
| +| pipe_preimage_to_memory | Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment.

Input: [num_words, write_ptr, COM, ...]
Output: [write_ptr', ...]
Cycles:
even num_words: 67 + 9 * num_words / 2
odd num_words: 84 + 9 * round_down(num_words / 2)
| diff --git a/stdlib/tests/crypto/native.rs b/stdlib/tests/crypto/native.rs index 3c96997aa3..8100264dce 100644 --- a/stdlib/tests/crypto/native.rs +++ b/stdlib/tests/crypto/native.rs @@ -5,13 +5,13 @@ use test_utils::{build_expected_hash, build_expected_perm, expect_exec_error}; fn test_invalid_end_addr() { // end_addr can not be smaller than start_addr let empty_range = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin push.0999 # end address push.1000 # start address - exec.native::hash_memory + exec.rpo::hash_memory end "; let test = build_test!(empty_range, &[]); @@ -26,13 +26,13 @@ fn test_invalid_end_addr() { // address range can not contain zero elements let empty_range = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin push.1000 # end address push.1000 # start address - exec.native::hash_memory + exec.rpo::hash_memory end "; let test = build_test!(empty_range, &[]); @@ -69,13 +69,13 @@ fn test_hash_empty() { // checks the hash compute from 8 zero elements is the same when using hash_memory let two_zeros = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin push.1002 # end address push.1000 # start address - exec.native::hash_memory + exec.rpo::hash_memory end "; @@ -110,7 +110,7 @@ fn test_single_iteration() { // Note: This is testing the hashing of two words, so no padding is added // here let one_element = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin # insert 1 to memory @@ -119,7 +119,7 @@ fn test_single_iteration() { push.1002 # end address push.1000 # start address - exec.native::hash_memory + exec.rpo::hash_memory end "; @@ -139,7 +139,7 @@ fn test_hash_one_word() { // checks the hash of 1 is the same when using hash_memory let one_element = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin push.1.1000 mem_store # push data to memory @@ -147,7 +147,7 @@ fn test_hash_one_word() { push.1001 # end address push.1000 # start address - exec.native::hash_memory + exec.rpo::hash_memory end "; @@ -158,7 +158,7 @@ fn test_hash_one_word() { fn test_hash_even_words() { // checks the hash of two words let even_words = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin push.1.0.0.0.1000 mem_storew dropw @@ -167,7 +167,7 @@ fn test_hash_even_words() { push.1002 # end address push.1000 # start address - exec.native::hash_memory + exec.rpo::hash_memory end "; @@ -183,7 +183,7 @@ fn test_hash_even_words() { fn test_hash_odd_words() { // checks the hash of three words let odd_words = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin push.1.0.0.0.1000 mem_storew dropw @@ -193,7 +193,7 @@ fn test_hash_odd_words() { push.1003 # end address push.1000 # start address - exec.native::hash_memory + exec.rpo::hash_memory end "; @@ -207,9 +207,9 @@ fn test_hash_odd_words() { } #[test] -fn test_hash_memory_even() { +fn test_absorb_double_words_from_memory() { let even_words = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin push.1.0.0.0.1000 mem_storew dropw @@ -218,7 +218,7 @@ fn test_hash_memory_even() { push.1002 # end address push.1000 # start address padw padw padw # hasher state - exec.native::hash_memory_even + exec.rpo::absorb_double_words_from_memory end "; @@ -237,9 +237,9 @@ fn test_hash_memory_even() { } #[test] -fn test_state_to_digest() { +fn test_squeeze_digest() { let even_words = " - use.std::crypto::hashes::native + use.std::crypto::hashes::rpo begin push.1.0.0.0.1000 mem_storew dropw @@ -250,9 +250,9 @@ fn test_state_to_digest() { push.1004 # end address push.1000 # start address padw padw padw # hasher state - exec.native::hash_memory_even + exec.rpo::absorb_double_words_from_memory - exec.native::state_to_digest + exec.rpo::squeeze_digest end "; diff --git a/stdlib/tests/mem/mod.rs b/stdlib/tests/mem/mod.rs index b199db7042..12dcc099ac 100644 --- a/stdlib/tests/mem/mod.rs +++ b/stdlib/tests/mem/mod.rs @@ -128,6 +128,7 @@ fn test_pipe_words_to_memory() { push.1 # number of words exec.mem::pipe_words_to_memory + dropw swapw dropw end", mem_addr ); @@ -150,6 +151,7 @@ fn test_pipe_words_to_memory() { push.3 # number of words exec.mem::pipe_words_to_memory + dropw swapw dropw end", mem_addr ); From 649b342166252086adbb3e1bcf22043242ca6ebf Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:37:58 +0200 Subject: [PATCH 04/14] chore: minor nits and comment updates --- assembly/src/ast/instruction/print.rs | 2 +- stdlib/asm/collections/mmr.masm | 2 +- stdlib/asm/crypto/dsa/rpo_falcon512.masm | 4 +++- stdlib/asm/crypto/hashes/rpo.masm | 2 +- stdlib/asm/crypto/stark/ood_frames.masm | 3 ++- stdlib/asm/crypto/stark/random_coin.masm | 6 +++--- stdlib/asm/mem.masm | 4 ++-- stdlib/docs/crypto/hashes/rpo.md | 2 +- stdlib/docs/mem.md | 2 +- stdlib/tests/crypto/falcon.rs | 2 +- stdlib/tests/crypto/native.rs | 8 ++++++-- stdlib/tests/mem/mod.rs | 6 ++++-- 12 files changed, 26 insertions(+), 17 deletions(-) diff --git a/assembly/src/ast/instruction/print.rs b/assembly/src/ast/instruction/print.rs index 421e28fd68..99358b4132 100644 --- a/assembly/src/ast/instruction/print.rs +++ b/assembly/src/ast/instruction/print.rs @@ -422,7 +422,7 @@ mod tests { let target = InvocationTarget::MastRoot(Span::unknown(digest)); let instruction = format!("{}", Instruction::Exec(target)); assert_eq!( - "exec.0x03b49d98981575360dd1f8c8b5a7feefcadadd56ec2a33e3e43edae3577de150", + "exec.0x90b3926941061b28638b6cc0bbdb3bcb335e834dc9ab8044250875055202d2fe", instruction ); } diff --git a/stdlib/asm/collections/mmr.masm b/stdlib/asm/collections/mmr.masm index 04f6c627a3..4ed948fc62 100644 --- a/stdlib/asm/collections/mmr.masm +++ b/stdlib/asm/collections/mmr.masm @@ -165,7 +165,7 @@ export.unpack # => [C, B, A, mmr_ptr+17, HASH, ...] # drop anything but the hash result, word B (11 cycles) - dropw swapw dropw movup.4 drop + exec.rpo::squeeze_digest movup.4 drop # => [B, HASH, ...] # assert on the resulting hash (11 cycles) diff --git a/stdlib/asm/crypto/dsa/rpo_falcon512.masm b/stdlib/asm/crypto/dsa/rpo_falcon512.masm index 5cb418dce3..637f490bf9 100644 --- a/stdlib/asm/crypto/dsa/rpo_falcon512.masm +++ b/stdlib/asm/crypto/dsa/rpo_falcon512.masm @@ -1,3 +1,5 @@ +use.std::crypto::hashes::rpo + # CONSTANTS # ================================================================================================= @@ -224,7 +226,7 @@ export.load_h_s2_and_product.1 end # 6) Return the challenge point and the incremented pointer - dropw swapw dropw + exec.rpo::squeeze_digest drop drop #=> [tau1, tau0, ptr + 512] end diff --git a/stdlib/asm/crypto/hashes/rpo.masm b/stdlib/asm/crypto/hashes/rpo.masm index 4913020310..27c6b12aec 100644 --- a/stdlib/asm/crypto/hashes/rpo.masm +++ b/stdlib/asm/crypto/hashes/rpo.masm @@ -27,7 +27,7 @@ export.squeeze_digest dropw end -#! Hashes the memory `start_addr` to `end_addr`. +#! Hashes the memory `start_addr` to `end_addr` given an RPO state specified by 3 words. #! #! This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite #! loop. `end_addr` is not inclusive. diff --git a/stdlib/asm/crypto/stark/ood_frames.masm b/stdlib/asm/crypto/stark/ood_frames.masm index c6b9e50f26..bb3fabc1bc 100644 --- a/stdlib/asm/crypto/stark/ood_frames.masm +++ b/stdlib/asm/crypto/stark/ood_frames.masm @@ -1,4 +1,5 @@ use.std::crypto::stark::constants +use.std::crypto::hashes::rpo #! Loads OOD evaluation frame, with current and next rows interleaved, into memory. This ouputs @@ -105,7 +106,7 @@ export.load_constraint_evaluations hperm - dropw swapw dropw + exec.rpo::squeeze_digest end #! Computes the H(z) evaluation of the constraint composition polynomial at the OOD element z. diff --git a/stdlib/asm/crypto/stark/random_coin.masm b/stdlib/asm/crypto/stark/random_coin.masm index e66b024a40..07f431cb22 100644 --- a/stdlib/asm/crypto/stark/random_coin.masm +++ b/stdlib/asm/crypto/stark/random_coin.masm @@ -1,6 +1,6 @@ use.std::crypto::stark::constants use.std::crypto::stark::utils - +use.std::crypto::hashes::rpo #! Helper procedure to compute addition of two words component-wise. #! Input: [b3, b2, b1, b0, a3, a2, a1, a0] @@ -665,7 +665,7 @@ export.generate_list_indices exec.get_rate_2 hperm - dropw swapw dropw + exec.rpo::squeeze_digest #=> [R1, query_ptr, mask, depth, num_queries, ...] @@ -698,7 +698,7 @@ export.generate_list_indices exec.get_rate_2 hperm - dropw swapw dropw + exec.rpo::squeeze_digest #=> [R1, query_ptr, mask, depth, num_queries, ...] movup.7 sub.1 dup movdn.8 push.0 neq diff --git a/stdlib/asm/mem.masm b/stdlib/asm/mem.masm index d984dc4968..b420ab944a 100644 --- a/stdlib/asm/mem.masm +++ b/stdlib/asm/mem.masm @@ -158,8 +158,8 @@ end #! Input: [num_words, write_ptr, COM, ...] #! Output: [write_ptr', ...] #! Cycles: -#! even num_words: 67 + 9 * num_words / 2 -#! odd num_words: 84 + 9 * round_down(num_words / 2) +#! even num_words: 62 + 9 * num_words / 2 +#! odd num_words: 79 + 9 * round_down(num_words / 2) export.pipe_preimage_to_memory.0 # Copies the advice stack data to memory exec.pipe_words_to_memory diff --git a/stdlib/docs/crypto/hashes/rpo.md b/stdlib/docs/crypto/hashes/rpo.md index cbeb54b721..eb10fb3cfb 100644 --- a/stdlib/docs/crypto/hashes/rpo.md +++ b/stdlib/docs/crypto/hashes/rpo.md @@ -3,5 +3,5 @@ Prepares the top of the stack with the hasher initial state.

This pro | Procedure | Description | | ----------- | ------------- | | squeeze_digest | Given the hasher state, returns the hash output.

Input: [C, B, A, ...]
Ouptut: [HASH, ...]
where: For the native RPO hasher HASH is B.
Cycles: 9
| -| absorb_double_words_from_memory | Hashes the memory `start_addr` to `end_addr`.

This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite
loop. `end_addr` is not inclusive.

Stack transition:
Input: [C, B, A, start_addr, end_addr, ...]
Output: [C', B', A', end_addr, end_addr ...]
Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1`

Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output.
| +| absorb_double_words_from_memory | Hashes the memory `start_addr` to `end_addr` given an RPO state specified by 3 words.

This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite
loop. `end_addr` is not inclusive.

Stack transition:
Input: [C, B, A, start_addr, end_addr, ...]
Output: [C', B', A', end_addr, end_addr ...]
Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1`

Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output.
| | hash_memory | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

Stack transition:
Input: [start_addr, end_addr, ...]
Output: [H, ...]
Cycles:
even words: 49 cycles + 3 * words
odd words: 61 cycles + 3 * words
| diff --git a/stdlib/docs/mem.md b/stdlib/docs/mem.md index 8267ca28e1..84fdb8134e 100644 --- a/stdlib/docs/mem.md +++ b/stdlib/docs/mem.md @@ -5,4 +5,4 @@ | memcopy | Copies `n` words from `read_ptr` to `write_ptr`.

Stack transition looks as follows:
[n, read_ptr, write_ptr, ...] -> [...]
cycles: 15 + 16n
| | pipe_double_words_to_memory | Copies an even number of words from the advice_stack to memory.

Input: [C, B, A, write_ptr, end_ptr, ...]
Output: [C, B, A, write_ptr, ...]

Where:
- The words C, B, and A are the RPO hasher state
- A is the capacity
- C,B are the rate portion of the state
- The value `words = end_ptr - write_ptr` must be positive and even

Cycles: 10 + 9 * word_pairs
| | pipe_words_to_memory | Copies an arbitrary number of words from the advice stack to memory

Input: [num_words, write_ptr, ...]
Output: [C, B, A, write_ptr', ...]
Cycles:
even num_words: 41 + 9 * num_words / 2
odd num_words: 58 + 9 * round_down(num_words / 2)
| -| pipe_preimage_to_memory | Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment.

Input: [num_words, write_ptr, COM, ...]
Output: [write_ptr', ...]
Cycles:
even num_words: 67 + 9 * num_words / 2
odd num_words: 84 + 9 * round_down(num_words / 2)
| +| pipe_preimage_to_memory | Moves an arbitrary number of words from the advice stack to memory and asserts it matches the commitment.

Input: [num_words, write_ptr, COM, ...]
Output: [write_ptr', ...]
Cycles:
even num_words: 62 + 9 * num_words / 2
odd num_words: 79 + 9 * round_down(num_words / 2)
| diff --git a/stdlib/tests/crypto/falcon.rs b/stdlib/tests/crypto/falcon.rs index 4e3693a504..4e5c65d19d 100644 --- a/stdlib/tests/crypto/falcon.rs +++ b/stdlib/tests/crypto/falcon.rs @@ -172,7 +172,7 @@ fn test_falcon512_probabilistic_product_failure() { expect_exec_error!( test, ExecutionError::FailedAssertion { - clk: 17490, + clk: 17498, err_code: 0, err_msg: None, } diff --git a/stdlib/tests/crypto/native.rs b/stdlib/tests/crypto/native.rs index 8100264dce..51617c238a 100644 --- a/stdlib/tests/crypto/native.rs +++ b/stdlib/tests/crypto/native.rs @@ -50,13 +50,15 @@ fn test_invalid_end_addr() { fn test_hash_empty() { // computes the hash for 8 consecutive zeros using mem_stream directly let two_zeros_mem_stream = " + use.std::crypto::hashes::rpo + begin # mem_stream state push.1000 padw padw padw mem_stream hperm # drop everything except the hash - dropw swapw dropw movup.4 drop + exec.rpo::squeeze_digest movup.4 drop end "; @@ -86,6 +88,8 @@ fn test_hash_empty() { fn test_single_iteration() { // computes the hash of 1 using mem_stream let one_memstream = " + use.std::crypto::hashes::rpo + begin # insert 1 to memory push.1.1000 mem_store @@ -95,7 +99,7 @@ fn test_single_iteration() { mem_stream hperm # drop everything except the hash - dropw swapw dropw movup.4 drop + exec.rpo::squeeze_digest movup.4 drop end "; diff --git a/stdlib/tests/mem/mod.rs b/stdlib/tests/mem/mod.rs index 12dcc099ac..0486258771 100644 --- a/stdlib/tests/mem/mod.rs +++ b/stdlib/tests/mem/mod.rs @@ -122,13 +122,14 @@ fn test_pipe_words_to_memory() { let mem_addr = 1000; let one_word = format!( "use.std::mem + use.std::crypto::hashes::rpo begin push.{} # target address push.1 # number of words exec.mem::pipe_words_to_memory - dropw swapw dropw + exec.rpo::squeeze_digest end", mem_addr ); @@ -145,13 +146,14 @@ fn test_pipe_words_to_memory() { let three_words = format!( "use.std::mem + use.std::crypto::hashes::rpo begin push.{} # target address push.3 # number of words exec.mem::pipe_words_to_memory - dropw swapw dropw + exec.rpo::squeeze_digest end", mem_addr ); From 96f24acef7d5aba6d1eb63aeeda76b59a801eb69 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 5 Jun 2024 17:42:17 +0200 Subject: [PATCH 05/14] chore: change file name --- stdlib/tests/crypto/mod.rs | 2 +- stdlib/tests/crypto/{native.rs => rpo.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename stdlib/tests/crypto/{native.rs => rpo.rs} (100%) diff --git a/stdlib/tests/crypto/mod.rs b/stdlib/tests/crypto/mod.rs index 848b9e1f62..e68dbc291e 100644 --- a/stdlib/tests/crypto/mod.rs +++ b/stdlib/tests/crypto/mod.rs @@ -6,6 +6,6 @@ mod ecdsa_secp256k1; mod elgamal; mod fri; mod keccak256; -mod native; +mod rpo; mod sha256; mod stark; diff --git a/stdlib/tests/crypto/native.rs b/stdlib/tests/crypto/rpo.rs similarity index 100% rename from stdlib/tests/crypto/native.rs rename to stdlib/tests/crypto/rpo.rs From 9ff8f064ee5b23e3d6d2dca1d501f361395ff376 Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 26 Jun 2024 19:38:44 +0300 Subject: [PATCH 06/14] feat: implement hash_memory procedure --- CHANGELOG.md | 1 + stdlib/asm/crypto/hashes/rpo.masm | 151 +++++++++++++++++++++++++++++- stdlib/docs/crypto/hashes/rpo.md | 3 +- stdlib/tests/crypto/rpo.rs | 47 ++++++++-- 4 files changed, 190 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f5bd1db4fb..8718d8ab51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ #### Stdlib - Added `init_no_padding` procedure to `std::crypto::hashes::native` (#1313). +- Added `hash_memory` procedure to `std::crypto::hashes::rpo` (#1368). #### VM Internals - Removed unused `find_lone_leaf()` function from the Advice Provider (#1262). diff --git a/stdlib/asm/crypto/hashes/rpo.masm b/stdlib/asm/crypto/hashes/rpo.masm index 27c6b12aec..471f3c97bd 100644 --- a/stdlib/asm/crypto/hashes/rpo.masm +++ b/stdlib/asm/crypto/hashes/rpo.masm @@ -56,7 +56,7 @@ end #! Cycles: #! even words: 49 cycles + 3 * words #! odd words: 61 cycles + 3 * words -export.hash_memory +export.hash_memory_words # enforce `start_addr < end_addr` dup.1 dup.1 u32assert2 u32gt assert @@ -100,3 +100,152 @@ export.hash_memory # drop start_addr/end_addr (4 cycles) movup.4 drop movup.4 drop end + +#! Computes hash of note inputs starting at the specified memory address. +#! +#! If the number if inputs is 0, procedure returns the empty word: [ZERO, ZERO, ZERO, ZERO]. +#! +#! Inputs: [inputs_ptr, num_inputs] +#! Outputs: [HASH] +export.hash_memory + # move number of inputs to the top of the stack + swap + # => [num_inputs, inputs_ptr] + + # get the number of double words + u32divmod.8 swap + # => [num_inputs/8, num_inputs%8, inputs_ptr] + + # get the end_addr for hash_memory_even proc (end address for pairs of words) + mul.2 dup.2 add movup.2 + # => [inputs_ptr, end_addr, num_inputs%8] + + # get the capacity element which is equal to num_inputs%8 + dup.2 + # => [capacity, inputs_ptr, end_addr, num_inputs%8] + + # prepare hasher state for RPO permutation + push.0.0.0 padw padw + # => [C, B, A, inputs_ptr, end_addr, num_inputs%8] + + # hash every pair of words + exec.absorb_double_words_from_memory + # => [C', B', A', inputs_ptr', end_addr, num_inputs%8] where inputs_ptr' = end_addr + + # hash remaining input values if there any left + # if num_inputs%8 is not ZERO + dup.14 push.0 neq + if.true + # load the remaining double word + mem_stream + # => [E, D, A', inputs_ptr'+2, end_addr, num_inputs%8] + + # clean the stack + movup.12 drop movup.12 drop + # => [E, D, A', num_inputs%8] + + # get the number of elements we need to drop + # notice that drop_counter could be any number from 1 to 7 + push.8 movup.13 sub movdn.12 + # => [E, D, A', drop_counter] + + ### 0th value ######################################################## + + # we need to drop first value anyway, since number of values is not divisible by 8 + drop + # => [e_1, e_2, e_3, d_0, d_1, d_2, d_3, A', drop_counter] + + # push the padding 0 value + push.0 + # => [0, e_1, e_2, e_3, d_0, d_1, d_2, d_3, A', drop_counter] + + # move the calculated value down the stack + movdn.6 + # => [e_1, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] + + ### 1st value ######################################################## + + # prepare the second element of the E Word (e_1) for cdrop instruction + push.0 swap + # => [e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] + + # push latch variable onto the stack; this will be the control for the cdrop instruction + push.0 + # => [latch = 0, e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] + + # get the flag whether the drop counter is equal 1 + dup.14 eq.1 + # => [drop_counter == 1, latch = 0, e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] + + # update the latch: if drop_counter == 1, latch will become 1 + or + # => [latch', e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] + + # save the latch value + dup movdn.14 + # => [latch', e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', latch', drop_counter] + + # if latch == 1, drop 0; otherwise drop e_1 + cdrop + # => [e_1_or_0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', latch', drop_counter] + + # move the calculated value down the stack + movdn.6 + # => [e_2, e_3, d_0, d_1, d_2, 0, e_1_or_0, d_3, A', latch', drop_counter] + + ### 2nd value ######################################################## + + # repeat the above process but now compare drop_counter to 2 + push.0 swap + movup.13 dup.14 eq.2 or + dup movdn.14 + cdrop movdn.6 + # => [e_3, d_0, d_1, d_2, 0, e_1_or_0, e_2_or_0, d_3, A', latch', drop_counter] + + ### 3rd value ######################################################## + + # repeat the above process but now compare drop_counter to 3 + push.0 swap + movup.13 dup.14 eq.3 or + dup movdn.14 + cdrop movdn.6 + # => [d_0, d_1, d_2, 0, e_1_or_0, e_2_or_0, e_3_or_0, d_3, A', latch', drop_counter] + + ### 4th value ######################################################## + + # repeat the above process but now compare drop_counter to 4 + push.0 swap + movup.13 dup.14 eq.4 or + dup movdn.14 + cdrop movdn.6 + # => [d_1, d_2, 0, e_1_or_0, e_2_or_0, e_3_or_0, d_0_or_0, d_3, A', latch', drop_counter] + + ### 5th value ######################################################## + + # repeat the above process but now compare drop_counter to 5 + push.0 swap + movup.13 dup.14 eq.5 or + dup movdn.14 + cdrop movdn.6 + # => [d_2, 0, e_1_or_0, e_2_or_0, e_3_or_0, d_0_or_0, d_1_or_0, d_3, A', latch', drop_counter] + + ### 6th value ######################################################## + + # repeat the above process but now compare drop_counter to 6 + push.0 swap + movup.13 movup.14 eq.6 or + cdrop movdn.6 + # => [0, e_1_or_0, e_2_or_0, e_3_or_0, d_0_or_0, d_1_or_0, d_2_or_0, d_3, A'] + # or in other words + # => [C, B, A', ... ] + + hperm + # => [F, E, D] + + exec.squeeze_digest + # => [E] + else + dropw movdnw.2 dropw dropw + # => [B'] + end +end \ No newline at end of file diff --git a/stdlib/docs/crypto/hashes/rpo.md b/stdlib/docs/crypto/hashes/rpo.md index eb10fb3cfb..cafe2d96e5 100644 --- a/stdlib/docs/crypto/hashes/rpo.md +++ b/stdlib/docs/crypto/hashes/rpo.md @@ -4,4 +4,5 @@ Prepares the top of the stack with the hasher initial state.

This pro | ----------- | ------------- | | squeeze_digest | Given the hasher state, returns the hash output.

Input: [C, B, A, ...]
Ouptut: [HASH, ...]
where: For the native RPO hasher HASH is B.
Cycles: 9
| | absorb_double_words_from_memory | Hashes the memory `start_addr` to `end_addr` given an RPO state specified by 3 words.

This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite
loop. `end_addr` is not inclusive.

Stack transition:
Input: [C, B, A, start_addr, end_addr, ...]
Output: [C', B', A', end_addr, end_addr ...]
Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1`

Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output.
| -| hash_memory | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

Stack transition:
Input: [start_addr, end_addr, ...]
Output: [H, ...]
Cycles:
even words: 49 cycles + 3 * words
odd words: 61 cycles + 3 * words
| +| hash_memory_words | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

Stack transition:
Input: [start_addr, end_addr, ...]
Output: [H, ...]
Cycles:
even words: 49 cycles + 3 * words
odd words: 61 cycles + 3 * words
| +| hash_memory | Computes hash of note inputs starting at the specified memory address.

If the number if inputs is 0, procedure returns the empty word: [ZERO, ZERO, ZERO, ZERO].

Inputs: [inputs_ptr, num_inputs]
Outputs: [HASH]
| diff --git a/stdlib/tests/crypto/rpo.rs b/stdlib/tests/crypto/rpo.rs index 51617c238a..3c7bd7244b 100644 --- a/stdlib/tests/crypto/rpo.rs +++ b/stdlib/tests/crypto/rpo.rs @@ -11,7 +11,7 @@ fn test_invalid_end_addr() { push.0999 # end address push.1000 # start address - exec.rpo::hash_memory + exec.rpo::hash_memory_words end "; let test = build_test!(empty_range, &[]); @@ -32,7 +32,7 @@ fn test_invalid_end_addr() { push.1000 # end address push.1000 # start address - exec.rpo::hash_memory + exec.rpo::hash_memory_words end "; let test = build_test!(empty_range, &[]); @@ -69,7 +69,7 @@ fn test_hash_empty() { ]).into_iter().map(|e| e.as_int()).collect(); build_test!(two_zeros_mem_stream, &[]).expect_stack(&zero_hash); - // checks the hash compute from 8 zero elements is the same when using hash_memory + // checks the hash compute from 8 zero elements is the same when using hash_memory_words let two_zeros = " use.std::crypto::hashes::rpo @@ -77,7 +77,7 @@ fn test_hash_empty() { push.1002 # end address push.1000 # start address - exec.rpo::hash_memory + exec.rpo::hash_memory_words end "; @@ -110,7 +110,7 @@ fn test_single_iteration() { ]).into_iter().map(|e| e.as_int()).collect(); build_test!(one_memstream, &[]).expect_stack(&one_hash); - // checks the hash of 1 is the same when using hash_memory + // checks the hash of 1 is the same when using hash_memory_words // Note: This is testing the hashing of two words, so no padding is added // here let one_element = " @@ -123,7 +123,7 @@ fn test_single_iteration() { push.1002 # end address push.1000 # start address - exec.rpo::hash_memory + exec.rpo::hash_memory_words end "; @@ -141,7 +141,7 @@ fn test_hash_one_word() { 1, 0, 0, 0, ]).into_iter().map(|e| e.as_int()).collect(); - // checks the hash of 1 is the same when using hash_memory + // checks the hash of 1 is the same when using hash_memory_words let one_element = " use.std::crypto::hashes::rpo @@ -151,7 +151,7 @@ fn test_hash_one_word() { push.1001 # end address push.1000 # start address - exec.rpo::hash_memory + exec.rpo::hash_memory_words end "; @@ -171,7 +171,7 @@ fn test_hash_even_words() { push.1002 # end address push.1000 # start address - exec.rpo::hash_memory + exec.rpo::hash_memory_words end "; @@ -197,7 +197,7 @@ fn test_hash_odd_words() { push.1003 # end address push.1000 # start address - exec.rpo::hash_memory + exec.rpo::hash_memory_words end "; @@ -274,3 +274,30 @@ fn test_squeeze_digest() { build_test!(even_words, &[]).expect_stack(&even_hash); } + +#[test] +fn test_hash_memory() { + let compute_inputs_hash = " + use.std::crypto::hashes::rpo + + begin + push.1.2.3.4.1000 mem_storew dropw + push.5.6.7.8.1001 mem_storew dropw + push.9.10.11.12.1002 mem_storew dropw + push.13.14.15.0.1003 mem_storew dropw + + + push.15.1000 + + ####################################################### + + exec.rpo::hash_memory + end + "; + + #[rustfmt::skip] + let expected_hash: Vec = build_expected_hash(&[ + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + ]).into_iter().map(|e| e.as_int()).collect(); + build_test!(compute_inputs_hash, &[]).expect_stack(&expected_hash); +} From cdba4ac491b10bc649c43a8a34a6686f03739f6f Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 26 Jun 2024 19:57:13 +0300 Subject: [PATCH 07/14] chore: fix clippy errors --- air/src/constraints/chiplets/hasher/mod.rs | 4 +- air/src/constraints/stack/field_ops/mod.rs | 8 +-- air/src/constraints/stack/op_flags/mod.rs | 2 +- air/src/constraints/stack/overflow/mod.rs | 6 +- .../stack/stack_manipulation/mod.rs | 4 +- air/src/constraints/stack/u32_ops/mod.rs | 8 +-- assembly/src/assembler/mod.rs | 8 +-- .../assembler/module_graph/rewrites/module.rs | 4 +- assembly/src/ast/module.rs | 8 +-- assembly/src/ast/visit.rs | 15 ++--- processor/src/chiplets/mod.rs | 64 ++++++++++--------- processor/src/decoder/mod.rs | 2 +- processor/src/host/advice/injectors/dsa.rs | 2 +- processor/src/operations/comb_ops.rs | 12 ++-- processor/src/operations/field_ops.rs | 6 +- processor/src/operations/io_ops.rs | 4 +- processor/src/trace/utils.rs | 2 +- test-utils/src/lib.rs | 2 +- test-utils/src/test_builders.rs | 18 +++--- 19 files changed, 90 insertions(+), 89 deletions(-) diff --git a/air/src/constraints/chiplets/hasher/mod.rs b/air/src/constraints/chiplets/hasher/mod.rs index e58828d80b..8df5fca0cb 100644 --- a/air/src/constraints/chiplets/hasher/mod.rs +++ b/air/src/constraints/chiplets/hasher/mod.rs @@ -101,9 +101,9 @@ pub fn get_transition_constraint_count() -> usize { /// Enforces constraints for the hasher chiplet. /// /// - The `hasher_flag` determines if the hasher chiplet is currently enabled. It should be -/// computed by the caller and set to `Felt::ONE` +/// computed by the caller and set to `Felt::ONE` /// - The `transition_flag` indicates whether this is the last row this chiplet's execution trace, -/// and therefore the constraints should not be enforced. +/// and therefore the constraints should not be enforced. pub fn enforce_constraints>( frame: &EvaluationFrame, periodic_values: &[E], diff --git a/air/src/constraints/stack/field_ops/mod.rs b/air/src/constraints/stack/field_ops/mod.rs index 4248eea85a..f185e255c9 100644 --- a/air/src/constraints/stack/field_ops/mod.rs +++ b/air/src/constraints/stack/field_ops/mod.rs @@ -188,7 +188,7 @@ pub fn enforce_incr_constraints( /// enforced: /// - The top element should be a binary. It is enforced as a general constraint. /// - The first element of the next frame should be a binary not of the first element of -/// the current frame. s0` + s0 = 1. +/// the current frame. s0` + s0 = 1. pub fn enforce_not_constraints( frame: &EvaluationFrame, result: &mut [E], @@ -207,7 +207,7 @@ pub fn enforce_not_constraints( /// Enforces constraints of the AND operation. The AND operation computes the bitwise and of the /// first two elements in the current trace. Therefore, the following constraints are enforced: /// - The top two element in the current frame of the stack should be binary. s0^2 - s0 = 0, -/// s1^2 - s1 = 0. The top element is binary or not is enforced as a general constraint. +/// s1^2 - s1 = 0. The top element is binary or not is enforced as a general constraint. /// - The first element of the next frame should be a binary and of the first two elements in the /// current frame. s0` - s0 * s1 = 0. pub fn enforce_and_constraints( @@ -234,7 +234,7 @@ pub fn enforce_and_constraints( /// Enforces constraints of the OR operation. The OR operation computes the bitwise or of the /// first two elements in the current trace. Therefore, the following constraints are enforced: /// - The top two element in the current frame of the stack should be binary. s0^2 - s0 = 0, -/// s1^2 - s1 = 0. The top element is binary or not is enforced as a general constraint. +/// s1^2 - s1 = 0. The top element is binary or not is enforced as a general constraint. /// - The first element of the next frame should be a binary or of the first two elements in the /// current frame. s0` - ( s0 + s1 - s0 * s1 ) = 0. pub fn enforce_or_constraints( @@ -324,7 +324,7 @@ pub fn enforce_eqz_constraints( /// constraint. /// - The exp value in the next frame should be the square of exp value in the current frame. /// - The accumulation value in the next frame is the product of the accumulation value in the -/// current frame and the value which needs to be included in this turn. +/// current frame and the value which needs to be included in this turn. /// - The b value is right shifted by 1 bit. pub fn enforce_expacc_constraints( frame: &EvaluationFrame, diff --git a/air/src/constraints/stack/op_flags/mod.rs b/air/src/constraints/stack/op_flags/mod.rs index 8359917d8d..ce08893ffb 100644 --- a/air/src/constraints/stack/op_flags/mod.rs +++ b/air/src/constraints/stack/op_flags/mod.rs @@ -100,7 +100,7 @@ impl OpFlags { /// - composite flag for the stack if the stack has been shifted to the right. /// - composite flag if the current operation being executed is a control flow operation or not. /// - composite flag if the current operation being executed has a binary element constraint on - /// the top element in the stack. + /// the top element in the stack. pub fn new(frame: &EvaluationFrame) -> Self { // intermediary array to cache the value of intermediate flags. let mut degree7_op_flags = [E::ZERO; NUM_DEGREE_7_OPS]; diff --git a/air/src/constraints/stack/overflow/mod.rs b/air/src/constraints/stack/overflow/mod.rs index 346bba5906..4cc319711c 100644 --- a/air/src/constraints/stack/overflow/mod.rs +++ b/air/src/constraints/stack/overflow/mod.rs @@ -93,7 +93,7 @@ pub fn enforce_stack_depth_constraints( /// Enforces constraints on the overflow flag h0. Therefore, the following constraints /// are enforced: /// - If overflow table has values, then, h0 should be set to ONE, otherwise it should -/// be ZERO. +/// be ZERO. pub fn enforce_overflow_flag_constraints( frame: &EvaluationFrame, result: &mut [E], @@ -108,9 +108,9 @@ pub fn enforce_overflow_flag_constraints( /// Enforces constraints on the bookkeeping index `b1`. The following constraints are enforced: /// - In the case of a right shift operation, the next b1 index should be updated with current -/// `clk` value. +/// `clk` value. /// - In the case of a left shift operation, the last stack item should be set to ZERO when the -/// depth of the stack is 16. +/// depth of the stack is 16. pub fn enforce_overflow_index_constraints( frame: &EvaluationFrame, result: &mut [E], diff --git a/air/src/constraints/stack/stack_manipulation/mod.rs b/air/src/constraints/stack/stack_manipulation/mod.rs index ab32a8263c..0678fe615e 100644 --- a/air/src/constraints/stack/stack_manipulation/mod.rs +++ b/air/src/constraints/stack/stack_manipulation/mod.rs @@ -94,7 +94,7 @@ pub fn enforce_pad_constraints( /// at depth n in the stack and pushes the copy onto the stack, whereas MOVUPn opearation moves the /// element at depth n to the top of the stack. Therefore, the following constraints are enforced: /// - The top element in the next frame should be equal to the element at depth n in the -/// current frame. s0` - sn = 0. +/// current frame. s0` - sn = 0. pub fn enforce_dup_movup_n_constraints( frame: &EvaluationFrame, result: &mut [E], @@ -245,7 +245,7 @@ pub fn enforce_swapwx_constraints( /// Enforces constraints of the MOVDNn operation. The MOVDNn operation moves the top element /// to depth n in the stack. Therefore, the following constraints are enforced: /// - The top element in the current frame should be equal to the element at depth n in the -/// next frame. s0 - sn` = 0. +/// next frame. s0 - sn` = 0. pub fn enforce_movdnn_constraints( frame: &EvaluationFrame, result: &mut [E], diff --git a/air/src/constraints/stack/u32_ops/mod.rs b/air/src/constraints/stack/u32_ops/mod.rs index ffe7ee56e0..d04b4a75b1 100644 --- a/air/src/constraints/stack/u32_ops/mod.rs +++ b/air/src/constraints/stack/u32_ops/mod.rs @@ -120,7 +120,7 @@ pub fn enforce_u32split_constraints>( /// elements in the current trace of the stack. Therefore, the following constraints are /// enforced: /// - The aggregation of limbs from the helper registers is equal to the sum of the top two -/// element in the stack. +/// element in the stack. pub fn enforce_u32add_constraints>( frame: &EvaluationFrame, result: &mut [E], @@ -141,7 +141,7 @@ pub fn enforce_u32add_constraints>( /// elements in the current trace of the stack. Therefore, the following constraints are /// enforced: /// - The aggregation of limbs from the helper registers is equal to the sum of the top three -/// elements in the stack. +/// elements in the stack. pub fn enforce_u32add3_constraints>( frame: &EvaluationFrame, result: &mut [E], @@ -290,9 +290,9 @@ pub fn enforce_check_element_validity>( /// are aggregated correctly or not. Therefore, the following constraints are enforced: /// - The aggregation of lower two lower 16-bits limbs in the helper registers is equal to the /// second -/// element in the next row. +/// element in the next row. /// - The aggregation of lower two upper 16-bits limbs in the helper registers is equal to the first -/// element in the next row. +/// element in the next row. pub fn enforce_limbs_agg>( frame: &EvaluationFrame, result: &mut [E], diff --git a/assembly/src/assembler/mod.rs b/assembly/src/assembler/mod.rs index c8c6dc8229..09d21b2f76 100644 --- a/assembly/src/assembler/mod.rs +++ b/assembly/src/assembler/mod.rs @@ -77,12 +77,12 @@ pub enum ArtifactKind { /// /// /// * If you have a single executable module you want to compile, just call [Assembler::compile] or -/// [Assembler::compile_ast], depending on whether you have source code in raw or parsed form. +/// [Assembler::compile_ast], depending on whether you have source code in raw or parsed form. /// /// * If you want to link your executable to a few other modules that implement supporting -/// procedures, build the assembler with them first, using the various builder methods on -/// [Assembler], e.g. [Assembler::with_module], [Assembler::with_library], etc. Then, call -/// [Assembler::compile] or [Assembler::compile_ast] to get your compiled program. +/// procedures, build the assembler with them first, using the various builder methods on +/// [Assembler], e.g. [Assembler::with_module], [Assembler::with_library], etc. Then, call +/// [Assembler::compile] or [Assembler::compile_ast] to get your compiled program. pub struct Assembler { /// The global [ModuleGraph] for this assembler. All new [AssemblyContext]s inherit this graph /// as a baseline. diff --git a/assembly/src/assembler/module_graph/rewrites/module.rs b/assembly/src/assembler/module_graph/rewrites/module.rs index a4055f5a0d..51145e593b 100644 --- a/assembly/src/assembler/module_graph/rewrites/module.rs +++ b/assembly/src/assembler/module_graph/rewrites/module.rs @@ -18,8 +18,8 @@ use crate::{ /// added to a [ModuleGraph]. These rewrites include: /// /// * Resolving, at least partially, all of the invocation targets in procedures of the module, and -/// rewriting those targets as concretely as possible OR as phantom calls representing procedures -/// referenced by MAST root for which we have no definition. +/// rewriting those targets as concretely as possible OR as phantom calls representing procedures +/// referenced by MAST root for which we have no definition. pub struct ModuleRewriter<'a, 'b: 'a> { resolver: &'a NameResolver<'b>, module_id: ModuleIndex, diff --git a/assembly/src/ast/module.rs b/assembly/src/ast/module.rs index ffc85dd4f0..1a5b6af251 100644 --- a/assembly/src/ast/module.rs +++ b/assembly/src/ast/module.rs @@ -46,11 +46,11 @@ pub enum ModuleKind { /// A kernel is like a library module, but is special in a few ways: /// /// * Its code always executes in the root context, so it is stateful in a way that normal - /// libraries cannot replicate. This can be used to provide core services that would otherwise - /// not be possible to implement. + /// libraries cannot replicate. This can be used to provide core services that would otherwise + /// not be possible to implement. /// /// * The procedures exported from the kernel may be the target of the `syscall` instruction, - /// and in fact _must_ be called that way. + /// and in fact _must_ be called that way. /// /// * Kernels may not use `syscall` or `call` instructions internally. Kernel = 2, @@ -294,7 +294,7 @@ impl Module { /// /// * The module was constructed in-memory via AST structures, and not derived from source code. /// * The module was serialized without debug info, and then deserialized. Without debug info, - /// the source code is lost when round-tripping through serialization. + /// the source code is lost when round-tripping through serialization. pub fn source_file(&self) -> Option> { self.source_file.clone() } diff --git a/assembly/src/ast/visit.rs b/assembly/src/ast/visit.rs index af19ec4ba3..5c621e1687 100644 --- a/assembly/src/ast/visit.rs +++ b/assembly/src/ast/visit.rs @@ -22,16 +22,15 @@ //! of the visitor, but here are some examples: //! //! 1. When implementing a visitor that performs constant folding/propagation, you need to visit the -//! operands of an expression before the operator, in order to determine whether it is possible to -//! fold, and if so, what the actual values of the operands are. As a result, this is implemented as -//! a postorder visitor, so that the AST node corresponding to the expression is rewritten after all -//! of it's children. +//! operands of an expression before the operator, in order to determine whether it is possible +//! to fold, and if so, what the actual values of the operands are. As a result, this is +//! implemented as a postorder visitor, so that the AST node corresponding to the expression is +//! rewritten after all of it's children. //! //! 2. When implementing an analysis based on lexical scope, it is necessary to "push down" context -//! from -//! the root to the leaves of the AST - the context being the contents of each AST nodes inherited -//! scope. As a result, this is implemented as a preorder traversal, so that the context at each -//! node can be computed before visiting the children of that node. +//! from the root to the leaves of the AST - the context being the contents of each AST nodes +//! inherited scope. As a result, this is implemented as a preorder traversal, so that the +//! context at each node can be computed before visiting the children of that node. //! //! In both cases, the implementor must call the free function corresponding to the _current_ AST //! node at the appropriate point (i.e. before/after executing the logic for the node), so that the diff --git a/processor/src/chiplets/mod.rs b/processor/src/chiplets/mod.rs index 1a90f1801b..0a70095389 100644 --- a/processor/src/chiplets/mod.rs +++ b/processor/src/chiplets/mod.rs @@ -37,43 +37,44 @@ mod tests; /// chiplet selectors. /// /// The module's trace can be thought of as 5 stacked chiplet segments in the following form: -/// * Hasher segment: contains the trace and selector for the hasher chiplet * -/// This segment fills the first rows of the trace up to the length of the hasher `trace_len`. -/// - column 0: selector column with values set to ZERO -/// - columns 1-17: execution trace of hash chiplet +/// * Hasher segment: contains the trace and selector for the hasher chiplet.\ +/// This segment fills the first rows of the trace up to the length of the hasher `trace_len`. +/// - column 0: selector column with values set to ZERO +/// - columns 1-17: execution trace of hash chiplet /// -/// * Bitwise segment: contains the trace and selectors for the bitwise chiplet * -/// This segment begins at the end of the hasher segment and fills the next rows of the trace for -/// the `trace_len` of the bitwise chiplet. -/// - column 0: selector column with values set to ONE -/// - column 1: selector column with values set to ZERO -/// - columns 2-14: execution trace of bitwise chiplet -/// - columns 15-17: unused columns padded with ZERO +/// * Bitwise segment: contains the trace and selectors for the bitwise chiplet.\ +/// This segment begins at the end of the hasher segment and fills the next rows of the trace for +/// the `trace_len` of the bitwise chiplet. +/// - column 0: selector column with values set to ONE +/// - column 1: selector column with values set to ZERO +/// - columns 2-14: execution trace of bitwise chiplet +/// - columns 15-17: unused columns padded with ZERO /// -/// * Memory segment: contains the trace and selectors for the memory chiplet * -/// This segment begins at the end of the bitwise segment and fills the next rows of the trace for -/// the `trace_len` of the memory chiplet. -/// - column 0-1: selector columns with values set to ONE -/// - column 2: selector column with values set to ZERO -/// - columns 3-14: execution trace of memory chiplet -/// - columns 15-17: unused column padded with ZERO +/// * Memory segment: contains the trace and selectors for the memory chiplet.\ +/// This segment begins at the end of the bitwise segment and fills the next rows of the trace for +/// the `trace_len` of the memory chiplet. +/// - column 0-1: selector columns with values set to ONE +/// - column 2: selector column with values set to ZERO +/// - columns 3-14: execution trace of memory chiplet +/// - columns 15-17: unused column padded with ZERO /// -/// * Kernel ROM segment: contains the trace and selectors for the kernel ROM chiplet * -/// This segment begins at the end of the memory segment and fills the next rows of the trace for -/// the `trace_len` of the kernel ROM chiplet. -/// - column 0-2: selector columns with values set to ONE -/// - column 3: selector column with values set to ZERO -/// - columns 4-9: execution trace of kernel ROM chiplet -/// - columns 10-17: unused column padded with ZERO +/// * Kernel ROM segment: contains the trace and selectors for the kernel ROM chiplet.\ +/// This segment begins at the end of the memory segment and fills the next rows of the trace for +/// the `trace_len` of the kernel ROM chiplet. +/// - column 0-2: selector columns with values set to ONE +/// - column 3: selector column with values set to ZERO +/// - columns 4-9: execution trace of kernel ROM chiplet +/// - columns 10-17: unused column padded with ZERO /// -/// * Padding segment: unused * -/// This segment begins at the end of the kernel ROM segment and fills the rest of the execution -/// trace minus the number of random rows. When it finishes, the execution trace should have -/// exactly enough rows remaining for the specified number of random rows. -/// - columns 0-3: selector columns with values set to ONE -/// - columns 3-17: unused columns padded with ZERO +/// * Padding segment: unused.\ +/// This segment begins at the end of the kernel ROM segment and fills the rest of the execution +/// trace minus the number of random rows. When it finishes, the execution trace should have +/// exactly enough rows remaining for the specified number of random rows. +/// - columns 0-3: selector columns with values set to ONE +/// - columns 3-17: unused columns padded with ZERO /// /// The following is a pictorial representation of the chiplet module: +/// ```text /// +---+-------------------------------------------------------+-------------+ /// | 0 | | |-------------| /// | . | Hash chiplet | Hash chiplet |-------------| @@ -111,6 +112,7 @@ mod tests; /// | . | . | . | . |---------------------------------------------------------| /// | 1 | 1 | 1 | 1 |---------------------------------------------------------| /// +---+---+---+---+---------------------------------------------------------+ +/// ``` pub struct Chiplets { /// Current clock cycle of the VM. clk: u32, diff --git a/processor/src/decoder/mod.rs b/processor/src/decoder/mod.rs index 03f022fa64..98c814d2b0 100644 --- a/processor/src/decoder/mod.rs +++ b/processor/src/decoder/mod.rs @@ -309,7 +309,7 @@ where /// of these columns contains a single binary value, which together form a single opcode. /// * Hasher state columns h0 through h7. These are multi purpose columns used as follows: /// - When starting decoding of a new code block (e.g., via JOIN, SPLIT, LOOP, SPAN operations) -/// these columns are used for providing inputs for the current block's hash computations. +/// these columns are used for providing inputs for the current block's hash computations. /// - When finishing decoding of a code block (i.e., via END operation), these columns are used to /// record the result of the hash computation. /// - Inside a SPAN block, the first two columns are used to keep track of un-executed operations diff --git a/processor/src/host/advice/injectors/dsa.rs b/processor/src/host/advice/injectors/dsa.rs index 778d8e538b..be11d1bd6f 100644 --- a/processor/src/host/advice/injectors/dsa.rs +++ b/processor/src/host/advice/injectors/dsa.rs @@ -10,7 +10,7 @@ use super::super::{ExecutionError, Felt, Word}; /// 2. The expanded public key represented as the coefficients of a polynomial of degree < 512. /// 3. The signature represented as the coefficients of a polynomial of degree < 512. /// 4. The product of the above two polynomials in the ring of polynomials with coefficients -/// in the Miden field. +/// in the Miden field. /// /// # Errors /// Will return an error if either: diff --git a/processor/src/operations/comb_ops.rs b/processor/src/operations/comb_ops.rs index 16d91d50ee..5fa0c098b5 100644 --- a/processor/src/operations/comb_ops.rs +++ b/processor/src/operations/comb_ops.rs @@ -45,17 +45,17 @@ where /// Here: /// /// 1. Ti for i in 0..=7 stands for the the value of the i-th trace polynomial for the current - /// query i.e. T_i(x). + /// query i.e. T_i(x). /// 2. (p0, p1) stands for an extension field element accumulating the values for the quotients - /// with common denominator (x - z). + /// with common denominator (x - z). /// 3. (r0, r1) stands for an extension field element accumulating the values for the quotients - /// with common denominator (x - gz). + /// with common denominator (x - gz). /// 4. x_addr is the memory address from which we are loading the Ti's using the MSTREAM - /// instruction. + /// instruction. /// 5. z_addr is the memory address to the i-th OOD evaluations at z and gz - /// i.e. T_i(z):= (T_i(z)0, T_i(z)1) and T_i(gz):= (T_i(gz)0, T_i(gz)1). + /// i.e. T_i(z):= (T_i(z)0, T_i(z)1) and T_i(gz):= (T_i(gz)0, T_i(gz)1). /// 6. a_addr is the memory address of the i-th random element alpha_i used in batching - /// the trace polynomial quotients. + /// the trace polynomial quotients. /// /// The instruction also makes use of the helper registers to hold the values of T_i(z), T_i(gz) /// and alpha_i during the course of its execution. diff --git a/processor/src/operations/field_ops.rs b/processor/src/operations/field_ops.rs index b7ae264ffd..a2b4f5fdc6 100644 --- a/processor/src/operations/field_ops.rs +++ b/processor/src/operations/field_ops.rs @@ -171,16 +171,16 @@ where /// Computes a single turn of exp accumulation for the given inputs. The top 4 elements in the /// stack is arranged as follows (from the top): /// - least significant bit of the exponent in the previous trace if there's an expacc call, - /// otherwise ZERO + /// otherwise ZERO /// - exponent of base for this turn /// - accumulated power of base so far /// - number which needs to be shifted to the right /// /// To perform the operation we do the following: /// 1. Pops top three elements off the stack and calculate the least significant bit of the - /// number `b`. + /// number `b`. /// 2. Use this bit to decide if the current `base` raise to the power exponent needs to be - /// included in the accumulator. + /// included in the accumulator. /// 3. Update exponent with its square and the number b with one right shift. /// 4. Pushes the calcuted new values to the stack in the mentioned order. pub(super) fn op_expacc(&mut self) -> Result<(), ExecutionError> { diff --git a/processor/src/operations/io_ops.rs b/processor/src/operations/io_ops.rs index de3d9eca02..2f005fbfdb 100644 --- a/processor/src/operations/io_ops.rs +++ b/processor/src/operations/io_ops.rs @@ -149,8 +149,8 @@ where /// The operation works as follows: /// - The memory address is popped off the stack. /// - The top stack element is saved into the first element of the word located at the specified - /// memory address. The remaining 3 elements of the word are not affected. The element is not - /// removed from the stack. + /// memory address. The remaining 3 elements of the word are not affected. The element is not + /// removed from the stack. /// /// Thus, the net result of the operation is that the stack is shifted left by one item. /// diff --git a/processor/src/trace/utils.rs b/processor/src/trace/utils.rs index e321aaa344..a3f706c874 100644 --- a/processor/src/trace/utils.rs +++ b/processor/src/trace/utils.rs @@ -80,7 +80,7 @@ impl<'a> TraceFragment<'a> { /// - `main_trace_len` contains the length of the main trace. /// - `range_trace_len` contains the length of the range checker trace. /// - `chiplets_trace_len` contains the trace lengths of the all chiplets (hash, bitwise, memory, -/// kernel ROM) +/// kernel ROM) #[derive(Debug, Default, Eq, PartialEq, Clone, Copy)] pub struct TraceLenSummary { main_trace_len: usize, diff --git a/test-utils/src/lib.rs b/test-utils/src/lib.rs index 0bbc520c58..3b72a4fe44 100644 --- a/test-utils/src/lib.rs +++ b/test-utils/src/lib.rs @@ -167,7 +167,7 @@ macro_rules! assert_assembler_diagnostic { /// /// Types of failure tests: /// - Assembly error test: check that attempting to compile the given source causes an -/// AssemblyError which contains the specified substring. +/// AssemblyError which contains the specified substring. /// - Execution error test: check that running a program compiled from the given source causes an /// ExecutionError which contains the specified substring. pub struct Test { diff --git a/test-utils/src/test_builders.rs b/test-utils/src/test_builders.rs index bf49661935..4cc6fde43d 100644 --- a/test-utils/src/test_builders.rs +++ b/test-utils/src/test_builders.rs @@ -9,11 +9,11 @@ /// /// * `source`: a string of one or more operations, e.g. "push.1 push.2". /// * `stack_inputs` (optional): the initial inputs which must be at the top of the stack before -/// executing the `source`. Stack inputs can be provided independently without any advice inputs. +/// executing the `source`. Stack inputs can be provided independently without any advice inputs. /// * `advice_stack` (optional): the initial advice stack values. When provided, `stack_inputs` and -/// `merkle_store` are also expected. +/// `merkle_store` are also expected. /// * `merkle_store` (optional): the initial merkle set values. When provided, `stack_inputs` and -/// `advice_stack` are also expected. +/// `advice_stack` are also expected. #[macro_export] macro_rules! build_op_test { ($op_str:expr) => {{ @@ -34,11 +34,11 @@ macro_rules! build_op_test { /// /// * `source`: a well-formed source string. /// * `stack_inputs` (optional): the initial inputs which must be at the top of the stack before -/// executing the `source`. Stack inputs can be provided independently without any advice inputs. +/// executing the `source`. Stack inputs can be provided independently without any advice inputs. /// * `advice_stack` (optional): the initial advice stack values. When provided, `stack_inputs` and -/// `merkle_store` are also expected. +/// `merkle_store` are also expected. /// * `merkle_store` (optional): the initial merkle set values. When provided, `stack_inputs` and -/// `advice_stack` are also expected. +/// `advice_stack` are also expected. #[macro_export] macro_rules! build_test { ($($params:tt)+) => {{ @@ -54,11 +54,11 @@ macro_rules! build_test { /// /// * `source`: a well-formed source string. /// * `stack_inputs` (optional): the initial inputs which must be at the top of the stack before -/// executing the `source`. Stack inputs can be provided independently without any advice inputs. +/// executing the `source`. Stack inputs can be provided independently without any advice inputs. /// * `advice_stack` (optional): the initial advice stack values. When provided, `stack_inputs` and -/// `merkle_store` are also expected. +/// `merkle_store` are also expected. /// * `merkle_store` (optional): the initial merkle set values. When provided, `stack_inputs` and -/// `advice_stack` are also expected. +/// `advice_stack` are also expected. #[macro_export] macro_rules! build_debug_test { ($($params:tt)+) => {{ From b48edd613f6bf67b03c61d42046caf74fa3ff89a Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 28 Jun 2024 00:31:00 +0300 Subject: [PATCH 08/14] refactor: improve comments and docs --- stdlib/asm/crypto/hashes/rpo.masm | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/stdlib/asm/crypto/hashes/rpo.masm b/stdlib/asm/crypto/hashes/rpo.masm index 471f3c97bd..9f1a5610ca 100644 --- a/stdlib/asm/crypto/hashes/rpo.masm +++ b/stdlib/asm/crypto/hashes/rpo.masm @@ -101,7 +101,7 @@ export.hash_memory_words movup.4 drop movup.4 drop end -#! Computes hash of note inputs starting at the specified memory address. +#! Computes hash of Felt values starting at the specified memory address. #! #! If the number if inputs is 0, procedure returns the empty word: [ZERO, ZERO, ZERO, ZERO]. #! @@ -116,7 +116,7 @@ export.hash_memory u32divmod.8 swap # => [num_inputs/8, num_inputs%8, inputs_ptr] - # get the end_addr for hash_memory_even proc (end address for pairs of words) + # get the end_addr for hash_memory_even procedure (end address for pairs of words) mul.2 dup.2 add movup.2 # => [inputs_ptr, end_addr, num_inputs%8] @@ -132,7 +132,7 @@ export.hash_memory exec.absorb_double_words_from_memory # => [C', B', A', inputs_ptr', end_addr, num_inputs%8] where inputs_ptr' = end_addr - # hash remaining input values if there any left + # hash remaining input values if there are any left # if num_inputs%8 is not ZERO dup.14 push.0 neq if.true @@ -238,6 +238,9 @@ export.hash_memory # => [0, e_1_or_0, e_2_or_0, e_3_or_0, d_0_or_0, d_1_or_0, d_2_or_0, d_3, A'] # or in other words # => [C, B, A', ... ] + # notice that we don't need to check the d_3 value: entering the if.true branch means that + # we have number of elements not divisible by 8, so we will have at least one element to + # hash here (which turns out to be d_3) hperm # => [F, E, D] From b839e79a77b835d23ff754a75419b7e1876b5c78 Mon Sep 17 00:00:00 2001 From: Andrey Date: Fri, 28 Jun 2024 15:09:35 +0300 Subject: [PATCH 09/14] refactor: improve comments, add test, update changelog --- CHANGELOG.md | 1 + stdlib/asm/crypto/hashes/rpo.masm | 254 +++++++++++++++--------------- stdlib/docs/crypto/hashes/rpo.md | 2 +- stdlib/tests/crypto/rpo.rs | 69 +++++++- 4 files changed, 195 insertions(+), 131 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8718d8ab51..84c7ec2281 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ #### Stdlib - Added `init_no_padding` procedure to `std::crypto::hashes::native` (#1313). +- [BREAKING] `native` module was renamed to the `pro`, `hash_memory` procedure was renamed to the `hash_memory_words` (#1368). - Added `hash_memory` procedure to `std::crypto::hashes::rpo` (#1368). #### VM Internals diff --git a/stdlib/asm/crypto/hashes/rpo.masm b/stdlib/asm/crypto/hashes/rpo.masm index 9f1a5610ca..11e8916eea 100644 --- a/stdlib/asm/crypto/hashes/rpo.masm +++ b/stdlib/asm/crypto/hashes/rpo.masm @@ -103,152 +103,158 @@ end #! Computes hash of Felt values starting at the specified memory address. #! -#! If the number if inputs is 0, procedure returns the empty word: [ZERO, ZERO, ZERO, ZERO]. +#! This procedure divides the hashing process into two parts: hashing pairs of words using +#! `absorb_double_words_from_memory` procedure and hashing the remaining values using the `hperm` +#! instruction. #! -#! Inputs: [inputs_ptr, num_inputs] +#! Inputs: [ptr, num_elements] #! Outputs: [HASH] +#! Cycles: +#! - If number of elements divides by 8: 47 cycles + 3 * words +#! - Else: 180 cycles + 3 * words +#! +#! Panics if number of inputs equals 0. export.hash_memory # move number of inputs to the top of the stack swap - # => [num_inputs, inputs_ptr] + # => [num_elements, ptr] + + # check that number of inputs greater than 0 + dup eq.0 assertz + # => [num_elements, ptr] # get the number of double words u32divmod.8 swap - # => [num_inputs/8, num_inputs%8, inputs_ptr] + # => [num_elements/8, num_elements%8, ptr] # get the end_addr for hash_memory_even procedure (end address for pairs of words) mul.2 dup.2 add movup.2 - # => [inputs_ptr, end_addr, num_inputs%8] + # => [ptr, end_addr, num_elements%8] - # get the capacity element which is equal to num_inputs%8 + # get the capacity element which is equal to num_elements%8 dup.2 - # => [capacity, inputs_ptr, end_addr, num_inputs%8] + # => [capacity, ptr, end_addr, num_elements%8] # prepare hasher state for RPO permutation push.0.0.0 padw padw - # => [C, B, A, inputs_ptr, end_addr, num_inputs%8] + # => [C, B, A, ptr, end_addr, num_elements%8] # hash every pair of words exec.absorb_double_words_from_memory - # => [C', B', A', inputs_ptr', end_addr, num_inputs%8] where inputs_ptr' = end_addr + # => [C', B', A', ptr', end_addr, num_elements%8] where ptr' = end_addr # hash remaining input values if there are any left - # if num_inputs%8 is not ZERO - dup.14 push.0 neq + # if num_elements%8 is ZERO and there are no elements to hash + dup.14 eq.0 if.true - # load the remaining double word - mem_stream - # => [E, D, A', inputs_ptr'+2, end_addr, num_inputs%8] - - # clean the stack - movup.12 drop movup.12 drop - # => [E, D, A', num_inputs%8] - - # get the number of elements we need to drop - # notice that drop_counter could be any number from 1 to 7 - push.8 movup.13 sub movdn.12 - # => [E, D, A', drop_counter] - - ### 0th value ######################################################## - - # we need to drop first value anyway, since number of values is not divisible by 8 - drop - # => [e_1, e_2, e_3, d_0, d_1, d_2, d_3, A', drop_counter] - - # push the padding 0 value - push.0 - # => [0, e_1, e_2, e_3, d_0, d_1, d_2, d_3, A', drop_counter] - - # move the calculated value down the stack - movdn.6 - # => [e_1, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] - - ### 1st value ######################################################## - - # prepare the second element of the E Word (e_1) for cdrop instruction - push.0 swap - # => [e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] - - # push latch variable onto the stack; this will be the control for the cdrop instruction - push.0 - # => [latch = 0, e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] - - # get the flag whether the drop counter is equal 1 - dup.14 eq.1 - # => [drop_counter == 1, latch = 0, e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] - - # update the latch: if drop_counter == 1, latch will become 1 - or - # => [latch', e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', drop_counter] - - # save the latch value - dup movdn.14 - # => [latch', e_1, 0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', latch', drop_counter] - - # if latch == 1, drop 0; otherwise drop e_1 - cdrop - # => [e_1_or_0, e_2, e_3, d_0, d_1, d_2, 0, d_3, A', latch', drop_counter] - - # move the calculated value down the stack - movdn.6 - # => [e_2, e_3, d_0, d_1, d_2, 0, e_1_or_0, d_3, A', latch', drop_counter] - - ### 2nd value ######################################################## - - # repeat the above process but now compare drop_counter to 2 - push.0 swap - movup.13 dup.14 eq.2 or - dup movdn.14 - cdrop movdn.6 - # => [e_3, d_0, d_1, d_2, 0, e_1_or_0, e_2_or_0, d_3, A', latch', drop_counter] - - ### 3rd value ######################################################## - - # repeat the above process but now compare drop_counter to 3 - push.0 swap - movup.13 dup.14 eq.3 or - dup movdn.14 - cdrop movdn.6 - # => [d_0, d_1, d_2, 0, e_1_or_0, e_2_or_0, e_3_or_0, d_3, A', latch', drop_counter] - - ### 4th value ######################################################## - - # repeat the above process but now compare drop_counter to 4 - push.0 swap - movup.13 dup.14 eq.4 or - dup movdn.14 - cdrop movdn.6 - # => [d_1, d_2, 0, e_1_or_0, e_2_or_0, e_3_or_0, d_0_or_0, d_3, A', latch', drop_counter] - - ### 5th value ######################################################## - - # repeat the above process but now compare drop_counter to 5 - push.0 swap - movup.13 dup.14 eq.5 or - dup movdn.14 - cdrop movdn.6 - # => [d_2, 0, e_1_or_0, e_2_or_0, e_3_or_0, d_0_or_0, d_1_or_0, d_3, A', latch', drop_counter] - - ### 6th value ######################################################## - - # repeat the above process but now compare drop_counter to 6 - push.0 swap - movup.13 movup.14 eq.6 or - cdrop movdn.6 - # => [0, e_1_or_0, e_2_or_0, e_3_or_0, d_0_or_0, d_1_or_0, d_2_or_0, d_3, A'] - # or in other words - # => [C, B, A', ... ] - # notice that we don't need to check the d_3 value: entering the if.true branch means that - # we have number of elements not divisible by 8, so we will have at least one element to - # hash here (which turns out to be d_3) - - hperm - # => [F, E, D] - - exec.squeeze_digest - # => [E] + # clean the stack + exec.squeeze_digest + swapw dropw + # => [B'] else - dropw movdnw.2 dropw dropw - # => [B'] + # load the remaining double word + mem_stream + # => [E, D, A', ptr'+2, end_addr, num_elements%8] + + # clean the stack + movup.12 drop movup.12 drop + # => [E, D, A', num_elements%8] + + # get the number of elements we need to drop + # notice that drop_counter could be any number from 1 to 7 + push.8 movup.13 sub movdn.12 + # => [E, D, A', drop_counter] + + ### 0th value ######################################################## + + # we need to drop first value anyway, since number of values is not divisible by 8 + # push the padding 0 on to the stack and move it down to the 6th position + drop push.0 movdn.6 + # => [e_2, e_1, e_0, d_3, d_2, d_1, 0, d_0, A', drop_counter] + + ### 1st value ######################################################## + + # prepare the second element of the E Word for cdrop instruction + push.0 swap + # => [e_2, 0, e_1, e_0, d_3, d_2, d_1, 0, d_0, A', drop_counter] + + # push latch variable onto the stack; this will be the control for the cdrop instruction + push.0 + # => [latch = 0, e_2, 0, e_1, e_0, d_3, d_2, d_1, 0, d_0, A', drop_counter] + + # get the flag whether the drop counter is equal 1 + dup.14 eq.1 + # => [drop_counter == 1, latch = 0, e_2, 0, e_1, e_0, d_3, d_2, d_1, 0, d_0, A', drop_counter] + + # update the latch: if drop_counter == 1, latch will become 1 + or + # => [latch', e_2, 0, e_1, e_0, d_3, d_2, d_1, 0, d_0, A', drop_counter] + + # save the latch value + dup movdn.14 + # => [latch', e_2, 0, e_1, e_0, d_3, d_2, d_1, 0, d_0, A', latch', drop_counter] + + # if latch == 1, drop 0; otherwise drop e_1 + cdrop + # => [e_2_or_0, e_1, e_0, d_3, d_2, d_1, 0, d_0, A', latch', drop_counter] + + # move the calculated value down the stack + movdn.6 + # => [e_1, e_0, d_3, d_2, d_1, 0, e_2_or_0, d_0, A', latch', drop_counter] + + ### 2nd value ######################################################## + + # repeat the above process but now compare drop_counter to 2 + push.0 swap + movup.13 dup.14 eq.2 or + dup movdn.14 + cdrop movdn.6 + # => [e_0, d_3, d_2, d_1, 0, e_2_or_0, e_1_or_0, d_0, A', latch', drop_counter] + + ### 3rd value ######################################################## + + # repeat the above process but now compare drop_counter to 3 + push.0 swap + movup.13 dup.14 eq.3 or + dup movdn.14 + cdrop movdn.6 + # => [d_3, d_2, d_1, 0, e_2_or_0, e_1_or_0, e_0_or_0, d_0, A', latch', drop_counter] + + ### 4th value ######################################################## + + # repeat the above process but now compare drop_counter to 4 + push.0 swap + movup.13 dup.14 eq.4 or + dup movdn.14 + cdrop movdn.6 + # => [d_2, d_1, 0, e_2_or_0, e_1_or_0, e_0_or_0, d_3_or_0, d_0, A', latch', drop_counter] + + ### 5th value ######################################################## + + # repeat the above process but now compare drop_counter to 5 + push.0 swap + movup.13 dup.14 eq.5 or + dup movdn.14 + cdrop movdn.6 + # => [d_1, 0, e_2_or_0, e_1_or_0, e_0_or_0, d_3_or_0, d_2_or_0, d_0, A', latch', drop_counter] + + ### 6th value ######################################################## + + # repeat the above process but now compare drop_counter to 6 + push.0 swap + movup.13 movup.14 eq.6 or + cdrop movdn.6 + # => [0, e_2_or_0, e_1_or_0, e_0_or_0, d_3_or_0, d_2_or_0, d_1_or_0, d_0, A'] + # or in other words + # => [C, B, A', ... ] + # notice that we don't need to check the d_0 value: entering the else branch means that + # we have number of elements not divisible by 8, so we will have at least one element to + # hash here (which turns out to be d_0) + + hperm + # => [F, E, D] + + exec.squeeze_digest + # => [E] end end \ No newline at end of file diff --git a/stdlib/docs/crypto/hashes/rpo.md b/stdlib/docs/crypto/hashes/rpo.md index cafe2d96e5..da22de54cc 100644 --- a/stdlib/docs/crypto/hashes/rpo.md +++ b/stdlib/docs/crypto/hashes/rpo.md @@ -5,4 +5,4 @@ Prepares the top of the stack with the hasher initial state.

This pro | squeeze_digest | Given the hasher state, returns the hash output.

Input: [C, B, A, ...]
Ouptut: [HASH, ...]
where: For the native RPO hasher HASH is B.
Cycles: 9
| | absorb_double_words_from_memory | Hashes the memory `start_addr` to `end_addr` given an RPO state specified by 3 words.

This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite
loop. `end_addr` is not inclusive.

Stack transition:
Input: [C, B, A, start_addr, end_addr, ...]
Output: [C', B', A', end_addr, end_addr ...]
Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1`

Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output.
| | hash_memory_words | Hashes the memory `start_addr` to `end_addr`, handles odd number of elements.

Requires `start_addr < end_addr`, `end_addr` is not inclusive.

Stack transition:
Input: [start_addr, end_addr, ...]
Output: [H, ...]
Cycles:
even words: 49 cycles + 3 * words
odd words: 61 cycles + 3 * words
| -| hash_memory | Computes hash of note inputs starting at the specified memory address.

If the number if inputs is 0, procedure returns the empty word: [ZERO, ZERO, ZERO, ZERO].

Inputs: [inputs_ptr, num_inputs]
Outputs: [HASH]
| +| hash_memory | Computes hash of Felt values starting at the specified memory address.

This procedure divides the hashing process into two parts: hashing pairs of words using
`absorb_double_words_from_memory` procedure and hashing the remaining values using the `hperm`
instruction.

Inputs: [ptr, num_elements]
Outputs: [HASH]
Cycles:
- If number of elements divides by 8: 47 cycles + 3 * words
- Else: 180 cycles + 3 * words

Panics if number of inputs equals 0.
| diff --git a/stdlib/tests/crypto/rpo.rs b/stdlib/tests/crypto/rpo.rs index 3c7bd7244b..d8c920f510 100644 --- a/stdlib/tests/crypto/rpo.rs +++ b/stdlib/tests/crypto/rpo.rs @@ -277,7 +277,48 @@ fn test_squeeze_digest() { #[test] fn test_hash_memory() { - let compute_inputs_hash = " + // hash fewer than 8 elements + let compute_inputs_hash_5 = " + use.std::crypto::hashes::rpo + + begin + push.1.2.3.4.1000 mem_storew dropw + push.5.0.0.0.1001 mem_storew dropw + + push.5.1000 + + exec.rpo::hash_memory + end + "; + + #[rustfmt::skip] + let expected_hash: Vec = build_expected_hash(&[ + 1, 2, 3, 4, 5 + ]).into_iter().map(|e| e.as_int()).collect(); + build_test!(compute_inputs_hash_5, &[]).expect_stack(&expected_hash); + + // hash exactly 8 elements + let compute_inputs_hash_8 = " + use.std::crypto::hashes::rpo + + begin + push.1.2.3.4.1000 mem_storew dropw + push.5.6.7.8.1001 mem_storew dropw + + push.8.1000 + + exec.rpo::hash_memory + end + "; + + #[rustfmt::skip] + let expected_hash: Vec = build_expected_hash(&[ + 1, 2, 3, 4, 5, 6, 7, 8 + ]).into_iter().map(|e| e.as_int()).collect(); + build_test!(compute_inputs_hash_8, &[]).expect_stack(&expected_hash); + + // hash more than 8 elements + let compute_inputs_hash_15 = " use.std::crypto::hashes::rpo begin @@ -286,18 +327,34 @@ fn test_hash_memory() { push.9.10.11.12.1002 mem_storew dropw push.13.14.15.0.1003 mem_storew dropw - push.15.1000 - ####################################################### - exec.rpo::hash_memory end "; #[rustfmt::skip] let expected_hash: Vec = build_expected_hash(&[ - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 + 1, 2, 3, 4, + 5, 6, 7, 8, + 9, 10, 11, 12, + 13, 14, 15 ]).into_iter().map(|e| e.as_int()).collect(); - build_test!(compute_inputs_hash, &[]).expect_stack(&expected_hash); + build_test!(compute_inputs_hash_15, &[]).expect_stack(&expected_hash); +} + +#[test] +fn test_hash_memory_fail() { + // try to hash 0 values + let compute_inputs_hash = " + use.std::crypto::hashes::rpo + + begin + push.0.1000 + + exec.rpo::hash_memory + end + "; + + assert!(build_test!(compute_inputs_hash, &[]).execute().is_err()); } From fd05155d7430ff0ca4c25cdd8f8c3f55df577fbc Mon Sep 17 00:00:00 2001 From: Andrey Date: Sat, 29 Jun 2024 00:37:33 +0300 Subject: [PATCH 10/14] fix: fix the error cleaning --- stdlib/asm/crypto/hashes/rpo.masm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/stdlib/asm/crypto/hashes/rpo.masm b/stdlib/asm/crypto/hashes/rpo.masm index 11e8916eea..9b8a3457db 100644 --- a/stdlib/asm/crypto/hashes/rpo.masm +++ b/stdlib/asm/crypto/hashes/rpo.masm @@ -149,7 +149,7 @@ export.hash_memory if.true # clean the stack exec.squeeze_digest - swapw dropw + swapw drop drop drop movdn.4 # => [B'] else # load the remaining double word From 98ca1ce3f61b946e7b55fd3073081e118fab41ea Mon Sep 17 00:00:00 2001 From: Andrey Date: Mon, 1 Jul 2024 02:01:59 +0300 Subject: [PATCH 11/14] test: check that other stack values stays unchanged --- stdlib/tests/crypto/rpo.rs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/stdlib/tests/crypto/rpo.rs b/stdlib/tests/crypto/rpo.rs index d8c920f510..d00da8fefc 100644 --- a/stdlib/tests/crypto/rpo.rs +++ b/stdlib/tests/crypto/rpo.rs @@ -284,6 +284,7 @@ fn test_hash_memory() { begin push.1.2.3.4.1000 mem_storew dropw push.5.0.0.0.1001 mem_storew dropw + push.11 push.5.1000 @@ -292,9 +293,11 @@ fn test_hash_memory() { "; #[rustfmt::skip] - let expected_hash: Vec = build_expected_hash(&[ + let mut expected_hash: Vec = build_expected_hash(&[ 1, 2, 3, 4, 5 ]).into_iter().map(|e| e.as_int()).collect(); + // make sure that value `11` stays unchanged + expected_hash.push(11); build_test!(compute_inputs_hash_5, &[]).expect_stack(&expected_hash); // hash exactly 8 elements @@ -304,6 +307,7 @@ fn test_hash_memory() { begin push.1.2.3.4.1000 mem_storew dropw push.5.6.7.8.1001 mem_storew dropw + push.11 push.8.1000 @@ -312,9 +316,11 @@ fn test_hash_memory() { "; #[rustfmt::skip] - let expected_hash: Vec = build_expected_hash(&[ + let mut expected_hash: Vec = build_expected_hash(&[ 1, 2, 3, 4, 5, 6, 7, 8 ]).into_iter().map(|e| e.as_int()).collect(); + // make sure that value `11` stays unchanged + expected_hash.push(11); build_test!(compute_inputs_hash_8, &[]).expect_stack(&expected_hash); // hash more than 8 elements @@ -326,6 +332,7 @@ fn test_hash_memory() { push.5.6.7.8.1001 mem_storew dropw push.9.10.11.12.1002 mem_storew dropw push.13.14.15.0.1003 mem_storew dropw + push.11 push.15.1000 @@ -334,12 +341,14 @@ fn test_hash_memory() { "; #[rustfmt::skip] - let expected_hash: Vec = build_expected_hash(&[ + let mut expected_hash: Vec = build_expected_hash(&[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 ]).into_iter().map(|e| e.as_int()).collect(); + // make sure that value `11` stays unchanged + expected_hash.push(11); build_test!(compute_inputs_hash_15, &[]).expect_stack(&expected_hash); } From 4cf59b682321063232685c5ee2af0f4aa666f4ed Mon Sep 17 00:00:00 2001 From: Andrey Date: Tue, 1 Oct 2024 13:27:53 +0300 Subject: [PATCH 12/14] refactor: impl test for empty inputs, update procedure docs, fix typo in changelog --- CHANGELOG.md | 2 +- stdlib/asm/crypto/hashes/rpo.masm | 30 +++++++++++++++++------------- stdlib/tests/crypto/rpo.rs | 4 ++-- 3 files changed, 20 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e53a69d70..788623c9fe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -158,7 +158,7 @@ #### Stdlib - Added `init_no_padding` procedure to `std::crypto::hashes::native` (#1313). -- [BREAKING] `native` module was renamed to the `pro`, `hash_memory` procedure was renamed to the `hash_memory_words` (#1368). +- [BREAKING] `native` module was renamed to the `rpo`, `hash_memory` procedure was renamed to the `hash_memory_words` (#1368). - Added `hash_memory` procedure to `std::crypto::hashes::rpo` (#1368). #### VM Internals diff --git a/stdlib/asm/crypto/hashes/rpo.masm b/stdlib/asm/crypto/hashes/rpo.masm index c852de82a7..b0357d50c5 100644 --- a/stdlib/asm/crypto/hashes/rpo.masm +++ b/stdlib/asm/crypto/hashes/rpo.masm @@ -5,6 +5,7 @@ #! #! Input: [] #! Ouptut: [PERM, PERM, PERM, ...] +#! #! Cycles: 12 export.init_no_padding padw padw padw @@ -14,7 +15,11 @@ end #! #! Input: [C, B, A, ...] #! Ouptut: [HASH, ...] -#! where: For the native RPO hasher HASH is B. +#! +#! Where : +#! - `A` is the capacity word that will be used by the hashing function. +#! - `B` is the hash output. +#! #! Cycles: 9 export.squeeze_digest # drop the first rate word (4 cycles) @@ -32,12 +37,14 @@ end #! This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite #! loop. `end_addr` is not inclusive. #! -#! Stack transition: #! Input: [C, B, A, start_addr, end_addr, ...] #! Output: [C', B', A', end_addr, end_addr ...] -#! Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1` #! -#! Where `A` is the capacity word that will be used by the hashing function, and `B'` the hash output. +#! Where : +#! - `A` is the capacity word that will be used by the hashing function. +#! - `B` is the hash output. +#! +#! Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1` export.absorb_double_words_from_memory dup.13 dup.13 neq # (4 cycles ) while.true @@ -50,12 +57,13 @@ end #! #! Requires `start_addr < end_addr`, `end_addr` is not inclusive. #! -#! Stack transition: #! Input: [start_addr, end_addr, ...] #! Output: [H, ...] +#! #! Cycles: -#! even words: 49 cycles + 3 * words -#! odd words: 61 cycles + 3 * words +#! - even words: 49 cycles + 3 * words +#! - odd words: 61 cycles + 3 * words +#! where `words` is the `start_addr - end_addr - 1` export.hash_memory_words # enforce `start_addr < end_addr` dup.1 dup.1 u32assert2 u32gt assert @@ -109,20 +117,16 @@ end #! #! Inputs: [ptr, num_elements] #! Outputs: [HASH] +#! #! Cycles: #! - If number of elements divides by 8: 47 cycles + 3 * words #! - Else: 180 cycles + 3 * words -#! -#! Panics if number of inputs equals 0. +#! where `words` is the number of quads of input values. export.hash_memory # move number of inputs to the top of the stack swap # => [num_elements, ptr] - # check that number of inputs greater than 0 - dup eq.0 assertz - # => [num_elements, ptr] - # get the number of double words u32divmod.8 swap # => [num_elements/8, num_elements%8, ptr] diff --git a/stdlib/tests/crypto/rpo.rs b/stdlib/tests/crypto/rpo.rs index fcc86e9c34..b1eac29e1d 100644 --- a/stdlib/tests/crypto/rpo.rs +++ b/stdlib/tests/crypto/rpo.rs @@ -353,7 +353,7 @@ fn test_hash_memory() { } #[test] -fn test_hash_memory_fail() { +fn test_hash_memory_empty() { // try to hash 0 values let compute_inputs_hash = " use.std::crypto::hashes::rpo @@ -365,5 +365,5 @@ fn test_hash_memory_fail() { end "; - assert!(build_test!(compute_inputs_hash, &[]).execute().is_err()); + build_test!(compute_inputs_hash, &[]).expect_stack(&[0; 16]); } From b84ae421cd430a039bb505f473890436376ba83c Mon Sep 17 00:00:00 2001 From: Andrey Date: Wed, 9 Oct 2024 20:51:40 +0300 Subject: [PATCH 13/14] refactor: update doc comments, add test for empty input --- stdlib/asm/crypto/hashes/rpo.masm | 36 +++++++++--------- stdlib/tests/crypto/rpo.rs | 63 +++++++++++++++++++------------ 2 files changed, 57 insertions(+), 42 deletions(-) diff --git a/stdlib/asm/crypto/hashes/rpo.masm b/stdlib/asm/crypto/hashes/rpo.masm index b0357d50c5..1035fa464d 100644 --- a/stdlib/asm/crypto/hashes/rpo.masm +++ b/stdlib/asm/crypto/hashes/rpo.masm @@ -34,8 +34,8 @@ end #! Hashes the memory `start_addr` to `end_addr` given an RPO state specified by 3 words. #! -#! This requires that `end_addr=start_addr + 2n + 1`, otherwise the procedure will enter an infinite -#! loop. `end_addr` is not inclusive. +#! This requires that `end_addr = start_addr + 2n` where n = {0, 1, 2 ...}, otherwise the procedure +#! will enter an infinite loop. #! #! Input: [C, B, A, start_addr, end_addr, ...] #! Output: [C', B', A', end_addr, end_addr ...] @@ -44,7 +44,7 @@ end #! - `A` is the capacity word that will be used by the hashing function. #! - `B` is the hash output. #! -#! Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr - 1` +#! Cycles: 4 + 3 * words, where `words` is the `start_addr - end_addr` export.absorb_double_words_from_memory dup.13 dup.13 neq # (4 cycles ) while.true @@ -55,7 +55,7 @@ end #! Hashes the memory `start_addr` to `end_addr`, handles odd number of elements. #! -#! Requires `start_addr < end_addr`, `end_addr` is not inclusive. +#! Requires `start_addr ≤ end_addr`, `end_addr` is not inclusive. #! #! Input: [start_addr, end_addr, ...] #! Output: [H, ...] @@ -65,48 +65,50 @@ end #! - odd words: 61 cycles + 3 * words #! where `words` is the `start_addr - end_addr - 1` export.hash_memory_words - # enforce `start_addr < end_addr` - dup.1 dup.1 u32assert2 u32gt assert + # enforce `start_addr ≤ end_addr` + dup.1 dup.1 u32assert2 u32gte assert # figure out if the range is for an odd number of words (9 cycles) dup.1 dup.1 sub is_odd - # stack: [is_odd, start_addr, end_addr, ...] + # => [is_odd, start_addr, end_addr, ...] # make the start/end range even (4 cycles) movup.2 dup.1 sub - # stack: [end_addr, is_odd, start_addr, ...] + # => [end_addr, is_odd, start_addr, ...] # move start_addr to the right stack position (1 cycles) movup.2 - # stack: [start_addr, end_addr, is_odd, ...] + # => [start_addr, end_addr, is_odd, ...] # prepare hasher state (14 cycles) dup.2 mul.4 push.0.0.0 padw padw - # stack: [C, B, A, start_addr, end_addr, is_odd, ...] + # => [C, B, A, start_addr, end_addr, is_odd, ...] # (4 + 3 * words cycles) exec.absorb_double_words_from_memory + # => [C', B', A', end_addr, end_addr, is_odd, ...] # (1 cycles) movup.14 + # => [is_odd, C', B', A', end_addr, end_addr, ...] # handle the odd element, if any (12 cycles) if.true - # start_addr and end_addr are equal after calling `absorb_double_words_from_memory`, and both point - # to the last element. Load the last word (6 cycles) + # start_addr and end_addr are equal after calling `absorb_double_words_from_memory`, and both + # point to the last element. Load the last word (6 cycles) dropw dup.9 mem_loadw + # => [D, A', end_addr, end_addr, ...] - # set the padding (4 cycles) - padw - - # (1 cycles) - hperm + # set the padding and compute the permutation (5 cycles) + padw hperm end exec.squeeze_digest + # => [HASH, end_addr, end_addr, ...] # drop start_addr/end_addr (4 cycles) movup.4 drop movup.4 drop + # => [HASH] end #! Computes hash of Felt values starting at the specified memory address. diff --git a/stdlib/tests/crypto/rpo.rs b/stdlib/tests/crypto/rpo.rs index b1eac29e1d..affc6d9d9c 100644 --- a/stdlib/tests/crypto/rpo.rs +++ b/stdlib/tests/crypto/rpo.rs @@ -23,27 +23,6 @@ fn test_invalid_end_addr() { err_msg: None, } ); - - // address range can not contain zero elements - let empty_range = " - use.std::crypto::hashes::rpo - - begin - push.1000 # end address - push.1000 # start address - - exec.rpo::hash_memory_words - end - "; - let test = build_test!(empty_range, &[]); - expect_exec_error!( - test, - ExecutionError::FailedAssertion { - clk: 18.into(), - err_code: 0, - err_msg: None, - } - ); } #[test] @@ -354,16 +333,50 @@ fn test_hash_memory() { #[test] fn test_hash_memory_empty() { - // try to hash 0 values - let compute_inputs_hash = " + // absorb_double_words_from_memory + let source = " + use.std::crypto::hashes::rpo + + begin + push.1000 # end address + push.1000 # start address + padw padw padw # hasher state + + exec.rpo::absorb_double_words_from_memory + end + "; + + let mut expected_stack = vec![0; 12]; + expected_stack.push(1000); + expected_stack.push(1000); + + build_test!(source, &[]).expect_stack(&expected_stack); + + // hash_memory_words + let source = " + use.std::crypto::hashes::rpo + + begin + push.1000 # end address + push.1000 # start address + + exec.rpo::hash_memory_words + end + "; + + build_test!(source, &[]).expect_stack(&[0; 4]); + + // hash_memory + let source = " use.std::crypto::hashes::rpo begin - push.0.1000 + push.0 # number of elements to hash + push.1000 # start address exec.rpo::hash_memory end "; - build_test!(compute_inputs_hash, &[]).expect_stack(&[0; 16]); + build_test!(source, &[]).expect_stack(&[0; 16]); } From bc565fa12d4f1f3fba959f1c46f9ea0eb25a5cf7 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 10 Oct 2024 01:00:30 +0300 Subject: [PATCH 14/14] refactor: fix clippy errors --- assembly/src/assembler/basic_block_builder.rs | 8 ++++---- assembly/src/assembler/module_graph/debug.rs | 8 ++++---- assembly/src/assembler/module_graph/mod.rs | 2 +- assembly/src/ast/attribute/set.rs | 4 ++-- assembly/src/ast/visit.rs | 4 ++-- assembly/src/compile.rs | 12 ++++++------ assembly/src/library/path.rs | 10 +++++----- assembly/src/parser/mod.rs | 2 +- assembly/src/parser/token.rs | 2 +- assembly/src/sema/passes/const_eval.rs | 4 ++-- assembly/src/sema/passes/verify_invoke.rs | 4 ++-- core/src/mast/node/basic_block_node/mod.rs | 4 ++-- core/src/mast/node/call_node.rs | 6 +++--- core/src/mast/node/dyn_node.rs | 6 +++--- core/src/mast/node/external.rs | 6 +++--- core/src/mast/node/join_node.rs | 4 ++-- core/src/mast/node/loop_node.rs | 4 ++-- core/src/mast/node/mod.rs | 4 ++-- core/src/mast/node/split_node.rs | 4 ++-- core/src/mast/serialization/basic_blocks.rs | 2 +- processor/src/host/advice/mod.rs | 2 +- processor/src/host/mod.rs | 2 +- prover/src/gpu/metal/mod.rs | 2 +- 23 files changed, 53 insertions(+), 53 deletions(-) diff --git a/assembly/src/assembler/basic_block_builder.rs b/assembly/src/assembler/basic_block_builder.rs index 1113e1fead..3246484d21 100644 --- a/assembly/src/assembler/basic_block_builder.rs +++ b/assembly/src/assembler/basic_block_builder.rs @@ -60,7 +60,7 @@ impl<'a> BasicBlockBuilder<'a> { } /// Accessors -impl<'a> BasicBlockBuilder<'a> { +impl BasicBlockBuilder<'_> { /// Returns a reference to the internal [`MastForestBuilder`]. pub fn mast_forest_builder(&self) -> &MastForestBuilder { self.mast_forest_builder @@ -73,7 +73,7 @@ impl<'a> BasicBlockBuilder<'a> { } /// Operations -impl<'a> BasicBlockBuilder<'a> { +impl BasicBlockBuilder<'_> { /// Adds the specified operation to the list of basic block operations. pub fn push_op(&mut self, op: Operation) { self.ops.push(op); @@ -96,7 +96,7 @@ impl<'a> BasicBlockBuilder<'a> { } /// Decorators -impl<'a> BasicBlockBuilder<'a> { +impl BasicBlockBuilder<'_> { /// Add the specified decorator to the list of basic block decorators. pub fn push_decorator(&mut self, decorator: Decorator) -> Result<(), AssemblyError> { let decorator_id = self.mast_forest_builder.ensure_decorator(decorator)?; @@ -159,7 +159,7 @@ impl<'a> BasicBlockBuilder<'a> { } /// Span Constructors -impl<'a> BasicBlockBuilder<'a> { +impl BasicBlockBuilder<'_> { /// Creates and returns a new basic block node from the operations and decorators currently in /// this builder. /// diff --git a/assembly/src/assembler/module_graph/debug.rs b/assembly/src/assembler/module_graph/debug.rs index bf584fad1b..eea58adf48 100644 --- a/assembly/src/assembler/module_graph/debug.rs +++ b/assembly/src/assembler/module_graph/debug.rs @@ -14,7 +14,7 @@ impl fmt::Debug for ModuleGraph { #[doc(hidden)] struct DisplayModuleGraph<'a>(&'a ModuleGraph); -impl<'a> fmt::Debug for DisplayModuleGraph<'a> { +impl fmt::Debug for DisplayModuleGraph<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_set() .entries(self.0.modules.iter().enumerate().flat_map(|(module_index, m)| { @@ -56,7 +56,7 @@ impl<'a> fmt::Debug for DisplayModuleGraph<'a> { #[doc(hidden)] struct DisplayModuleGraphNodes<'a>(&'a Vec); -impl<'a> fmt::Debug for DisplayModuleGraphNodes<'a> { +impl fmt::Debug for DisplayModuleGraphNodes<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_list() .entries(self.0.iter().enumerate().flat_map(|(module_index, m)| { @@ -111,7 +111,7 @@ struct DisplayModuleGraphNode<'a> { ty: GraphNodeType, } -impl<'a> fmt::Debug for DisplayModuleGraphNode<'a> { +impl fmt::Debug for DisplayModuleGraphNode<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Node") .field("id", &format_args!("{}:{}", &self.module.as_usize(), &self.index.as_usize())) @@ -128,7 +128,7 @@ struct DisplayModuleGraphNodeWithEdges<'a> { out_edges: &'a [GlobalProcedureIndex], } -impl<'a> fmt::Debug for DisplayModuleGraphNodeWithEdges<'a> { +impl fmt::Debug for DisplayModuleGraphNodeWithEdges<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("Edge") .field( diff --git a/assembly/src/assembler/module_graph/mod.rs b/assembly/src/assembler/module_graph/mod.rs index c96617a314..f8116f9985 100644 --- a/assembly/src/assembler/module_graph/mod.rs +++ b/assembly/src/assembler/module_graph/mod.rs @@ -39,7 +39,7 @@ pub enum ProcedureWrapper<'a> { Info(&'a ProcedureInfo), } -impl<'a> ProcedureWrapper<'a> { +impl ProcedureWrapper<'_> { /// Returns the name of the procedure. pub fn name(&self) -> &ProcedureName { match self { diff --git a/assembly/src/ast/attribute/set.rs b/assembly/src/ast/attribute/set.rs index bbf69698a5..f215f96db0 100644 --- a/assembly/src/ast/attribute/set.rs +++ b/assembly/src/ast/attribute/set.rs @@ -197,7 +197,7 @@ pub struct AttributeSetOccupiedEntry<'a> { set: &'a mut AttributeSet, index: usize, } -impl<'a> AttributeSetOccupiedEntry<'a> { +impl AttributeSetOccupiedEntry<'_> { #[inline] pub fn get(&self) -> &Attribute { &self.set.attrs[self.index] @@ -228,7 +228,7 @@ pub struct AttributeSetVacantEntry<'a> { key: Ident, index: usize, } -impl<'a> AttributeSetVacantEntry<'a> { +impl AttributeSetVacantEntry<'_> { pub fn insert(self, attr: Attribute) { if self.key != attr.id() { self.set.insert(attr); diff --git a/assembly/src/ast/visit.rs b/assembly/src/ast/visit.rs index b9d60cbe65..ecd11fb86e 100644 --- a/assembly/src/ast/visit.rs +++ b/assembly/src/ast/visit.rs @@ -139,7 +139,7 @@ pub trait Visit { } } -impl<'a, V, T> Visit for &'a mut V +impl Visit for &mut V where V: ?Sized + Visit, { @@ -575,7 +575,7 @@ pub trait VisitMut { } } -impl<'a, V, T> VisitMut for &'a mut V +impl VisitMut for &mut V where V: ?Sized + VisitMut, { diff --git a/assembly/src/compile.rs b/assembly/src/compile.rs index 1d2fda3a45..2e36858cdd 100644 --- a/assembly/src/compile.rs +++ b/assembly/src/compile.rs @@ -130,7 +130,7 @@ impl Compile for Module { } } -impl<'a> Compile for &'a Module { +impl Compile for &Module { #[inline(always)] fn compile_with_options( self, @@ -197,7 +197,7 @@ impl Compile for Arc { } } -impl<'a> Compile for &'a str { +impl Compile for &str { #[inline(always)] fn compile_with_options( self, @@ -208,7 +208,7 @@ impl<'a> Compile for &'a str { } } -impl<'a> Compile for &'a String { +impl Compile for &String { #[inline(always)] fn compile_with_options( self, @@ -251,7 +251,7 @@ impl Compile for Box { } } -impl<'a> Compile for Cow<'a, str> { +impl Compile for Cow<'_, str> { #[inline(always)] fn compile_with_options( self, @@ -265,7 +265,7 @@ impl<'a> Compile for Cow<'a, str> { // COMPILE IMPLEMENTATIONS FOR BYTES // ------------------------------------------------------------------------------------------------ -impl<'a> Compile for &'a [u8] { +impl Compile for &[u8] { #[inline] fn compile_with_options( self, @@ -350,7 +350,7 @@ where // ------------------------------------------------------------------------------------------------ #[cfg(feature = "std")] -impl<'a> Compile for &'a std::path::Path { +impl Compile for &std::path::Path { fn compile_with_options( self, source_manager: &dyn SourceManager, diff --git a/assembly/src/library/path.rs b/assembly/src/library/path.rs index a77ea1b287..22e5fe8479 100644 --- a/assembly/src/library/path.rs +++ b/assembly/src/library/path.rs @@ -65,9 +65,9 @@ impl<'a> LibraryPathComponent<'a> { } } -impl<'a> Eq for LibraryPathComponent<'a> {} +impl Eq for LibraryPathComponent<'_> {} -impl<'a> PartialEq for LibraryPathComponent<'a> { +impl PartialEq for LibraryPathComponent<'_> { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Namespace(a), Self::Namespace(b)) => a == b, @@ -77,13 +77,13 @@ impl<'a> PartialEq for LibraryPathComponent<'a> { } } -impl<'a> PartialEq for LibraryPathComponent<'a> { +impl PartialEq for LibraryPathComponent<'_> { fn eq(&self, other: &str) -> bool { self.as_ref().eq(other) } } -impl<'a> AsRef for LibraryPathComponent<'a> { +impl AsRef for LibraryPathComponent<'_> { fn as_ref(&self) -> &str { match self { Self::Namespace(ns) => ns.as_str(), @@ -92,7 +92,7 @@ impl<'a> AsRef for LibraryPathComponent<'a> { } } -impl<'a> fmt::Display for LibraryPathComponent<'a> { +impl fmt::Display for LibraryPathComponent<'_> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str(self.as_ref()) } diff --git a/assembly/src/parser/mod.rs b/assembly/src/parser/mod.rs index d91f9e1024..d61e5619a1 100644 --- a/assembly/src/parser/mod.rs +++ b/assembly/src/parser/mod.rs @@ -304,7 +304,7 @@ mod module_walker { } } - impl<'a> Iterator for WalkModules<'a> { + impl Iterator for WalkModules<'_> { type Item = Result; fn next(&mut self) -> Option { diff --git a/assembly/src/parser/token.rs b/assembly/src/parser/token.rs index 8251278716..602e274912 100644 --- a/assembly/src/parser/token.rs +++ b/assembly/src/parser/token.rs @@ -316,7 +316,7 @@ pub enum Token<'input> { Eof, } -impl<'input> fmt::Display for Token<'input> { +impl fmt::Display for Token<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Token::Add => write!(f, "add"), diff --git a/assembly/src/sema/passes/const_eval.rs b/assembly/src/sema/passes/const_eval.rs index f76de03ad2..8394bc5402 100644 --- a/assembly/src/sema/passes/const_eval.rs +++ b/assembly/src/sema/passes/const_eval.rs @@ -17,7 +17,7 @@ impl<'analyzer> ConstEvalVisitor<'analyzer> { } } -impl<'analyzer> ConstEvalVisitor<'analyzer> { +impl ConstEvalVisitor<'_> { fn eval_const(&mut self, imm: &mut Immediate) -> ControlFlow<()> where T: TryFrom, @@ -45,7 +45,7 @@ impl<'analyzer> ConstEvalVisitor<'analyzer> { } } -impl<'analyzer> VisitMut for ConstEvalVisitor<'analyzer> { +impl VisitMut for ConstEvalVisitor<'_> { fn visit_mut_immediate_u8(&mut self, imm: &mut Immediate) -> ControlFlow<()> { self.eval_const(imm) } diff --git a/assembly/src/sema/passes/verify_invoke.rs b/assembly/src/sema/passes/verify_invoke.rs index a1c38ba8ca..16c7ac5ba5 100644 --- a/assembly/src/sema/passes/verify_invoke.rs +++ b/assembly/src/sema/passes/verify_invoke.rs @@ -43,7 +43,7 @@ impl<'a> VerifyInvokeTargets<'a> { } } -impl<'a> VerifyInvokeTargets<'a> { +impl VerifyInvokeTargets<'_> { fn resolve_local(&mut self, name: &ProcedureName) -> ControlFlow<()> { if !self.procedures.contains(name) { self.analyzer @@ -72,7 +72,7 @@ impl<'a> VerifyInvokeTargets<'a> { } } -impl<'a> VisitMut for VerifyInvokeTargets<'a> { +impl VisitMut for VerifyInvokeTargets<'_> { fn visit_mut_inst(&mut self, inst: &mut Span) -> ControlFlow<()> { let span = inst.span(); match &**inst { diff --git a/core/src/mast/node/basic_block_node/mod.rs b/core/src/mast/node/basic_block_node/mod.rs index 81f0afa0a5..726decbc72 100644 --- a/core/src/mast/node/basic_block_node/mod.rs +++ b/core/src/mast/node/basic_block_node/mod.rs @@ -247,7 +247,7 @@ struct BasicBlockNodePrettyPrint<'a> { mast_forest: &'a MastForest, } -impl<'a> PrettyPrint for BasicBlockNodePrettyPrint<'a> { +impl PrettyPrint for BasicBlockNodePrettyPrint<'_> { #[rustfmt::skip] fn render(&self) -> crate::prettier::Document { use crate::prettier::*; @@ -295,7 +295,7 @@ impl<'a> PrettyPrint for BasicBlockNodePrettyPrint<'a> { } } -impl<'a> fmt::Display for BasicBlockNodePrettyPrint<'a> { +impl fmt::Display for BasicBlockNodePrettyPrint<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::prettier::PrettyPrint; self.pretty_print(f) diff --git a/core/src/mast/node/call_node.rs b/core/src/mast/node/call_node.rs index c028a32456..7f207d386f 100644 --- a/core/src/mast/node/call_node.rs +++ b/core/src/mast/node/call_node.rs @@ -201,7 +201,7 @@ struct CallNodePrettyPrint<'a> { mast_forest: &'a MastForest, } -impl<'a> CallNodePrettyPrint<'a> { +impl CallNodePrettyPrint<'_> { /// Concatenates the provided decorators in a single line. If the list of decorators is not /// empty, prepends `prepend` and appends `append` to the decorator document. fn concatenate_decorators( @@ -240,7 +240,7 @@ impl<'a> CallNodePrettyPrint<'a> { } } -impl<'a> PrettyPrint for CallNodePrettyPrint<'a> { +impl PrettyPrint for CallNodePrettyPrint<'_> { fn render(&self) -> Document { let call_or_syscall = { let callee_digest = self.mast_forest[self.node.callee].digest(); @@ -265,7 +265,7 @@ impl<'a> PrettyPrint for CallNodePrettyPrint<'a> { } } -impl<'a> fmt::Display for CallNodePrettyPrint<'a> { +impl fmt::Display for CallNodePrettyPrint<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::prettier::PrettyPrint; self.pretty_print(f) diff --git a/core/src/mast/node/dyn_node.rs b/core/src/mast/node/dyn_node.rs index 34e87610b8..91afeea798 100644 --- a/core/src/mast/node/dyn_node.rs +++ b/core/src/mast/node/dyn_node.rs @@ -91,7 +91,7 @@ struct DynNodePrettyPrint<'a> { mast_forest: &'a MastForest, } -impl<'a> DynNodePrettyPrint<'a> { +impl DynNodePrettyPrint<'_> { /// Concatenates the provided decorators in a single line. If the list of decorators is not /// empty, prepends `prepend` and appends `append` to the decorator document. fn concatenate_decorators( @@ -130,7 +130,7 @@ impl<'a> DynNodePrettyPrint<'a> { } } -impl<'a> crate::prettier::PrettyPrint for DynNodePrettyPrint<'a> { +impl crate::prettier::PrettyPrint for DynNodePrettyPrint<'_> { fn render(&self) -> crate::prettier::Document { let dyn_text = const_text("dyn"); @@ -144,7 +144,7 @@ impl<'a> crate::prettier::PrettyPrint for DynNodePrettyPrint<'a> { } } -impl<'a> fmt::Display for DynNodePrettyPrint<'a> { +impl fmt::Display for DynNodePrettyPrint<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.pretty_print(f) } diff --git a/core/src/mast/node/external.rs b/core/src/mast/node/external.rs index 3b3f23e403..d966008009 100644 --- a/core/src/mast/node/external.rs +++ b/core/src/mast/node/external.rs @@ -89,7 +89,7 @@ struct ExternalNodePrettyPrint<'a> { mast_forest: &'a MastForest, } -impl<'a> ExternalNodePrettyPrint<'a> { +impl ExternalNodePrettyPrint<'_> { /// Concatenates the provided decorators in a single line. If the list of decorators is not /// empty, prepends `prepend` and appends `append` to the decorator document. fn concatenate_decorators( @@ -128,7 +128,7 @@ impl<'a> ExternalNodePrettyPrint<'a> { } } -impl<'a> crate::prettier::PrettyPrint for ExternalNodePrettyPrint<'a> { +impl crate::prettier::PrettyPrint for ExternalNodePrettyPrint<'_> { fn render(&self) -> crate::prettier::Document { let external = const_text("external") + const_text(".") @@ -144,7 +144,7 @@ impl<'a> crate::prettier::PrettyPrint for ExternalNodePrettyPrint<'a> { } } -impl<'a> fmt::Display for ExternalNodePrettyPrint<'a> { +impl fmt::Display for ExternalNodePrettyPrint<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::prettier::PrettyPrint; self.pretty_print(f) diff --git a/core/src/mast/node/join_node.rs b/core/src/mast/node/join_node.rs index 17aaccd8ec..d3d04b4510 100644 --- a/core/src/mast/node/join_node.rs +++ b/core/src/mast/node/join_node.rs @@ -142,7 +142,7 @@ struct JoinNodePrettyPrint<'a> { mast_forest: &'a MastForest, } -impl<'a> PrettyPrint for JoinNodePrettyPrint<'a> { +impl PrettyPrint for JoinNodePrettyPrint<'_> { #[rustfmt::skip] fn render(&self) -> crate::prettier::Document { use crate::prettier::*; @@ -195,7 +195,7 @@ impl<'a> PrettyPrint for JoinNodePrettyPrint<'a> { } } -impl<'a> fmt::Display for JoinNodePrettyPrint<'a> { +impl fmt::Display for JoinNodePrettyPrint<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::prettier::PrettyPrint; self.pretty_print(f) diff --git a/core/src/mast/node/loop_node.rs b/core/src/mast/node/loop_node.rs index 08933ac521..6091ce034d 100644 --- a/core/src/mast/node/loop_node.rs +++ b/core/src/mast/node/loop_node.rs @@ -131,7 +131,7 @@ struct LoopNodePrettyPrint<'a> { mast_forest: &'a MastForest, } -impl<'a> crate::prettier::PrettyPrint for LoopNodePrettyPrint<'a> { +impl crate::prettier::PrettyPrint for LoopNodePrettyPrint<'_> { fn render(&self) -> crate::prettier::Document { use crate::prettier::*; @@ -175,7 +175,7 @@ impl<'a> crate::prettier::PrettyPrint for LoopNodePrettyPrint<'a> { } } -impl<'a> fmt::Display for LoopNodePrettyPrint<'a> { +impl fmt::Display for LoopNodePrettyPrint<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::prettier::PrettyPrint; self.pretty_print(f) diff --git a/core/src/mast/node/mod.rs b/core/src/mast/node/mod.rs index cbb3192f40..2163565742 100644 --- a/core/src/mast/node/mod.rs +++ b/core/src/mast/node/mod.rs @@ -273,7 +273,7 @@ impl<'a> MastNodePrettyPrint<'a> { } } -impl<'a> PrettyPrint for MastNodePrettyPrint<'a> { +impl PrettyPrint for MastNodePrettyPrint<'_> { fn render(&self) -> Document { self.node_pretty_print.render() } @@ -289,7 +289,7 @@ impl<'a> MastNodeDisplay<'a> { } } -impl<'a> fmt::Display for MastNodeDisplay<'a> { +impl fmt::Display for MastNodeDisplay<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.node_display.fmt(f) } diff --git a/core/src/mast/node/split_node.rs b/core/src/mast/node/split_node.rs index 6b1b96e0cc..8a46fcdc70 100644 --- a/core/src/mast/node/split_node.rs +++ b/core/src/mast/node/split_node.rs @@ -144,7 +144,7 @@ struct SplitNodePrettyPrint<'a> { mast_forest: &'a MastForest, } -impl<'a> PrettyPrint for SplitNodePrettyPrint<'a> { +impl PrettyPrint for SplitNodePrettyPrint<'_> { #[rustfmt::skip] fn render(&self) -> crate::prettier::Document { use crate::prettier::*; @@ -190,7 +190,7 @@ impl<'a> PrettyPrint for SplitNodePrettyPrint<'a> { } } -impl<'a> fmt::Display for SplitNodePrettyPrint<'a> { +impl fmt::Display for SplitNodePrettyPrint<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use crate::prettier::PrettyPrint; self.pretty_print(f) diff --git a/core/src/mast/serialization/basic_blocks.rs b/core/src/mast/serialization/basic_blocks.rs index e32caa6e99..86cf884717 100644 --- a/core/src/mast/serialization/basic_blocks.rs +++ b/core/src/mast/serialization/basic_blocks.rs @@ -67,7 +67,7 @@ impl<'a> BasicBlockDataDecoder<'a> { } /// Decoding methods -impl<'a> BasicBlockDataDecoder<'a> { +impl BasicBlockDataDecoder<'_> { pub fn decode_operations_and_decorators( &self, ops_offset: NodeDataOffset, diff --git a/processor/src/host/advice/mod.rs b/processor/src/host/advice/mod.rs index 6dacc08b45..4eba93fe7c 100644 --- a/processor/src/host/advice/mod.rs +++ b/processor/src/host/advice/mod.rs @@ -718,7 +718,7 @@ pub trait AdviceProvider: Sized { R: Borrow; } -impl<'a, T> AdviceProvider for &'a mut T +impl AdviceProvider for &mut T where T: AdviceProvider, { diff --git a/processor/src/host/mod.rs b/processor/src/host/mod.rs index 10366e7c66..4e4289b331 100644 --- a/processor/src/host/mod.rs +++ b/processor/src/host/mod.rs @@ -176,7 +176,7 @@ pub trait Host { } } -impl<'a, H> Host for &'a mut H +impl Host for &mut H where H: Host, { diff --git a/prover/src/gpu/metal/mod.rs b/prover/src/gpu/metal/mod.rs index ab7132834e..930253b5fc 100644 --- a/prover/src/gpu/metal/mod.rs +++ b/prover/src/gpu/metal/mod.rs @@ -688,7 +688,7 @@ where E: FieldElement, I: IntoIterator>; -impl<'a, 'b, E, I, const N: usize> Iterator for SegmentIterator<'a, 'b, E, I, N> +impl Iterator for SegmentIterator where E: FieldElement, I: IntoIterator>,