From 2a654e34148d4a756db5a4811a632d5b8c426f0e Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:25:30 +0100 Subject: [PATCH 01/14] feat: add horner_eval_ext, update tests and docs --- stdlib/tests/crypto/falcon.rs | 1 + stdlib/tests/crypto/stark/mod.rs | 1 + 2 files changed, 2 insertions(+) diff --git a/stdlib/tests/crypto/falcon.rs b/stdlib/tests/crypto/falcon.rs index 02d025134..5cc7c8786 100644 --- a/stdlib/tests/crypto/falcon.rs +++ b/stdlib/tests/crypto/falcon.rs @@ -145,6 +145,7 @@ fn test_falcon512_probabilistic_product() { test.expect_stack(expected_stack); } +#[ignore = "needs horner_eval_base op"] #[test] fn test_falcon512_probabilistic_product_failure() { // create two random polynomials and generate the input operand stack and advice stack to diff --git a/stdlib/tests/crypto/stark/mod.rs b/stdlib/tests/crypto/stark/mod.rs index 66ab2128b..64f0cdb4c 100644 --- a/stdlib/tests/crypto/stark/mod.rs +++ b/stdlib/tests/crypto/stark/mod.rs @@ -9,6 +9,7 @@ use verifier_recursive::{VerifierData, generate_advice_inputs}; // Note: Changes to Miden VM may cause this test to fail when some of the assumptions documented // in `stdlib/asm/crypto/stark/verifier.masm` are violated. +#[ignore = "needs horner_eval_* ops"] #[test] fn stark_verifier_e2f4() { // An example MASM program to be verified inside Miden VM. From e9511b4b0cafe53a85d7bc5f373ada67b56c3a20 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Fri, 14 Feb 2025 20:40:04 +0100 Subject: [PATCH 02/14] chore: address feedback --- processor/src/operations/horner_ops.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/processor/src/operations/horner_ops.rs b/processor/src/operations/horner_ops.rs index cf7309c77..88526d923 100644 --- a/processor/src/operations/horner_ops.rs +++ b/processor/src/operations/horner_ops.rs @@ -1,4 +1,5 @@ -use vm_core::{Felt, Operation}; +use miden_air::trace::decoder::NUM_USER_OP_HELPERS; +use vm_core::{Felt, Operation, ZERO}; use crate::{ExecutionError, Process, QuadFelt}; From 2f31f7842e75a641755686732765b7cdd6f09ecd Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Mon, 17 Feb 2025 17:15:29 +0100 Subject: [PATCH 03/14] feat: updated recursive verifier to use horner_eval_* --- stdlib/tests/crypto/stark/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/stdlib/tests/crypto/stark/mod.rs b/stdlib/tests/crypto/stark/mod.rs index 64f0cdb4c..66ab2128b 100644 --- a/stdlib/tests/crypto/stark/mod.rs +++ b/stdlib/tests/crypto/stark/mod.rs @@ -9,7 +9,6 @@ use verifier_recursive::{VerifierData, generate_advice_inputs}; // Note: Changes to Miden VM may cause this test to fail when some of the assumptions documented // in `stdlib/asm/crypto/stark/verifier.masm` are violated. -#[ignore = "needs horner_eval_* ops"] #[test] fn stark_verifier_e2f4() { // An example MASM program to be verified inside Miden VM. From 7f1118d78af89c9275ccb7251e10c0c608dff952 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 18 Mar 2025 09:32:23 +0100 Subject: [PATCH 04/14] wip rebase --- Cargo.lock | 29 +-- Cargo.toml | 11 + stdlib/asm/crypto/fri/frie2f4.masm | 243 ++++++++++++++---- stdlib/asm/crypto/fri/helper.masm | 113 ++------ stdlib/asm/crypto/stark/constants.masm | 26 +- stdlib/asm/crypto/stark/verifier.masm | 44 ++-- stdlib/tests/crypto/stark/mod.rs | 2 +- .../crypto/stark/verifier_recursive/mod.rs | 7 - 8 files changed, 277 insertions(+), 198 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8aad3112c..e7e757d4f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2933,9 +2933,8 @@ dependencies = [ [[package]] name = "winter-air" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d7fbdcaa53d220b84811199790c1dda77c025533cdd27715cf1625af2b4027a" +version = "0.12.0" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "libm", "winter-crypto", @@ -2947,8 +2946,7 @@ dependencies = [ [[package]] name = "winter-crypto" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32247cde9f43e5bbd05362caa7274608790ea69b14f7c81cd509aae7127c5ff2" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "blake3", "sha3", @@ -2959,8 +2957,7 @@ dependencies = [ [[package]] name = "winter-fri" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4d09d5ac254ac54028ac04751d7ae0cbeb111c6cb08cc30c6400ff61b3203bd" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "winter-crypto", "winter-math", @@ -2970,8 +2967,7 @@ dependencies = [ [[package]] name = "winter-math" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "326dfe4bfa4072b7c909133a88f8807820d3e49e5dfd246f67981771f74a0ed3" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "winter-utils", ] @@ -2979,8 +2975,7 @@ dependencies = [ [[package]] name = "winter-maybe-async" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaa132be74e602b707f1dab5a69c38496445e54ee940e7c281c02b15007241bd" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "quote", "syn", @@ -2989,8 +2984,7 @@ dependencies = [ [[package]] name = "winter-prover" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71658b20723e8b6d5f50fb1b5eddb1f9ac56dfe9b85aefb38c08c00496d4a2c2" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "tracing", "winter-air", @@ -3004,8 +2998,7 @@ dependencies = [ [[package]] name = "winter-rand-utils" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6321741f063344258c80f0c0255a559ded99bc17fe99fab9577f2460065ddf" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "rand 0.8.5", "winter-utils", @@ -3014,8 +3007,7 @@ dependencies = [ [[package]] name = "winter-utils" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d47518e6931955dcac73a584cacb04550b82ab2f45c72880cbbbdbe13adb63c" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "rayon", ] @@ -3023,8 +3015,7 @@ dependencies = [ [[package]] name = "winter-verifier" version = "0.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d3187d4ba3a2648740d504f4b11b7d8271c16ec545d639c1a643e8724bff836" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" dependencies = [ "winter-air", "winter-crypto", diff --git a/Cargo.toml b/Cargo.toml index dcd280ef1..05cc16245 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,3 +36,14 @@ overflow-checks = true [workspace.dependencies] thiserror = { version = "2.0", default-features = false } + +[patch.crates-io] +winter-air = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-air" } +winter-crypto = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-crypto" } +winter-prover = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-prover" } +winter-verifier = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-verifier" } +winter-math = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-math" } +winter-fri = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-fri" } +winter-maybe-async = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-maybe-async" } +winter-utils = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-utils" } +winter-rand-utils = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-rand-utils" } \ No newline at end of file diff --git a/stdlib/asm/crypto/fri/frie2f4.masm b/stdlib/asm/crypto/fri/frie2f4.masm index da054ed15..8ec1eeaed 100644 --- a/stdlib/asm/crypto/fri/frie2f4.masm +++ b/stdlib/asm/crypto/fri/frie2f4.masm @@ -1,3 +1,5 @@ +use.std::crypto::stark::constants + #! Stores the layer commitments C followed by [d_size, t_depth, a1, a0] and [poe, p, e1, e0] where: #! 1) d_size is the domain size divided by 4 of the domain corresponding to C. #! 2) t_depth is the tree depth of the Merkle tree with commitment C. @@ -90,7 +92,7 @@ end #! Input: [layer_ptr, layer_ptr, poe, p, e1, e0, layer_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] #! Output: [layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] #! -#! Cycles: 76 +#! Cycles: 83 export.verify_query_layer.12 # load layer commitment C as well as [a0, a1, t_depth, d_size] (7 cycles) @@ -120,11 +122,11 @@ export.verify_query_layer.12 # unhash V and save the pre-image in locaddr.0 and locaddr.4; we don't clear values of C # because adv_pipe overwrites the first 8 elements of the stack (15 cycles) - locaddr.4 + exec.constants::tmp3 movdn.4 - push.0.0.0.0 + padw swapw - push.0.0.0.0 + padw adv_pipe hperm # => [T2, T1, T0, ptr, V, f_pos, d_seg, poe, e1, e0, a1, a0, layer_ptr, rem_ptr, ..] @@ -141,9 +143,11 @@ export.verify_query_layer.12 assert_eq # load (v7, ..v0) from memory (8 cycles) - loc_loadw.4 + exec.constants::tmp3 + mem_loadw swapw - loc_loadw.8 + exec.constants::tmp4 + mem_loadw # => [v7, ..., v0, f_pos, d_seg, poe, e1, e0, a1, a0, layer_ptr, rem_ptr, ...] # fold by 4 (1 cycle) @@ -166,6 +170,9 @@ end #! Verifies one FRI query. #! +#! This procedure is specialized to the case when the remainder polynomial, used in the final check, +#! is expected to have degree at most 64. +#! #! Input: [poe, p, e1, e0, layer_ptr, rem_ptr, ...] #! Output: [x, x, x, x, x, x, x, x, x, x, ...] #! @@ -174,17 +181,17 @@ end #! - (e0, e1) is an extension field element corresponding to the value of the first layer at index p. #! - layer_ptr is the memory address of the layer data (Merkle tree root, alpha etc.) for the next #! layer. -#! - rem_ptr is the memory address of the remainder codeword. +#! - rem_ptr is the memory address of the remainder polynomial. #! -#! Cycles: 42 + num_layers * 76 -export.verify_query +#! Cycles: 107 + num_layers * 83 +export.verify_query_64 # prepare stack to be in a form that leverages the fri_ext2fold4 instruction output stack state # (16 cycles) dup.5 dup.5 - push.0.0.0.0 - push.0.0.0.0 + padw + padw swapdw dup dup @@ -198,41 +205,92 @@ export.verify_query end # => [rem_ptr, rem_ptr, poe^(2^n), f_pos, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] - # check that rem_ptr[f_pos] == (ne0, ne1) + movup.2 mul.7 + exec.constants::tmp2 mem_store + # => [rem_ptr, rem_ptr, f_pos, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] - # Since each memory address contains two extension field elements, we have to determine which - # of the two elements we should compare against. (7 cycles) - movup.3 # [f_pos, rem_ptr, rem_ptr, poe^(2^n), ne1, ne0, rem_ptr, rem_ptr, ...] - push.2 # [2, f_pos, rem_ptr, rem_ptr, poe^(2^n), ne1, ne0, rem_ptr, rem_ptr, ...] - u32divmod # [f_pos%2, f_pos/2, rem_ptr, rem_ptr, poe^(2^n), ne1, ne0, rem_ptr, rem_ptr, ...] - movdn.4 # [f_pos/2, rem_ptr, rem_ptr, poe^(2^n), f_pos%2, ne1, ne0, rem_ptr, rem_ptr, ...] - mul.4 # [f_pos*2, rem_ptr, rem_ptr, poe^(2^n), f_pos%2, ne1, ne0, rem_ptr, rem_ptr, ...] - dup.1 - dup.1 # [f_pos*2, rem_ptr, f_pos*2, rem_ptr, rem_ptr, poe^(2^n), f_pos%2, ne1, ne0, rem_ptr, rem_ptr, ...] - add # [rem_ptr + f_pos*2, f_pos*2, rem_ptr, rem_ptr, poe^(2^n), f_pos%2, ne1, ne0, rem_ptr, rem_ptr, ...] - # => [rem_ptr + offset, x, x, x, x, ?, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ..] + push.0 exec.constants::tmp1 mem_loadw + # => [P, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] - mem_loadw - # => [e1', e0', e1, e0, ?, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ..] + swapw swapdw + # => [x, x, x, x, x, x, x, x, ne1, ne0, rem_ptr, rem_ptr, P, ...] - # compare (ne0, ne1) to the appropriate tuple from the remainder word (14 cycles) - movup.2 - swap - dup.4 - cdrop - movdn.3 - movup.2 - cdrop - swap.2 - assert_eq - assert_eq - # => [x, x, x, x, x, x, x, x, x, x, ...] + repeat.16 + mem_stream + horner_eval_ext + end + # => [x, x, x, x, x, x, x, x, ne1, ne0, rem_ptr, rem_ptr, P, ...] + + swapdw + # => [ne1, ne0, rem_ptr, rem_ptr, P, x, x, x, x, x, x, x, x, ...] + movup.6 assert_eq + movup.5 assert_eq + # => [X, x, x, x, x, x, x, x, x, ...] end +#! Verifies one FRI query. +#! +#! This procedure is specialized to the case when the remainder polynomial, used in the final check, +#! is expected to have degree at most 128. +#! +#! Input: [poe, p, e1, e0, layer_ptr, rem_ptr, ...] +#! Output: [x, x, x, x, x, x, x, x, x, x, ...] +#! +#! - poe is g^p. +#! - p is a query index at the first layer. +#! - (e0, e1) is an extension field element corresponding to the value of the first layer at index p. +#! - layer_ptr is the memory address of the layer data (Merkle tree root, alpha etc.) for the next +#! layer. +#! - rem_ptr is the memory address of the remainder polynomial. +#! +#! Cycles: 140 + num_layers * 83 +export.verify_query_128 + + # prepare stack to be in a form that leverages the fri_ext2fold4 instruction output stack state + # (16 cycles) + dup.5 + dup.5 + padw + padw + swapdw + dup + dup + movup.3 + neq + # => [?, layer_ptr, layer_ptr, poe, p, e1, e0, layer_ptr, rem_ptr, 0, 0, 0, 0, 0, 0, 0, 0, ...] + + # verify correctness of layer folding + while.true + exec.verify_query_layer + end + # => [rem_ptr, rem_ptr, poe^(2^n), f_pos, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + + movup.2 mul.7 + exec.constants::tmp2 mem_store + # => [rem_ptr, rem_ptr, f_pos, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + + push.0 exec.constants::tmp1 mem_loadw + # => [P, ne1, ne0, rem_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] + + swapw swapdw + # => [x, x, x, x, x, x, x, x, ne1, ne0, rem_ptr, rem_ptr, P, ...] + + repeat.32 + mem_stream + horner_eval_ext + end + + # => [x, x, x, x, x, x, x, x, ne1, ne0, rem_ptr, rem_ptr, P, ...] + swapdw + # => [ne1, ne0, rem_ptr, rem_ptr, P, x, x, x, x, x, x, x, x, ...] + movup.6 assert_eq + movup.5 assert_eq + # => [X, x, x, x, x, x, x, x, x, ...] +end + + #! Verifies a FRI proof where the proof was generated over the quadratic extension of the base #! field and layer folding was performed using folding factor 4. -#! Note that the check that the remainder codeword corresponds to the remainder polynomial received -#! by the verifier should now be performed by the calling procedure. #! #! Input: [query_ptr, layer_ptr, rem_ptr, g, ...] #! Output: [...] @@ -241,13 +299,14 @@ end #! to g^p with g being the initial FRI domain generator. p is the query index at the first layer #! and (e0, e1) is an extension field element corresponding to the value of the first layer at index p. #! - layer_ptr is a pointer to the first layer commitment denoted throughout the code by C. -#! layer_ptr + 4 points to the first [alpha0, alpha1, t_depth, d_size] where d_size is the size +#! layer_ptr + 1 points to the first [alpha0, alpha1, t_depth, d_size] where d_size is the size #! of initial domain divided by 4, t_depth is the depth of the Merkle tree commitment to the #! first layer and (alpha0, alpha1) is the first challenge used in folding the first layer. #! Both t_depth and d_size are expected to be smaller than 2^32. Otherwise, the result of #! this procedure is undefined. #! - rem_ptr is a pointer to the first tuple of two consecutive degree 2 extension field -#! elements making up the remainder codeword. This codeword can be of length either 32 or 64. +#! elements making up the remainder polynomial. This procedure is specialized to the case when +#! the the degree of the latter is less than 64. #! #! The memory referenced above is used contiguously, as follows: #! @@ -257,8 +316,8 @@ end #! 1. rem_ptr - 1 points to the last (alpha0, alpha1, t_depth, d_size) tuple. #! 2. layer_ptr - 1 points to the last (e0, e1, p, poe) tuple. #! -#! Cycles: 7 + 4 + num_queries * (42 + num_layers * 76 + 26) -export.verify.4 +#! Cycles: 18 + num_queries * (107 + num_layers * 83) +export.verify_64.4 # store [query_ptr, layer_ptr, rem_ptr, g] to keep track of all queries # (3 cycles) @@ -270,28 +329,110 @@ export.verify.4 dup.2 neq + # Save a word containing a fresh accumulator for Horner evaluating the remainder polynomial, + # a pointer to the evaluation point and a pointer to the location of the polynomial. + push.0.0 exec.constants::tmp2 + padw exec.constants::tmp8 mem_loadw movdn.3 drop drop drop + exec.constants::tmp1 mem_storew + movup.4 + while.true # load [e0, e1, p, poe] from memory i.e. next query data (7 cycles) - push.0.0.0.0 movup.4 mem_loadw # => [poe, p, e1, e0, layer_ptr, rem_ptr, g, ...] # we now have everything to verify query p - exec.verify_query + exec.verify_query_64 # prepare for next iteration (18 cycles) # => [x, x, x, x, x, x, x, x, x, x, g, ...] - dropw drop drop drop + dropw drop loc_loadw.0 # load [query_ptr, layer_ptr, rem_ptr, g] add.4 - loc_storew.0 # store [query_ptr + 4, layer_ptr, rem_ptr, g] - dup - dup.2 + loc_storew.0 # store [query_ptr + 1, layer_ptr, rem_ptr, g] + swapw + # => [x, x, x, x, query_ptr + 1, layer_ptr, rem_ptr, g, ...] + dup.5 + dup.5 neq - #=> [?, query_ptr + 4, layer_ptr, rem_ptr, g, ...] + #=> [?, query_ptr + 1, layer_ptr, rem_ptr, g, ...] end #=> [X, ..] - dropw + dropw dropw +end + +#! Verifies a FRI proof where the proof was generated over the quadratic extension of the base +#! field and layer folding was performed using folding factor 4. +#! +#! Input: [query_ptr, layer_ptr, rem_ptr, g, ...] +#! Output: [...] +#! +#! - query_ptr is a pointer to a list of tuples of the form (e0, e1, p, poe) where poe is equal +#! to g^p with g being the initial FRI domain generator. p is the query index at the first layer +#! and (e0, e1) is an extension field element corresponding to the value of the first layer at index p. +#! - layer_ptr is a pointer to the first layer commitment denoted throughout the code by C. +#! layer_ptr + 1 points to the first [alpha0, alpha1, t_depth, d_size] where d_size is the size +#! of initial domain divided by 4, t_depth is the depth of the Merkle tree commitment to the +#! first layer and (alpha0, alpha1) is the first challenge used in folding the first layer. +#! Both t_depth and d_size are expected to be smaller than 2^32. Otherwise, the result of +#! this procedure is undefined. +#! - rem_ptr is a pointer to the first tuple of two consecutive degree 2 extension field +#! elements making up the remainder polynomial. This procedure is specialized to the case when +#! the the degree of the latter is less than 128. +#! +#! The memory referenced above is used contiguously, as follows: +#! +#! [query_ptr ... layer_ptr ... rem_ptr ...] +#! +#! This means for example that: +#! 1. rem_ptr - 1 points to the last (alpha0, alpha1, t_depth, d_size) tuple. +#! 2. layer_ptr - 1 points to the last (e0, e1, p, poe) tuple. +#! +#! Cycles: 18 + num_queries * (140 + num_layers * 83) +export.verify_128.4 + + # store [query_ptr, layer_ptr, rem_ptr, g] to keep track of all queries + # (3 cycles) + loc_storew.0 + + # [(query_ptr == layer_ptr), query_ptr, layer_ptr, rem_ptr, g] + # (4 cycles) + dup + dup.2 + neq + + # Save a word containing a fresh accumulator for Horner evaluating the remainder polynomial, + # a pointer to the evaluation point and a pointer to the location of the polynomial. + push.0.0 exec.constants::tmp2 + padw exec.constants::tmp8 mem_loadw movdn.3 drop drop drop + exec.constants::tmp1 mem_storew + movup.4 + + while.true + # load [e0, e1, p, poe] from memory i.e. next query data (7 cycles) + movup.4 + mem_loadw + # => [poe, p, e1, e0, layer_ptr, rem_ptr, g, ...] + + # we now have everything to verify query p + exec.verify_query_128 + + # prepare for next iteration (18 cycles) + # => [x, x, x, x, x, x, x, x, x, x, g, ...] + dropw drop + loc_loadw.0 # load [query_ptr, layer_ptr, rem_ptr, g] + add.4 + loc_storew.0 # store [query_ptr + 1, layer_ptr, rem_ptr, g] + swapw + # => [x, x, x, x, query_ptr + 1, layer_ptr, rem_ptr, g, ...] + dup.5 + dup.5 + neq + #=> [?, x, x, x, x, query_ptr + 1, layer_ptr, rem_ptr, g, ...] + end + #=> [X, X, ..] + + dropw dropw end diff --git a/stdlib/asm/crypto/fri/helper.masm b/stdlib/asm/crypto/fri/helper.masm index aca0a71d7..6959d62c0 100644 --- a/stdlib/asm/crypto/fri/helper.masm +++ b/stdlib/asm/crypto/fri/helper.masm @@ -60,20 +60,21 @@ export.generate_fri_parameters dup is_odd if.true - push.32 + push.512 swap - sub.5 + sub.9 div.2 else - push.64 + push.1024 swap - sub.6 + sub.10 div.2 end # => [num_fri_layers, remainder_size, lde_size, lde_size, log2(lde_size), domain_gen, 0, ...] (12 cycles) # Save `[num_fri_layers, remainder_size, lde_size, lde_size]` in memory exec.constants::tmp6 mem_storew + swap div.8 swap movdn.6 dropw drop @@ -155,14 +156,12 @@ export.load_fri_layer_commitments #=> [...] end -#! Load the remainder polynomial from the advice provider and check that its hash corresponds -#! to its commitment and reseed with the latter. -#! Load the remainder code word, i.e. the NTT of the remainder polynomial, and use its hash, together, -#! with the hash of the remainder polynomial in order to generate the Fiat-Shamir challenge `tau` for -#! the `verify_remainder_xx` procedure. +#! Load and save the remainder polynomial from the advice provider and check that its hash +#! corresponds to its commitment and reseed with the latter. #! #! Input: [...] #! Output: [...] +#! #! Cycles: #! 1- Remainder of size 32: 1633 #! 2- Remainder of size 64: 3109 @@ -192,33 +191,20 @@ export.load_and_verify_remainder #=> [ptr_remainder, remainder_size, y, y] dup.1 - push.32 + push.512 + eq if.true - # Remainder length equal to 32 + # Remainder polynomial degree less than 64 push.0.0.0.0 push.0.0.0.0 push.0.0.0.0 # => [Y, Y, 0, 0, 0, 0 ptr_remainder, remainder_size, y, y] # adv_load remainder polynomial - # TODO: This is a workaround since the FRI verifier expects the memory layout to be - # [query_ptr ... layer_ptr ... rem_ptr ...] which leaves only one option for laying out - # the polynomial coefficients i.e. starting at remainder_ptr + remainder_codeword_length/2. - # On the other hand, we need to check that the hash of the polynomial coefficients agrees with - # the commitment already received by the prover. Thus the need for hashing the polynomial - # coefficients first. - adv_loadw - dup.12 - add.64 - mem_storew - swapw - adv_loadw - dup.12 - add.68 - mem_storew - hperm - # => [Y, Remainder_poly_com, Y, ptr_remainder, remainder_size, y, y] + repeat.16 + adv_pipe hperm + end # Compare Remainder_poly_com with the read commitment exec.constants::tmp7 mem_loadw @@ -229,47 +215,18 @@ export.load_and_verify_remainder movup.2 assert_eq assert_eq - # => [Y, ptr_remainder, remainder_size, y, y] - push.0.0.0.0 - push.0.0.0.0 - repeat.8 - adv_pipe hperm - end + else - # Remainder length equal to 64 + # Remainder polynomial degree less than 128 push.0.0.0.0 push.0.0.0.0 push.0.0.0.0 # => [Y, Y, 0, 0, 0, 0 ptr_remainder, remainder_size, y, y] # adv_load remainder polynomial - # TODO: This is a workaround since the FRI verifier expects the memory layout to be - # [query_ptr ... layer_ptr ... rem_ptr ...] which leaves only one option for laying out - # the polynomial coefficients i.e. starting at remainder_ptr + remainder_codeword_length/2. - # On the other hand, we need to check that the hash of the polynomial coefficients agrees with - # the commitment already received by the prover. Thus the need for hashing the polynomial - # coefficients first. - adv_loadw - dup.12 - add.128 - mem_storew - swapw - adv_loadw - dup.12 - add.132 - mem_storew - hperm - - adv_loadw - dup.12 - add.136 - mem_storew - swapw - adv_loadw - dup.12 - add.140 - mem_storew - hperm + repeat.32 + adv_pipe hperm + end # => [Y, Remainder_poly_com, Y, ptr_remainder, remainder_size, y, y] # Compare Remainder_poly_com with the read commitment @@ -281,36 +238,8 @@ export.load_and_verify_remainder movup.2 assert_eq assert_eq - # => [Y, ptr_remainder, remainder_size, y, y] - push.0.0.0.0 - push.0.0.0.0 - repeat.16 - adv_pipe hperm - end - end - # => [Y, R, Y, Y] where R = [y, y, tau1, tau0] - - dropw - swapw.2 - dropw - drop - drop - #=> [Y, tau1, tau0] where tau is the challenge of ext2fri::verify_remainder_xx - - # Prepare for remainder verification procedure - exec.constants::tmp8 mem_loadw - movup.2 drop - movup.2 drop - # => [ptr_remainder, remainder_size, tau1, tau0] - - # Call the correct remainder verification procedure - movdn.3 - push.32 - eq - if.true - exec.ext2fri::verify_remainder_32 - else - exec.ext2fri::verify_remainder_64 + end + dropw dropw #=> [...] end diff --git a/stdlib/asm/crypto/stark/constants.masm b/stdlib/asm/crypto/stark/constants.masm index ef7f5aedf..bff78936a 100644 --- a/stdlib/asm/crypto/stark/constants.masm +++ b/stdlib/asm/crypto/stark/constants.masm @@ -79,25 +79,25 @@ const.DEEP_RAND_CC_PTR=4294912000 const.FRI_COM_PTR=4294912800 # Commitment to main, auxiliary and composition polynomials traces -const.MAIN_TRACE_COM_PTR=4294913200 -const.AUX_TRACE_COM_PTR=4294913204 -const.COMPOSITION_POLY_COM_PTR=4294913208 +const.MAIN_TRACE_COM_PTR=4294813200 +const.AUX_TRACE_COM_PTR=4294813204 +const.COMPOSITION_POLY_COM_PTR=4294813208 # Instant-specific constants -const.LDE_SIZE_PTR=4294913212 -const.Z_PTR=4294913216 -const.NUM_QUERIES_PTR=4294913220 -const.TRACE_LENGTH_PTR=4294913224 -const.TRACE_LENGTH_LOG_PTR=4294913228 -const.GRINDING_FACTOR_PTR=4294913232 +const.LDE_SIZE_PTR=4294813212 +const.Z_PTR=4294813216 +const.NUM_QUERIES_PTR=4294813220 +const.TRACE_LENGTH_PTR=4294813224 +const.TRACE_LENGTH_LOG_PTR=4294813228 +const.GRINDING_FACTOR_PTR=4294813232 # RPO capacity initialization words -const.ZERO_WORD_PTR=4294913236 +const.ZERO_WORD_PTR=4294813236 # State of RPO-based random coin -const.C_PTR=4294913244 -const.R1_PTR=4294913248 -const.R2_PTR=4294913252 +const.C_PTR=4294813244 +const.R1_PTR=4294813248 +const.R2_PTR=4294813252 # Address used for storing temporary values: const.TMP1=4294913256 diff --git a/stdlib/asm/crypto/stark/verifier.masm b/stdlib/asm/crypto/stark/verifier.masm index 4d2a69b4d..b5ef27d85 100644 --- a/stdlib/asm/crypto/stark/verifier.masm +++ b/stdlib/asm/crypto/stark/verifier.masm @@ -28,10 +28,15 @@ use.std::crypto::stark::utils #! Output: [...] #! #! Cycles: -#! 1- Remainder codeword size 32: -#! 2000 + num_queries * (495 + num_fri_layers * 86) + 108 * num_fri_layers + 10 * log(trace_length) + 1526 -#! 2- Remainder codeword size 64: -#! 2000 + num_queries * (495 + num_fri_layers * 86) + 108 * num_fri_layers + 10 * log(trace_length) + 2863 +#! 1- Remainder polynomial size 64: +#! 2175 + num_queries * (512 + num_fri_layers * 83) + 108 * num_fri_layers + 10 * log(trace_length) +#! 2- Remainder polynomial size 128: +#! 2200 + num_queries * (541 + num_fri_layers * 83) + 108 * num_fri_layers + 10 * log(trace_length) +#! +#! where num_fri_layers is computed as: +#! +#! 1- If log(trace_length) is even, then num_fri_layers = (log(trace_length) - 6) / 2, where 6 = log2(64), +#! 2- If log(trace_length) is odd, then num_fri_layers = (log(trace_length) - 7) / 2, where 7 = log2(128). export.verify #============================================================================================== @@ -181,17 +186,15 @@ export.verify # => [...] #============================================ - # 4) Remainder verification: - # a) Check commitment to remainder polynomial - # coefficients. - # b) Load the NTT of remainder polynomial - # into memory. - # c) Check the NTT relationship. + # 4) Load and check commitment to remainder + # polynomial. #============================================ # Cycles: - # 1- Remainder of size 32: 1526 - # 2- Remainder of size 64: 2863 + # 1- Remainder polynomial of degree less + # than 64: 157 + # 2- Remainder polynomial of degree less + # than 128: 191 exec.helper::load_and_verify_remainder # => [...] @@ -204,7 +207,6 @@ export.verify exec.random_coin::check_pow # => [...] - #============================================ # 6) Compute evaluations of DEEP composition # polynomial at randomly chosen query positions @@ -256,9 +258,21 @@ export.verify movup.3 # => [query_ptr, fri_layer_ptr, remainder_ptr, domain_gen, ...] + padw exec.constants::tmp8 mem_loadw + drop movdn.2 drop drop + # Call FRI verifier # - # Cycles: 7 + 4 + num_queries * (89 + num_layers * 86) - exec.frie2f4::verify + # Cycles: + # 1- Remainder of size 64: 18 + num_queries * (107 + num_layers * 83) + # 2- Remainder of size 128: 18 + num_queries * (140 + num_layers * 83) + push.512 + eq + + if.true + exec.frie2f4::verify_64 + else + exec.frie2f4::verify_128 + end # => [...] end diff --git a/stdlib/tests/crypto/stark/mod.rs b/stdlib/tests/crypto/stark/mod.rs index 66ab2128b..6e87afadd 100644 --- a/stdlib/tests/crypto/stark/mod.rs +++ b/stdlib/tests/crypto/stark/mod.rs @@ -53,7 +53,7 @@ pub fn generate_recursive_verifier_data( let mut host = DefaultHost::new(advice_provider); let options = - ProvingOptions::new(27, 8, 16, FieldExtension::Quadratic, 4, 7, HashFunction::Rpo256); + ProvingOptions::new(27, 8, 16, FieldExtension::Quadratic, 4, 127, HashFunction::Rpo256); let (stack_outputs, proof) = prove(&program, stack_inputs.clone(), &mut host, options).unwrap(); diff --git a/stdlib/tests/crypto/stark/verifier_recursive/mod.rs b/stdlib/tests/crypto/stark/verifier_recursive/mod.rs index e884d5efd..6b28859a6 100644 --- a/stdlib/tests/crypto/stark/verifier_recursive/mod.rs +++ b/stdlib/tests/crypto/stark/verifier_recursive/mod.rs @@ -13,7 +13,6 @@ use winter_fri::VerifierChannel as FriVerifierChannel; mod channel; use channel::VerifierChannel; -pub const BLOWUP_FACTOR: usize = 8; pub type QuadExt = QuadExtension; #[derive(Debug, Clone, Eq, PartialEq)] @@ -127,16 +126,10 @@ pub fn generate_advice_inputs( let fri_commitments_digests = channel.read_fri_layer_commitments(); let poly = channel.read_remainder().unwrap(); - // Reed-Solomon encode the remainder polynomial as this is needed for the probabilistic NTT - let twiddles = fft::get_twiddles(poly.len()); - let fri_remainder = - fft::evaluate_poly_with_offset(&poly, &twiddles, Felt::GENERATOR, BLOWUP_FACTOR); - // add the above to the advice tape let fri_commitments: Vec = digest_to_int_vec(&fri_commitments_digests); advice_stack.extend_from_slice(&fri_commitments); advice_stack.extend_from_slice(&to_int_vec(&poly)); - advice_stack.extend_from_slice(&to_int_vec(&fri_remainder)); // reseed with FRI layer commitments let _deep_coefficients = air From 9655d81837abe8987ad3a31beb21bf601fcf30e7 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 18 Mar 2025 12:49:57 +0100 Subject: [PATCH 05/14] wip rebase on next --- processor/src/operations/horner_ops.rs | 3 +- processor/src/stack/mod.rs | 1 + stdlib/asm/crypto/stark/random_coin.masm | 4 +-- stdlib/tests/crypto/falcon.rs | 1 - stdlib/tests/crypto/fri/channel.rs | 10 ++---- stdlib/tests/crypto/fri/mod.rs | 8 ++--- stdlib/tests/crypto/fri/verifier_fri_e2f4.rs | 31 +++++++++++++------ .../crypto/stark/verifier_recursive/mod.rs | 5 +-- 8 files changed, 34 insertions(+), 29 deletions(-) diff --git a/processor/src/operations/horner_ops.rs b/processor/src/operations/horner_ops.rs index 88526d923..cf7309c77 100644 --- a/processor/src/operations/horner_ops.rs +++ b/processor/src/operations/horner_ops.rs @@ -1,5 +1,4 @@ -use miden_air::trace::decoder::NUM_USER_OP_HELPERS; -use vm_core::{Felt, Operation, ZERO}; +use vm_core::{Felt, Operation}; use crate::{ExecutionError, Process, QuadFelt}; diff --git a/processor/src/stack/mod.rs b/processor/src/stack/mod.rs index 9561bc882..c75ebfd2a 100644 --- a/processor/src/stack/mod.rs +++ b/processor/src/stack/mod.rs @@ -133,6 +133,7 @@ impl Stack { /// # Errors /// Returns an error if the overflow table is not empty at the current clock cycle. pub fn build_stack_outputs(&self) -> Result { + std::println!("stack state is {:?}", self.get_state_at(self.clk)); if self.overflow.num_active_rows() != 0 { return Err(ExecutionError::OutputStackOverflow(self.overflow.num_active_rows())); } diff --git a/stdlib/asm/crypto/stark/random_coin.masm b/stdlib/asm/crypto/stark/random_coin.masm index 924856a9c..cb62ada2d 100644 --- a/stdlib/asm/crypto/stark/random_coin.masm +++ b/stdlib/asm/crypto/stark/random_coin.masm @@ -180,7 +180,7 @@ export.init_seed push.0xffffffff # upper half of the modulus ## field extension and FRI parameters ## field extension degree || FRI folding factor || FRI remainder polynomial max degree || blowup factor - push.0x02040708 + push.0x02047f08 # => [proof_options, modulus1, modulus0, trace_info, trace_length, num_queries, blowup, grinding, ...] # Hash proof context @@ -191,7 +191,7 @@ export.init_seed exec.constants::get_num_constraints movdn.3 - # => [num_queries, grinding, proof_options, NUM_CONSTRAINTS, modulus1, modulus0, trace_length, trace_info, ...] + # => [num_queries, grinding, proof_options, num_constraints, modulus1, modulus0, trace_length, trace_info, ...] push.4.0.0.0 movdnw.2 diff --git a/stdlib/tests/crypto/falcon.rs b/stdlib/tests/crypto/falcon.rs index 5cc7c8786..02d025134 100644 --- a/stdlib/tests/crypto/falcon.rs +++ b/stdlib/tests/crypto/falcon.rs @@ -145,7 +145,6 @@ fn test_falcon512_probabilistic_product() { test.expect_stack(expected_stack); } -#[ignore = "needs horner_eval_base op"] #[test] fn test_falcon512_probabilistic_product_failure() { // create two random polynomials and generate the input operand stack and advice stack to diff --git a/stdlib/tests/crypto/fri/channel.rs b/stdlib/tests/crypto/fri/channel.rs index 5ad2382a3..d91776623 100644 --- a/stdlib/tests/crypto/fri/channel.rs +++ b/stdlib/tests/crypto/fri/channel.rs @@ -1,8 +1,7 @@ use processor::Digest; use test_utils::{ - Felt, FieldElement, MerkleTreeVC, StarkField, + Felt, FieldElement, MerkleTreeVC, crypto::{BatchMerkleProof, ElementHasher, Hasher as HasherTrait, PartialMerkleTree}, - math::fft, serde::DeserializationError, }; use winter_fri::{FriProof, VerifierError}; @@ -77,11 +76,6 @@ where let commitment = H::hash_elements(&poly); assert_eq!(&commitment, expected_commitment); - // Compute remainder codeword corresponding to remainder polynomial - let twiddles = fft::get_twiddles(poly.len()); - let remainder = - fft::evaluate_poly_with_offset(&poly, &twiddles, E::BaseField::GENERATOR, 8); - - Ok(remainder) + Ok(poly) } } diff --git a/stdlib/tests/crypto/fri/mod.rs b/stdlib/tests/crypto/fri/mod.rs index 7c8de87d8..036fb9183 100644 --- a/stdlib/tests/crypto/fri/mod.rs +++ b/stdlib/tests/crypto/fri/mod.rs @@ -11,13 +11,13 @@ pub use verifier_fri_e2f4::*; mod remainder; #[test] -fn fri_fold4_ext2_remainder32() { +fn fri_fold4_ext2_remainder64() { let source = " use.std::crypto::fri::frie2f4 begin exec.frie2f4::preprocess - exec.frie2f4::verify + exec.frie2f4::verify_128 end "; @@ -59,13 +59,13 @@ fn fri_fold4_ext2_remainder32() { } #[test] -fn fri_fold4_ext2_remainder64() { +fn fri_fold4_ext2_remainder128() { let source = " use.std::crypto::fri::frie2f4 begin exec.frie2f4::preprocess - exec.frie2f4::verify + exec.frie2f4::verify_128 end "; diff --git a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs index 43d2b0b88..894e5343c 100644 --- a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs +++ b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs @@ -53,7 +53,7 @@ pub struct FriResult { // a FRI proof inside the Miden VM. // The output is organized as follows: pub fn fri_prove_verify_fold4_ext2(trace_length_e: usize) -> Result { - let max_remainder_size_e = 3; + let max_remainder_size_e = 7; let folding_factor_e = 2; let trace_length = 1 << trace_length_e; let lde_blowup = 1 << 3; @@ -93,10 +93,7 @@ pub fn fri_prove_verify_fold4_ext2(trace_length_e: usize) -> Result = proof.parse_remainder().expect("should return remainder polynomial"); - let twiddles = fft::get_twiddles(remainder_poly.len()); - let remainder = fft::evaluate_poly_with_offset(&remainder_poly, &twiddles, Felt::GENERATOR, 8); - - let remainder: Vec = QuadExt::slice_as_base_elements(&remainder[..]) + let remainder: Vec = QuadExt::slice_as_base_elements(&&remainder_poly[..]) .to_owned() .iter() .map(|a| a.as_int()) @@ -255,7 +252,7 @@ impl FriVerifierFold4Ext2 { let advice_provider = channel.unbatch::<4, 3>(&positions, self.domain_size(), self.layer_commitments.clone()); - let mut d_generator; + let mut d_generator = self.domain_generator; let mut all_alphas = vec![]; let mut all_position_evaluation = vec![]; for (index, &position) in positions.iter().enumerate() { @@ -281,9 +278,14 @@ impl FriVerifierFold4Ext2 { // read the remainder from the channel and make sure it matches with the columns // of the previous layer let remainder_commitment = self.layer_commitments.last().unwrap(); - let remainder = channel.read_remainder::<4>(remainder_commitment)?; - for (pos, eval) in final_pos_eval.iter() { - if remainder[*pos] != *eval { + let remainder_poly = channel.read_remainder::<4>(remainder_commitment)?; + let offset = Felt::GENERATOR; + for &(final_pos, final_eval) in final_pos_eval.iter() { + let comp_eval = eval_horner_rev( + &remainder_poly, + offset * d_generator.exp_vartime((final_pos as u64).into()), + ); + if comp_eval != final_eval { return Err(VerifierError::InvalidRemainderFolding); } } @@ -451,7 +453,9 @@ impl UnBatch for MidenFriVerifierChannel(f_x: E, f_minus_x: E, x_star: E, alpha: E) -> E where B: StarkField, @@ -459,3 +463,10 @@ where { (f_x + f_minus_x + ((f_x - f_minus_x) * alpha / x_star)) / E::ONE.double() } + +pub fn eval_horner_rev(p: &[E], x: E::BaseField) -> E +where + E: FieldElement, +{ + p.iter().fold(E::ZERO, |acc, &coeff| acc * E::from(x) + coeff) +} diff --git a/stdlib/tests/crypto/stark/verifier_recursive/mod.rs b/stdlib/tests/crypto/stark/verifier_recursive/mod.rs index 6b28859a6..c0b2d5557 100644 --- a/stdlib/tests/crypto/stark/verifier_recursive/mod.rs +++ b/stdlib/tests/crypto/stark/verifier_recursive/mod.rs @@ -3,10 +3,11 @@ use alloc::vec::Vec; use miden_air::ProcessorAir; use processor::crypto::RpoRandomCoin; use test_utils::{ - Felt, VerifierError, + VerifierError, crypto::{MerkleStore, RandomCoin, Rpo256, RpoDigest}, - math::{FieldElement, QuadExtension, StarkField, ToElements, fft}, + math::{FieldElement, QuadExtension, ToElements}, }; +use vm_core::Felt; use winter_air::{Air, proof::Proof}; use winter_fri::VerifierChannel as FriVerifierChannel; From 727a12ecf404c4ee8038a4d697d52da2fb8caf6a Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 18 Mar 2025 18:16:50 +0100 Subject: [PATCH 06/14] fix FRI verify tests and clean up the verifier --- stdlib/asm/crypto/fri/frie2f4.masm | 93 ++++++++--- stdlib/asm/crypto/fri/helper.masm | 79 +++++---- stdlib/asm/crypto/stark/constants.masm | 125 +++++++++++--- stdlib/asm/crypto/stark/deep_queries.masm | 16 +- stdlib/asm/crypto/stark/public_inputs.masm | 17 +- stdlib/asm/crypto/stark/random_coin.masm | 166 ++----------------- stdlib/asm/crypto/stark/verifier.masm | 59 +------ stdlib/tests/crypto/fri/mod.rs | 4 +- stdlib/tests/crypto/fri/verifier_fri_e2f4.rs | 23 ++- 9 files changed, 287 insertions(+), 295 deletions(-) diff --git a/stdlib/asm/crypto/fri/frie2f4.masm b/stdlib/asm/crypto/fri/frie2f4.masm index 8ec1eeaed..e0a3295a8 100644 --- a/stdlib/asm/crypto/fri/frie2f4.masm +++ b/stdlib/asm/crypto/fri/frie2f4.masm @@ -9,8 +9,14 @@ use.std::crypto::stark::constants #! TODO: This pre-processing function should in fact compute d_size and t_depth for each C #! starting from the original domain size. export.preprocess.16 - locaddr.12 - adv_push.1 #[num_queries, query_ptr, g, ..] + adv_push.1 + # => [num_queries, g, ...] + exec.constants::fri_com_ptr + # => [layer_ptr, num_queries, g, ...] + dup.1 mul.4 sub + # => [query_ptr, num_queries, g, ...] + dup exec.constants::set_fri_queries_address + swap sub.1 push.0.0.0.0 push.1 @@ -38,7 +44,7 @@ export.preprocess.16 mul.2 sub.1 movdn.4 - #=> [X, layer_ptr, num_layers, layer_ptr, g] + #=> [X, num_layers, layer_ptr, layer_ptr, g] push.1 while.true @@ -52,19 +58,21 @@ export.preprocess.16 swap.5 neq.0 end - #=> [X, x, remainder_ptr, layer_ptr, g] + #=> [X, x, remainder_poly_address_ptr, layer_ptr, g] drop - #=> [X, remainder_ptr, layer_ptr, g] + #=> [X, remainder_poly_address_ptr, layer_ptr, g] dup.4 movdn.5 - #=> [X, remainder_ptr, remainder_ptr, layer_ptr, g] + #=> [X, remainder_poly_address_ptr, remainder_poly_address_ptr, layer_ptr, g] adv_push.1 + dup mul.2 exec.constants::set_remainder_poly_size + sub.1 movdn.4 - #=> [X, remainder_ptr, len_remainder/2, remainder_ptr, layer_ptr, g] + #=> [X, len_remainder/2, remainder_poly_address_ptr, remainder_poly_address_ptr, layer_ptr, g] push.1 while.true @@ -78,12 +86,12 @@ export.preprocess.16 swap.5 neq.0 end - #=> [X, x, x, remainder_ptr, layer_ptr, g] + #=> [X, x, x, remainder_poly_address_ptr, layer_ptr, g] dropw drop drop + #=> [remainder_poly_address_ptr, layer_ptr, g] - swap - locaddr.12 - #=> [query_ptr, layer_ptr, remainder_ptr, g] + exec.constants::set_remainder_poly_address + drop drop end #! Checks that, for a query with index p at layer i, the folding procedure to create layer (i + 1) @@ -290,7 +298,8 @@ end #! Verifies a FRI proof where the proof was generated over the quadratic extension of the base -#! field and layer folding was performed using folding factor 4. +#! field and layer folding was performed using folding factor 4 when the degree of the remainder +#! polynomial is less than 64. #! #! Input: [query_ptr, layer_ptr, rem_ptr, g, ...] #! Output: [...] @@ -316,8 +325,8 @@ end #! 1. rem_ptr - 1 points to the last (alpha0, alpha1, t_depth, d_size) tuple. #! 2. layer_ptr - 1 points to the last (e0, e1, p, poe) tuple. #! -#! Cycles: 18 + num_queries * (107 + num_layers * 83) -export.verify_64.4 +#! Cycles: 24 + num_queries * (107 + num_layers * 83) +proc.verify_64.4 # store [query_ptr, layer_ptr, rem_ptr, g] to keep track of all queries # (3 cycles) @@ -331,8 +340,8 @@ export.verify_64.4 # Save a word containing a fresh accumulator for Horner evaluating the remainder polynomial, # a pointer to the evaluation point and a pointer to the location of the polynomial. - push.0.0 exec.constants::tmp2 - padw exec.constants::tmp8 mem_loadw movdn.3 drop drop drop + push.0.0 + exec.constants::tmp2 exec.constants::get_remainder_poly_address exec.constants::tmp1 mem_storew movup.4 @@ -364,7 +373,8 @@ export.verify_64.4 end #! Verifies a FRI proof where the proof was generated over the quadratic extension of the base -#! field and layer folding was performed using folding factor 4. +#! field and layer folding was performed using folding factor 4 when the degree of the remainder +#! polynomial is less than 128. #! #! Input: [query_ptr, layer_ptr, rem_ptr, g, ...] #! Output: [...] @@ -390,8 +400,8 @@ end #! 1. rem_ptr - 1 points to the last (alpha0, alpha1, t_depth, d_size) tuple. #! 2. layer_ptr - 1 points to the last (e0, e1, p, poe) tuple. #! -#! Cycles: 18 + num_queries * (140 + num_layers * 83) -export.verify_128.4 +#! Cycles: 24 + num_queries * (140 + num_layers * 83) +proc.verify_128.4 # store [query_ptr, layer_ptr, rem_ptr, g] to keep track of all queries # (3 cycles) @@ -405,8 +415,8 @@ export.verify_128.4 # Save a word containing a fresh accumulator for Horner evaluating the remainder polynomial, # a pointer to the evaluation point and a pointer to the location of the polynomial. - push.0.0 exec.constants::tmp2 - padw exec.constants::tmp8 mem_loadw movdn.3 drop drop drop + push.0.0 + exec.constants::tmp2 exec.constants::get_remainder_poly_address exec.constants::tmp1 mem_storew movup.4 @@ -436,3 +446,44 @@ export.verify_128.4 dropw dropw end + +#! Verifies a FRI proof where the proof was generated over the quadratic extension of the base +#! field and layer folding was performed using folding factor 4. +#! +#! Input: [...] +#! Output: [...] +#! +#! Cycles: +#! +#! Polynomial degree less than 64: 24 + num_queries * (107 + num_layers * 83) +#! Polynomial degree less than 128: 24 + num_queries * (140 + num_layers * 83) +export.verify + + # Get domain generator and pointer to the remainder codeword + # (4 cycles) + exec.constants::get_lde_domain_generator + exec.constants::get_remainder_poly_address + # => [remainder_poly_address_ptr, g, ...] + + # Get the pointer to the first layer commitment + # (1 cycles) + exec.constants::fri_com_ptr + # => [fri_layer_ptr, remainder_poly_address_ptr, g, ...] + + # Get the pointer to the first FRI query to the top + # (2 cycles) + exec.constants::get_fri_queries_address + # => [query_ptr, fri_layer_ptr, remainder_poly_address_ptr, g, ...] + + + exec.constants::get_remainder_poly_size + push.64 + eq + + if.true + exec.verify_64 + else + exec.verify_128 + end + # => [...] +end diff --git a/stdlib/asm/crypto/fri/helper.masm b/stdlib/asm/crypto/fri/helper.masm index 6959d62c0..53ccf8a47 100644 --- a/stdlib/asm/crypto/fri/helper.masm +++ b/stdlib/asm/crypto/fri/helper.masm @@ -10,7 +10,7 @@ use.std::crypto::stark::constants #! Cycles: 77 export.generate_fri_parameters # Load FRI verifier data - padw exec.constants::lde_size_ptr mem_loadw + padw exec.constants::get_lde_domain_info #=> [lde_size, log(lde_size), lde_g, 0, ...] (6 cycles) # Store in `TMP5` in order to use it for fri layer loading @@ -35,7 +35,7 @@ export.generate_fri_parameters #=> [z1, z0, z1, z0, lde_size, log2(lde_size), lde_g, 0, ...] (6 cycles) # Load `trace_g` from memory - exec.constants::trace_domain_generator_ptr mem_load + exec.constants::get_trace_domain_generator #=> [trace_g, z1, z0, z1, z0, lde_size, log2(lde_size), lde_g, 0, ...] (2 cycles) # Compute `gz0` = `trace_g * z_0` @@ -72,29 +72,27 @@ export.generate_fri_parameters end # => [num_fri_layers, remainder_size, lde_size, lde_size, log2(lde_size), domain_gen, 0, ...] (12 cycles) - # Save `[num_fri_layers, remainder_size, lde_size, lde_size]` in memory - exec.constants::tmp6 mem_storew - swap div.8 swap - movdn.6 + exec.constants::set_num_fri_layers + div.8 + exec.constants::set_remainder_poly_size + # => [lde_size, lde_size, log2(lde_size), domain_gen, 0, ...] (7 cycles) + dropw drop - drop - # => [num_fri_layers, ...] (10 cycles) + # => [...] (5 cycles) end #! Get FRI layer commitments and reseed with them in order to draw folding challenges i.e. alphas. #! -#! Input: [ptr_layer, num_layers, ...] +#! Input: [...] #! Output: [...] #! Cycles: 21 + 83 * num_fri_layers export.load_fri_layer_commitments # Address containing the first layer commitment push.0.0 - movup.3 - movup.3 - swap push.0.0.0.0 - swapw + exec.constants::fri_com_ptr + exec.constants::get_num_fri_layers # => [num_layers, ptr_layer, y, y, Y, ...] dup @@ -176,22 +174,20 @@ export.load_and_verify_remainder exec.random_coin::reseed #=> [...] - # adv_pipe the remainder codeword - ## Get the length of remainder - padw exec.constants::tmp6 mem_loadw - ## Compute the correct remainder pointer using length of remainder - exec.constants::fri_com_ptr - #=> [fri_com_ptr, num_fri_layers, remainder_size, lde_size, lde_size] - - swap - mul.8 - add + # `adv_pipe` the remainder codeword + ## Get the numbers of FRI layers + exec.constants::get_num_fri_layers + ## Compute the correct remainder pointer, note that the remainder poly is laid out just after + ## the FRI layer commitments, each saved in a word, and folding challenges, also saved in + ## a word, and this explains the multiplication by 8 + mul.8 exec.constants::fri_com_ptr add + #=> [fri_com_ptr, 8 * num_fri_layers, ...] ## Store for later use - exec.constants::tmp8 mem_storew - #=> [ptr_remainder, remainder_size, y, y] + dup exec.constants::set_remainder_poly_address + #=> [remainder_poly_ptr, ...] - dup.1 - push.512 + exec.constants::get_remainder_poly_size + push.64 eq if.true @@ -199,7 +195,7 @@ export.load_and_verify_remainder push.0.0.0.0 push.0.0.0.0 push.0.0.0.0 - # => [Y, Y, 0, 0, 0, 0 ptr_remainder, remainder_size, y, y] + # => [Y, Y, 0, 0, 0, 0 remainder_poly_ptr, remainder_size, y, y] # adv_load remainder polynomial repeat.16 @@ -221,13 +217,13 @@ export.load_and_verify_remainder push.0.0.0.0 push.0.0.0.0 push.0.0.0.0 - # => [Y, Y, 0, 0, 0, 0 ptr_remainder, remainder_size, y, y] + # => [Y, Y, 0, 0, 0, 0 remainder_poly_ptr, remainder_size, y, y] # adv_load remainder polynomial repeat.32 adv_pipe hperm end - # => [Y, Remainder_poly_com, Y, ptr_remainder, remainder_size, y, y] + # => [Y, Remainder_poly_com, Y, remainder_poly_ptr, remainder_size, y, y] # Compare Remainder_poly_com with the read commitment exec.constants::tmp7 mem_loadw @@ -243,3 +239,26 @@ export.load_and_verify_remainder dropw dropw #=> [...] end + +#! Compute the pointer to the first word storing the FRI queries. +#! +#! Since the FRI queries are laid out just before the FRI commitments, we compute the address +#! to the first FRI query by subtracting from the pointer to the first FRI layer commitment +#! the total number of queries. +#! +#! Input: [...] +#! Output: [...] +#! +#! Cycles: 7 +export.compute_query_pointer + exec.constants::fri_com_ptr + exec.constants::get_number_queries + mul.4 + # => [num_queries*4, fri_com_ptr, ...] + + sub + # => [query_ptr, ...] + + exec.constants::set_fri_queries_address + # => [...] +end diff --git a/stdlib/asm/crypto/stark/constants.masm b/stdlib/asm/crypto/stark/constants.masm index bff78936a..340c73785 100644 --- a/stdlib/asm/crypto/stark/constants.masm +++ b/stdlib/asm/crypto/stark/constants.masm @@ -41,15 +41,10 @@ const.CURRENT_TRACE_ROW_PTR=4294900400 # There are are currently 16 ExtFelt for a total of 32 Felt. Thus the number of memory slots required is 32. const.AUX_RAND_ELEM_PTR=4294900600 -# We need 2 Felt for each constraint. We take 112000 slots as an upper bound +# Address to the randomness used in computing the constraint composition polynomial const.COMPOSITION_COEF_PTR=4294900800 -# We need 2 Felt for each trace column and each of the 8 constraint composition columns. We thus need -# (71 + 7 + 8) * 2 = 172 Felt i.e. 172 memory slots. -# Note that there is a cap on the number of such coefficients so that the memory region allocated for -# these coefficients does not overlap with the memory region storing the FRI queries. -# This cap is of a 100 coefficients which is equivalent to 200 memory slots. This gives 600 memory -# slots for all of the FRI queries i.e., 150 FRI queries. +# Address to the randomness used in computing the DEEP polynomial const.DEEP_RAND_CC_PTR=4294912000 # FRI @@ -64,18 +59,17 @@ const.DEEP_RAND_CC_PTR=4294912000 # . # (FRI_COM_PTR + 128) ---| # . -# . | <- Remainder codeword and polynomial +# . | <- Remainder polynomial # . -# (FRI_COM_PTR + 264-1) ---| +# (FRI_COM_PTR + 256-1) ---| # # For each FRI layer, we need 8 memory slots, one for storing the FRI layer commitment and one for # storing the word [a0, a1, log2(lde_size), lde_size] where a := (a0, a1) is the folding randomness -# and lde_size is the size of the LDE domain. Since we are using a folding factor of 4 and the -# maximal degree of the remainder polynomial that we allow is 7, an upper limit of 16 FRI layers is -# ample and the number of memory slots we thus allocate for this is 128. Moreover, we allocate -# an additional 128 slots for the remainder codeword and 8 for the remainder polynomial. These are -# expected to be laid out right after the FRI commitments. -# The total number of slots thus becomes 264. +# and lde_size is the size of the LDE domain of the corresponding FRI layer. +# Since we are using a folding factor of 4 and the maximal degree of the remainder polynomial +# that we allow is 127, an upper limit of 16 FRI layers is ample and the number of memory slots +# we thus allocate for this is 128. Moreover, we allocate an additional 128 slots for the remainder +# polynomial which is expected to be laid out right after the FRI commitments. const.FRI_COM_PTR=4294912800 # Commitment to main, auxiliary and composition polynomials traces @@ -84,10 +78,15 @@ const.AUX_TRACE_COM_PTR=4294813204 const.COMPOSITION_POLY_COM_PTR=4294813208 # Instant-specific constants -const.LDE_SIZE_PTR=4294813212 +const.LDE_DOMAIN_INFO_PTR=4294813212 +const.LDE_DOMAIN_GEN_PTR=4294813213 const.Z_PTR=4294813216 const.NUM_QUERIES_PTR=4294813220 +const.REMAINDER_POLY_SIZE_PTR=4294813221 +const.REMAINDER_POLY_ADDRESS_PTR=4294813223 +const.NUM_FRI_LAYERS_PTR=4294813222 const.TRACE_LENGTH_PTR=4294813224 +const.FRI_QUERIES_ADDRESS_PTR=4294813225 const.TRACE_LENGTH_LOG_PTR=4294813228 const.GRINDING_FACTOR_PTR=4294813232 @@ -161,7 +160,7 @@ const.ALPHA_POWER_85_1_PTR=4294903445 # | MAIN_TRACE_COM_PTR | 4294913200 | # | AUX_TRACE_COM_PTR | 4294913204 | # | COMPOSITION_POLY_COM_PTR | 4294913208 | -# | LDE_SIZE_PTR | 4294913212 | +# | LDE_DOMAIN_INFO_PTR | 4294913212 | # | Z_PTR | 4294913216 | # | NUM_QUERIES_PTR | 4294913220 | # | TRACE_LENGTH_PTR | 4294913224 | @@ -226,6 +225,14 @@ export.trace_domain_generator_ptr push.TRACE_DOMAIN_GENERATOR_PTR end +export.set_trace_domain_generator + push.TRACE_DOMAIN_GENERATOR_PTR mem_store +end + +export.get_trace_domain_generator + push.TRACE_DOMAIN_GENERATOR_PTR mem_load +end + export.domain_offset push.DOMAIN_OFFSET end @@ -234,6 +241,18 @@ export.domain_offset_inv push.DOMAIN_OFFSET_INV end +export.lde_domain_generator_ptr + push.LDE_DOMAIN_GEN_PTR +end + +export.set_lde_domain_generator + push.LDE_DOMAIN_GEN_PTR mem_store +end + +export.get_lde_domain_generator + push.LDE_DOMAIN_GEN_PTR mem_load +end + export.public_inputs_ptr push.PUBLIC_INPUTS_PTR end @@ -285,8 +304,16 @@ end #! Address to store details about the lde size. #! #! Memory is `[lde_size, log(lde_size), lde_g, 0]` -export.lde_size_ptr - push.LDE_SIZE_PTR +export.lde_domain_info_ptr + push.LDE_DOMAIN_INFO_PTR +end + +export.set_lde_domain_info + push.LDE_DOMAIN_INFO_PTR mem_storew +end + +export.get_lde_domain_info + push.LDE_DOMAIN_INFO_PTR mem_loadw end #! Address for the point `z` and its exponentiation `z^N` where `N=trace_len`. @@ -300,6 +327,62 @@ export.number_queries_ptr push.NUM_QUERIES_PTR end +export.set_number_queries + push.NUM_QUERIES_PTR mem_store +end + +export.get_number_queries + push.NUM_QUERIES_PTR mem_load +end + +export.remainder_poly_size_ptr + push.REMAINDER_POLY_SIZE_PTR +end + +export.set_remainder_poly_size + push.REMAINDER_POLY_SIZE_PTR mem_store +end + +export.get_remainder_poly_size + push.REMAINDER_POLY_SIZE_PTR mem_load +end + +export.num_fri_layers_ptr + push.NUM_FRI_LAYERS_PTR +end + +export.set_num_fri_layers + push.NUM_FRI_LAYERS_PTR mem_store +end + +export.get_num_fri_layers + push.NUM_FRI_LAYERS_PTR mem_load +end + +export.remainder_poly_address_ptr + push.REMAINDER_POLY_ADDRESS_PTR +end + +export.set_remainder_poly_address + push.REMAINDER_POLY_ADDRESS_PTR mem_store +end + +export.get_remainder_poly_address + push.REMAINDER_POLY_ADDRESS_PTR mem_load +end + +export.fri_queries_address_ptr + push.FRI_QUERIES_ADDRESS_PTR +end + +export.set_fri_queries_address + push.FRI_QUERIES_ADDRESS_PTR mem_store +end + +export.get_fri_queries_address + push.FRI_QUERIES_ADDRESS_PTR mem_load +end + export.trace_length_ptr push.TRACE_LENGTH_PTR end @@ -403,6 +486,10 @@ export.deep_rand_alpha_inv push.ALPHA_INV end +export.ood_constraint_evals_next_ptr + push.OOD_TRACE_NEXT_PTR +end + export.deep_rand_alpha_1 push.ALPHA_POWER_1_PTR end diff --git a/stdlib/asm/crypto/stark/deep_queries.masm b/stdlib/asm/crypto/stark/deep_queries.masm index b32fb7eab..69b03022a 100644 --- a/stdlib/asm/crypto/stark/deep_queries.masm +++ b/stdlib/asm/crypto/stark/deep_queries.masm @@ -575,7 +575,7 @@ end #! Cycles: 58 proc.compute_denominators # Compute x = offset * domain_gen^index - exec.constants::lde_size_ptr mem_loadw + exec.constants::lde_domain_info_ptr mem_loadw #=> [lde_size, depth, domain_gen, 0, Y, index, ...] movup.2 dup.8 @@ -647,12 +647,16 @@ end #! Compute the DEEP composition polynomial FRI queries. #! -#! Input: [query_ptr, ...] -#! Output: [query_ptr, ...] +#! Input: [...] +#! Output: [...] #! Cycles: 386 + num_queries * 414 export.compute_deep_composition_polynomial_queries exec.compute_adjustment_power_z_quotients # (Cycles: 146) + # => [...] + + exec.constants::get_fri_queries_address + # => [query_ptr, ...] exec.compute_q_z_p_gz_at_alpha # (Cycles: 200) # => [p_gz_1, p_gz_0, q_z_1, q_z_0, query_ptr, ...] @@ -678,11 +682,11 @@ export.compute_deep_composition_polynomial_queries drop drop neg swap neg # => [-z0, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] - dup.1 exec.constants::trace_domain_generator_ptr mem_load mul + dup.1 exec.constants::get_trace_domain_generator mul # => [-gz1, -z0, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] swap # => [-z0, -gz1, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] - dup exec.constants::trace_domain_generator_ptr mem_load mul + dup exec.constants::get_trace_domain_generator mul # => [-gz0, -z0, -gz1, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] swap # => [-z0, -gz0, -gz1, -z1, query_ptr, query_end_ptr, W, query_ptr, ...] @@ -742,5 +746,5 @@ export.compute_deep_composition_polynomial_queries neq #=> [?, Y, query_ptr+1, query_end_ptr, ...] end - dropw dropw drop drop + dropw dropw drop drop drop end diff --git a/stdlib/asm/crypto/stark/public_inputs.masm b/stdlib/asm/crypto/stark/public_inputs.masm index af8151d87..0c519740f 100644 --- a/stdlib/asm/crypto/stark/public_inputs.masm +++ b/stdlib/asm/crypto/stark/public_inputs.masm @@ -1,4 +1,3 @@ - use.std::crypto::stark::constants @@ -7,18 +6,15 @@ use.std::crypto::stark::constants #! capacity registers of the hash function set to `C` resulting from hashing the proof context. #! The output D is the digest of the hashing. #! -#! Input: [public_inputs_ptr, C] -#! Output: [D] +#! Input: [C, ...] +#! Output: [D, ...] #! Cycles: 38 export.load - - # TODO: load the public inputs using public_inputs_ptr - drop - # Unhash the public inputs from the advice provider. - # The following assumes that the public inputs contain only the input and output states - # of the operand stack and both are of length exactly 16. - # TODO: generalize to any number of public inputs supported by the VM. + # The public inputs are made up of the input operand stack and the output operand stack + # both of length 16 field elements. + exec.constants::public_inputs_ptr + movdn.4 padw padw repeat.4 adv_loadw @@ -34,4 +30,5 @@ export.load dropw swapw dropw + movup.4 drop end diff --git a/stdlib/asm/crypto/stark/random_coin.masm b/stdlib/asm/crypto/stark/random_coin.masm index cb62ada2d..7732d4c64 100644 --- a/stdlib/asm/crypto/stark/random_coin.masm +++ b/stdlib/asm/crypto/stark/random_coin.masm @@ -142,7 +142,7 @@ export.init_seed #=> [lde_size, log(lde_size), lde_g, 0, trace_length, num_queries, blowup, grinding] # Save `[lde_size, log(lde_size), lde_g, 0]` - exec.constants::lde_size_ptr mem_storew + exec.constants::set_lde_domain_info #=> [lde_size, log(lde_size), lde_g, 0, trace_length, num_queries, blowup, grinding] # clean stack @@ -156,7 +156,7 @@ export.init_seed #=> [trace_g, 0, trace_length, num_queries, blowup, grinding] # Save `trace_g` to memory - exec.constants::trace_domain_generator_ptr mem_store + exec.constants::set_trace_domain_generator #=> [0, trace_length, num_queries, blowup, grinding] # clean stack @@ -316,147 +316,14 @@ proc.generate_random_coefficients #=> [...] end -#! Generates a `num_tuples` tuples of random field elements and stores them in memory -#! starting from address `dest_ptr`. Each memory word holds one tuple, e.g. `[0, 0, t0, t1]`. -#! TODO: Generalize by keeping track of something similar to the `output` variable in `RpoRandomCoin` -#! so that we keep track of already used randomness and know when there is a need to apply `hperm`. -#! -#! `dest_ptr` must be word-aligned. -#! -#! Input: [dest_ptr, num_tuples, ...] -#! Output: [...] -#! -#! Cycles: 104 + (69 * num_tuples) / 4 -proc.generate_random_coefficients_pad - - # Compute the loop counter. We use checked division to make sure the number is a multiple of 4. - # If we use field division and num_tuples is not a multiple of 4 then we will enter into - # a very large loop with high probability. - push.0 dup movup.2 movup.3 - u32assert u32divmod.4 - assertz - neg - #=> [loop_ctr, dest_ptr, x, x, ...] - # where loop_ctr = - num_tuples / 4; we negate the counter so that we can count up to 0 - - exec.get_rate_1 - dup.5 - #=> [dest_ptr, a11, a10, a01, a00, loop_ctr, dest_ptr, x, x, ...] - dup.4 - dup.4 - push.0.0 - dup.4 - #=> [dest_ptr, 0, 0, a01, a00, dest_ptr, a11, a10, a01, a00, loop_ctr, dest_ptr, x, x, ...] - - mem_storew dropw - #=> [dest_ptr, a11, a10, a01, a00, loop_ctr, dest_ptr, x, x, ...] - - dup.2 dup.2 push.0.0 - #=> [0, 0, a11, a10, dest_ptr, a11, a10, a01, a00, loop_ctr, dest_ptr, x, x, ...] - - movup.4 add.4 mem_storew - #=> [0, 0, a11, a10, a11, a10, a01, a00, loop_ctr, dest_ptr, x, x, ...] - - exec.constants::r2_ptr mem_loadw - #=> [a31, a30, a21, a20, a11, a10, a01, a00, loop_ctr, dest_ptr, x, x, ...] - - dup.9 add.16 swap.10 - #=> [dest_ptr, a31, a30, a21, a20, a11, a10, a01, a00, loop_ctr, dest_ptr+16, x, x, ...] - - dup.4 - dup.4 - push.0.0 - #=> [0, 0, a21, a20, dest_ptr, a31, a30, a21, a20, a11, a10, a01, a00, loop_ctr, dest_ptr+16, x, x, ...] - - dup.4 add.8 - mem_storew dropw - #=> [dest_ptr, a31, a30, a21, a20, a11, a10, a01, a00, loop_ctr, dest_ptr+16, x, x, ...] - - dup.2 dup.2 push.0.0 - #=> [0, 0, a31, a30, dest_ptr, a31, a30, a21, a20, a11, a10, a01, a00, loop_ctr, dest_ptr+16, x, x, ...] - - movup.4 add.12 mem_storew - #=> [0, 0, a31, a30, a31, a30, a21, a20, a11, a10, a01, a00, loop_ctr, dest_ptr+16, x, x, ...] - - exec.constants::c_ptr mem_loadw - #=> [C, a31, a30, a21, a20, a11, a10, a01, a00, loop_ctr, dest_ptr+16, x, x, ...] - - swapdw - #=> [a11, a10, a01, a00, loop_ctr, dest_ptr+16, x, x, C, a31, a30, a21, a20, ...] - swapw - #=> [loop_ctr, dest_ptr+16, x, x, R1, C, R2, ..] - - add.1 dup neq.0 - - while.true - - swapw.3 hperm - #=> [R2, R1, C, loop_ctr, dest_ptr, x, x, ...] - - # save R2 to mem[dest+4]; we use dup.13 here because it takes only 1 cycle - dup.13 - dup.4 dup.4 push.0.0 - #=> [0, 0, a31, a30, dest_ptr, R2, R1, C, loop_ctr, dest_ptr, x, x, ...] - - dup.4 add.8 - mem_storew dropw - #=> [dest_ptr, a31, a30, a21, a20, a11, a10, a01, a00, C, loop_ctr, dest_ptr, x, x, ...] - - dup.2 dup.2 push.0.0 - #=> [0, 0, a31, a30, dest_ptr, a31, a30, a21, a20, a11, a10, a01, a00, C, loop_ctr, dest_ptr, x, x, ...] - - movup.4 add.12 mem_storew dropw - #=> [a31, a30, a21, a20, a11, a10, a01, a00, C, loop_ctr, dest_ptr, x, x, ...] - - # save R1 to mem[dest] - swapw dup.13 - #=> [dest_ptr, a11, a10, a01, a00, a31, a30, a21, a20, C, loop_ctr, dest_ptr, x, x, ...] - - dup.4 dup.4 push.0.0 - #=> [0, 0, a01, a00, dest_ptr, a11, a10, a01, a00, a31, a30, a21, a20, C, loop_ctr, dest_ptr, x, x, ...] - - dup.4 - mem_storew dropw - #=> [dest_ptr, a11, a10, a01, a00, a31, a30, a21, a20, C, loop_ctr, dest_ptr, x, x, ...] - - dup.2 dup.2 push.0.0 - #=> [0, 0, a11, a10, dest_ptr, a11, a10, a01, a00, a31, a30, a21, a20, C, loop_ctr, dest_ptr, x, x, ...] - - movup.4 add.4 mem_storew dropw - #=> [a11, a10, a01, a00, a31, a30, a21, a20, C, loop_ctr, dest_ptr, x, x, ...] - - # reshuffle and update destination pointer and loop counter - swapw - swapw.3 - #=> [loop_ctr, dest_ptr, x, x, R1, C, R2, ...] - - swap add.16 swap - #=> [loop_ctr, dest_ptr+2, x, x, R1, C, R2, ...] - - add.1 dup - #=> [loop_ctr+1, loop_ctr+1, dest_ptr+2, x, x, R1, C, R2, ...] - - neq.0 - end - - # Save the new state of the random coin - dropw - exec.constants::r1_ptr mem_storew - dropw - exec.constants::c_ptr mem_storew - dropw - exec.constants::r2_ptr mem_storew - dropw - #=> [...] -end - -#! Draw a list of random extension field elements related to the auxiliary trace and store the list -#! in memory from `aux_rand_elem_ptr` to `aux_rand_elem_ptr + 32 - 4` +#! Draw a list of random extension field elements related to the auxiliary segment of the execution +#! trace and store the list in memory from `aux_rand_elem_ptr` to `aux_rand_elem_ptr + 32 - 4`. #! -#! Input: [aux_rand_elem_ptr, ...] +#! Input: [...] #! Output: [...] #! Cycles: 159 export.generate_aux_randomness + exec.constants::aux_rand_elem_ptr exec.constants::num_aux_trace_coefs swap exec.generate_random_coefficients #=> [...] @@ -466,12 +333,12 @@ end #! #! Input: [...] #! Output: [...] -#! Cycles: 12 +#! Cycles: 13 export.generate_constraint_composition_coefficients - padw exec.constants::r1_ptr mem_loadw - # => [y, y, alpha1, alpha0, compos_coef_ptr, ...] exec.constants::composition_coef_ptr - mem_storew dropw + padw exec.constants::r1_ptr mem_loadw + # => [y, y, alpha1, alpha0, compos_coef_ptr, ...] where y is a "garbage" value + movup.4 mem_storew dropw #=> [...] end @@ -479,11 +346,11 @@ end #! #! Input: [...] #! Output: [...] -#! Cycles: 14 +#! Cycles: 13 export.generate_deep_composition_random_coefficients exec.constants::deep_rand_coef_ptr padw exec.constants::r1_ptr mem_loadw - # => [y, y, alpha1, alpha0, deep_rand_coef_ptr, ...] + # => [y, y, alpha1, alpha0, deep_rand_coef_ptr, ...] where y is a "garbage" value movup.4 mem_storew dropw #=> [...] end @@ -651,7 +518,6 @@ end #! [0, lde_size] and store it in memory starting from `query_ptr`. #! The list is stored as `(r, depth, y, y)` where `depth` is `log(lde_domain_size)`. #!`depth` is needed when computing the deep queries. -#! TODO: the case of duplicate queries #! #! Input: [query_ptr, num_queries, ...] #! Output: [...] @@ -663,9 +529,11 @@ end #! NOTE: The cycles count can be estimated, using the fact that r < 8, via the more compact formula #! 470 + 236 * (num_queries / 8) export.generate_list_indices + exec.constants::number_queries_ptr mem_load + exec.constants::get_fri_queries_address # Create mask padw - exec.constants::lde_size_ptr mem_loadw + exec.constants::get_lde_domain_info movup.2 drop movup.2 drop sub.1 @@ -808,10 +676,12 @@ end #! Check that the Proof-of-Work contained in the nonce is equal to the required number #! of bits prescribed by grinding bits. The grinding factor is assumed to be less than 32. #! -#! Input: [grinding_factor, ...] +#! Input: [...] #! Output: [...] #! Cycles: 73 export.check_pow + # Load the grinding factor + exec.constants::grinding_factor_ptr mem_load # Compute the mask. pow2 diff --git a/stdlib/asm/crypto/stark/verifier.masm b/stdlib/asm/crypto/stark/verifier.masm index b5ef27d85..ca81d96b5 100644 --- a/stdlib/asm/crypto/stark/verifier.masm +++ b/stdlib/asm/crypto/stark/verifier.masm @@ -51,14 +51,13 @@ export.verify # Initialize the seed using proof context # - # Cycles: 228 + # Cycles: 210 exec.random_coin::init_seed - # => [C] + # => [C, ...] # Load public inputs # # Cycles: 94 - exec.constants::public_inputs_ptr exec.public_inputs::load exec.random_coin::reseed # => [...] @@ -80,7 +79,6 @@ export.verify # Draw random ExtFelt for the auxiliary trace # # Cycles: 168 - exec.constants::aux_rand_elem_ptr exec.random_coin::generate_aux_randomness # => [...] @@ -97,7 +95,7 @@ export.verify # III) Draw constraint composition coefficients #============================================================================================== - # Cycles: 12 + # Cycles: 13 exec.random_coin::generate_constraint_composition_coefficients # => [...] @@ -172,7 +170,7 @@ export.verify # Cycles: 77 exec.helper::generate_fri_parameters - # => [num_fri_layers, ...] + # => [...] #============================================ # 3) Load and reseed with FRI layer commitments @@ -181,7 +179,6 @@ export.verify #============================================ # Cycles: 40 + 108 * num_fri_layers - exec.constants::fri_com_ptr exec.helper::load_fri_layer_commitments # => [...] @@ -203,7 +200,6 @@ export.verify #============================================ # Cycles: 78 - exec.constants::grinding_factor_ptr mem_load exec.random_coin::check_pow # => [...] @@ -213,66 +209,29 @@ export.verify #============================================ # Compute the pointer to the first query using the pointer to - # the first layer commitment and total number of queries. - exec.constants::fri_com_ptr - exec.constants::number_queries_ptr mem_load - dup movdn.2 mul.4 - # => [num_queries*4, fri_com_ptr, num_queries, ...] - - sub - # => [query_ptr, num_queries, ...] + # the first layer commitment and the total number of queries. + exec.helper::compute_query_pointer # Draw random query indices # # Cycles: 92 + 32.5 * num_queries - swap dup.1 exec.random_coin::generate_list_indices - # => [query_ptr, ...] + # => [...] # Compute deep composition polynomial queries # # Cycles: 426 + num_queries * 373 - # => [query_ptr, ...] exec.deep_queries::compute_deep_composition_polynomial_queries - # => [query_ptr, ...] + # => [...] #============================================ # 7) Call the FRI verifier #============================================ - # Get domain generator and pointer to the remainder codeword - # - # Cycles: 15 - padw - exec.constants::lde_size_ptr mem_loadw - push.0.0 - exec.constants::tmp8 mem_loadw - swap.3 - drop drop drop movup.2 drop - # => [remainder_ptr, g, query_ptr, ...] - - # Get the pointer to the first layer commitment - exec.constants::fri_com_ptr - - # Get the pointer to the first FRI query to the top - movup.3 - # => [query_ptr, fri_layer_ptr, remainder_ptr, domain_gen, ...] - - padw exec.constants::tmp8 mem_loadw - drop movdn.2 drop drop - # Call FRI verifier # # Cycles: # 1- Remainder of size 64: 18 + num_queries * (107 + num_layers * 83) # 2- Remainder of size 128: 18 + num_queries * (140 + num_layers * 83) - push.512 - eq - - if.true - exec.frie2f4::verify_64 - else - exec.frie2f4::verify_128 - end - # => [...] + exec.frie2f4::verify end diff --git a/stdlib/tests/crypto/fri/mod.rs b/stdlib/tests/crypto/fri/mod.rs index 036fb9183..cbc3bb18e 100644 --- a/stdlib/tests/crypto/fri/mod.rs +++ b/stdlib/tests/crypto/fri/mod.rs @@ -17,7 +17,7 @@ fn fri_fold4_ext2_remainder64() { begin exec.frie2f4::preprocess - exec.frie2f4::verify_128 + exec.frie2f4::verify end "; @@ -65,7 +65,7 @@ fn fri_fold4_ext2_remainder128() { begin exec.frie2f4::preprocess - exec.frie2f4::verify_128 + exec.frie2f4::verify end "; diff --git a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs index 894e5343c..50db01401 100644 --- a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs +++ b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs @@ -16,6 +16,11 @@ use winter_fri::{ use super::channel::{MidenFriVerifierChannel, UnBatch}; +const MAX_REMAINDER_POLY_DEGREE_LOG: usize = 7; +const FRI_FOLDING_FACTOR_LOG: usize = 2; +const BLOWUP_FACTOR_LOG: usize = 3; +const NUM_FRI_QUERIES: usize = 32; + type AdvMap = Vec<(RpoDigest, Vec)>; pub struct FriResult { @@ -53,10 +58,10 @@ pub struct FriResult { // a FRI proof inside the Miden VM. // The output is organized as follows: pub fn fri_prove_verify_fold4_ext2(trace_length_e: usize) -> Result { - let max_remainder_size_e = 7; - let folding_factor_e = 2; + let max_remainder_size_e = MAX_REMAINDER_POLY_DEGREE_LOG; + let folding_factor_e = FRI_FOLDING_FACTOR_LOG; let trace_length = 1 << trace_length_e; - let lde_blowup = 1 << 3; + let lde_blowup = 1 << BLOWUP_FACTOR_LOG; let max_remainder_size = 1 << max_remainder_size_e; let folding_factor = 1 << folding_factor_e; let nonce = 0_u64; @@ -120,7 +125,7 @@ pub fn build_prover_channel( trace_length: usize, options: &FriOptions, ) -> DefaultProverChannel> { - DefaultProverChannel::new(trace_length * options.blowup_factor(), 32) + DefaultProverChannel::new(trace_length * options.blowup_factor(), NUM_FRI_QUERIES) } pub fn build_evaluations(trace_length: usize, lde_blowup: usize) -> Vec { @@ -184,8 +189,8 @@ impl FriVerifierFold4Ext2 { options: FriOptions, max_poly_degree: usize, ) -> Result { - assert_eq!(options.blowup_factor(), 8); - assert_eq!(options.folding_factor(), 4); + assert_eq!(options.blowup_factor(), 1 << BLOWUP_FACTOR_LOG); + assert_eq!(options.folding_factor(), 1 << FRI_FOLDING_FACTOR_LOG); // infer evaluation domain info let domain_size = max_poly_degree.next_power_of_two() * options.blowup_factor(); @@ -322,7 +327,7 @@ fn iterate_query_fold_4_quad_ext( let mut alphas = vec![]; for depth in 0..number_of_layers { - let target_domain_size = domain_size / 4; + let target_domain_size = domain_size / (1 << FRI_FOLDING_FACTOR_LOG); let folded_pos = cur_pos % target_domain_size; @@ -386,9 +391,9 @@ fn iterate_query_fold_4_quad_ext( alphas.push(0); alphas.push(0); - *domain_generator = (*domain_generator).exp((4_u32).into()); + *domain_generator = (*domain_generator).exp(((1 << FRI_FOLDING_FACTOR_LOG) as u32).into()); cur_pos = folded_pos; - domain_size /= 4; + domain_size /= 1 << FRI_FOLDING_FACTOR_LOG; } Ok((cur_pos, evaluation, position_evaluation, alphas)) From e1ee8f0b3d559a0c79d5f109edffd095c5b466cf Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 18 Mar 2025 18:19:36 +0100 Subject: [PATCH 07/14] remove print --- processor/src/stack/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/processor/src/stack/mod.rs b/processor/src/stack/mod.rs index c75ebfd2a..9561bc882 100644 --- a/processor/src/stack/mod.rs +++ b/processor/src/stack/mod.rs @@ -133,7 +133,6 @@ impl Stack { /// # Errors /// Returns an error if the overflow table is not empty at the current clock cycle. pub fn build_stack_outputs(&self) -> Result { - std::println!("stack state is {:?}", self.get_state_at(self.clk)); if self.overflow.num_active_rows() != 0 { return Err(ExecutionError::OutputStackOverflow(self.overflow.num_active_rows())); } From 3ca2fe3a3bae84212752837c115c23c70ecd3812 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 18 Mar 2025 18:21:02 +0100 Subject: [PATCH 08/14] add changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9051ead22..506d07150 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ - [BREAKING] Updated Winterfell dependency to v0.12 (#1658). - Update recursive verifier to use `HORNERBASE` (#1665). - Remove `FALCON_SIG_TO_STACK` event (#1703) - +- Optimize FRI remainder polynomial check (#1670). ## 0.12.0 (2025-01-22) From e4cc2ada3697451003aea477316d6c79218e5388 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Tue, 18 Mar 2025 19:19:59 +0100 Subject: [PATCH 09/14] change winterfell branch --- Cargo.lock | 20 ++++++++++---------- Cargo.toml | 18 +++++++++--------- stdlib/tests/crypto/fri/verifier_fri_e2f4.rs | 4 ++-- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7e757d4f..9364f86b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2933,8 +2933,8 @@ dependencies = [ [[package]] name = "winter-air" -version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +version = "0.12.1" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "libm", "winter-crypto", @@ -2946,7 +2946,7 @@ dependencies = [ [[package]] name = "winter-crypto" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "blake3", "sha3", @@ -2957,7 +2957,7 @@ dependencies = [ [[package]] name = "winter-fri" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "winter-crypto", "winter-math", @@ -2967,7 +2967,7 @@ dependencies = [ [[package]] name = "winter-math" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "winter-utils", ] @@ -2975,7 +2975,7 @@ dependencies = [ [[package]] name = "winter-maybe-async" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "quote", "syn", @@ -2984,7 +2984,7 @@ dependencies = [ [[package]] name = "winter-prover" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "tracing", "winter-air", @@ -2998,7 +2998,7 @@ dependencies = [ [[package]] name = "winter-rand-utils" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "rand 0.8.5", "winter-utils", @@ -3007,7 +3007,7 @@ dependencies = [ [[package]] name = "winter-utils" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "rayon", ] @@ -3015,7 +3015,7 @@ dependencies = [ [[package]] name = "winter-verifier" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-recursive-verifier-remainder-opt#c3dda426b52c0ac852f53df1d4bc0a4042782893" +source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" dependencies = [ "winter-air", "winter-crypto", diff --git a/Cargo.toml b/Cargo.toml index 05cc16245..c3f85bb62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,12 +38,12 @@ overflow-checks = true thiserror = { version = "2.0", default-features = false } [patch.crates-io] -winter-air = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-air" } -winter-crypto = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-crypto" } -winter-prover = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-prover" } -winter-verifier = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-verifier" } -winter-math = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-math" } -winter-fri = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-fri" } -winter-maybe-async = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-maybe-async" } -winter-utils = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-utils" } -winter-rand-utils = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-recursive-verifier-remainder-opt", package = "winter-rand-utils" } \ No newline at end of file +winter-air = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-air" } +winter-crypto = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-crypto" } +winter-prover = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-prover" } +winter-verifier = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-verifier" } +winter-math = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-math" } +winter-fri = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-fri" } +winter-maybe-async = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-maybe-async" } +winter-utils = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-utils" } +winter-rand-utils = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-rand-utils" } \ No newline at end of file diff --git a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs index 50db01401..ad2bd187a 100644 --- a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs +++ b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs @@ -98,7 +98,7 @@ pub fn fri_prove_verify_fold4_ext2(trace_length_e: usize) -> Result = proof.parse_remainder().expect("should return remainder polynomial"); - let remainder: Vec = QuadExt::slice_as_base_elements(&&remainder_poly[..]) + let remainder: Vec = QuadExt::slice_as_base_elements(&remainder_poly[..]) .to_owned() .iter() .map(|a| a.as_int()) @@ -288,7 +288,7 @@ impl FriVerifierFold4Ext2 { for &(final_pos, final_eval) in final_pos_eval.iter() { let comp_eval = eval_horner_rev( &remainder_poly, - offset * d_generator.exp_vartime((final_pos as u64).into()), + offset * d_generator.exp_vartime(final_pos as u64), ); if comp_eval != final_eval { return Err(VerifierError::InvalidRemainderFolding); From 4fa8e23146c79e2d14e992633600e23777b584ee Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Wed, 19 Mar 2025 17:23:10 +0100 Subject: [PATCH 10/14] feat: improve procedures for getting and setting constants --- stdlib/asm/crypto/fri/helper.masm | 16 +- stdlib/asm/crypto/stark/constants.masm | 300 +++++++------------ stdlib/asm/crypto/stark/deep_queries.masm | 63 ++-- stdlib/asm/crypto/stark/public_inputs.masm | 29 +- stdlib/asm/crypto/stark/random_coin.masm | 26 +- stdlib/asm/crypto/stark/utils.masm | 2 +- stdlib/asm/crypto/stark/verifier.masm | 7 +- stdlib/tests/crypto/fri/channel.rs | 2 +- stdlib/tests/crypto/fri/verifier_fri_e2f4.rs | 30 +- 9 files changed, 205 insertions(+), 270 deletions(-) diff --git a/stdlib/asm/crypto/fri/helper.masm b/stdlib/asm/crypto/fri/helper.masm index 53ccf8a47..8838352a1 100644 --- a/stdlib/asm/crypto/fri/helper.masm +++ b/stdlib/asm/crypto/fri/helper.masm @@ -10,11 +10,11 @@ use.std::crypto::stark::constants #! Cycles: 77 export.generate_fri_parameters # Load FRI verifier data - padw exec.constants::get_lde_domain_info + padw exec.constants::get_lde_domain_info_word #=> [lde_size, log(lde_size), lde_g, 0, ...] (6 cycles) - # Store in `TMP5` in order to use it for fri layer loading - exec.constants::tmp5 mem_storew + # Store temporarily in order to use it for FRI layer loading + exec.constants::tmp1 mem_storew # Compute [gz1, gz0, z1, z0] using domain generator # TODO: move to somewhere else @@ -117,7 +117,7 @@ export.load_fri_layer_commitments exec.random_coin::get_rate_1 #=> [R1, ZERO, num_layers, ptr_layer + 4, y, y, ... ] push.0.0 - exec.constants::tmp5 mem_loadw + exec.constants::tmp1 mem_loadw # => [lde_size, log2(lde_size), lde_generator, 0, a1, a0, Y, num_layers, ptr_layer + 4, y, y, ...] # Compute and save to memory new lde_size and its new logarithm @@ -125,7 +125,7 @@ export.load_fri_layer_commitments swap sub.2 swap - exec.constants::tmp5 mem_storew + exec.constants::tmp1 mem_storew # Move the pointer higher up the stack movup.2 drop @@ -167,7 +167,7 @@ export.load_and_verify_remainder # Load remainder commitment and save it at `TMP7` push.0.0.0.0 adv_loadw - exec.constants::tmp7 mem_storew + exec.constants::tmp1 mem_storew #=> [COM, ...] # Reseed with remainder commitment @@ -203,7 +203,7 @@ export.load_and_verify_remainder end # Compare Remainder_poly_com with the read commitment - exec.constants::tmp7 mem_loadw + exec.constants::tmp1 mem_loadw movup.4 assert_eq movup.3 @@ -226,7 +226,7 @@ export.load_and_verify_remainder # => [Y, Remainder_poly_com, Y, remainder_poly_ptr, remainder_size, y, y] # Compare Remainder_poly_com with the read commitment - exec.constants::tmp7 mem_loadw + exec.constants::tmp1 mem_loadw movup.4 assert_eq movup.3 diff --git a/stdlib/asm/crypto/stark/constants.masm b/stdlib/asm/crypto/stark/constants.masm index 340c73785..6dbf917ed 100644 --- a/stdlib/asm/crypto/stark/constants.masm +++ b/stdlib/asm/crypto/stark/constants.masm @@ -103,12 +103,6 @@ const.TMP1=4294913256 const.TMP2=4294913260 const.TMP3=4294913264 const.TMP4=4294913268 -const.TMP5=4294913272 -const.TMP6=4294913276 -const.TMP7=4294913280 -const.TMP8=4294913284 -const.TMP9=4294913288 -const.TMP10=4294913292 # RPO state capacity portion initialization words. In theory, we need a variant for each possible # remainder modulo 8 but in practice we only need the following: @@ -175,12 +169,6 @@ const.ALPHA_POWER_85_1_PTR=4294903445 # | TMP2 | 4294913260 | # | TMP3 | 4294913264 | # | TMP4 | 4294913268 | -# | TMP5 | 4294913272 | -# | TMP6 | 4294913276 | -# | TMP7 | 4294913280 | -# | TMP8 | 4294913284 | -# | TMP9 | 4294913288 | -# | TMP10 | 4294913292 | # | ZERO_ZERO_ZERO_FOUR_PTR | 4294913400 | # | ZERO_ZERO_ZERO_FIVE_PTR | 4294913404 | # | ZERO_ZERO_ZERO_SIX_PTR | 4294913408 | @@ -204,55 +192,6 @@ const.ALPHA_POWER_85_1_PTR=4294903445 # ACCESSORS # ================================================================================================= -export.root_unity - push.ROOT_UNITY -end - -export.num_aux_trace_coefs - push.NUM_AUX_TRACE_COEFS -end - -export.get_num_constraints - push.NUM_CONSTRAINTS -end - -# Procedure to push the trace domain generator address to the stack. -# -# Input: [...] -# Output: [ptr, ...] wher ptr is the memory address of the trace domain generator -# Cycles: 1 -export.trace_domain_generator_ptr - push.TRACE_DOMAIN_GENERATOR_PTR -end - -export.set_trace_domain_generator - push.TRACE_DOMAIN_GENERATOR_PTR mem_store -end - -export.get_trace_domain_generator - push.TRACE_DOMAIN_GENERATOR_PTR mem_load -end - -export.domain_offset - push.DOMAIN_OFFSET -end - -export.domain_offset_inv - push.DOMAIN_OFFSET_INV -end - -export.lde_domain_generator_ptr - push.LDE_DOMAIN_GEN_PTR -end - -export.set_lde_domain_generator - push.LDE_DOMAIN_GEN_PTR mem_store -end - -export.get_lde_domain_generator - push.LDE_DOMAIN_GEN_PTR mem_load -end - export.public_inputs_ptr push.PUBLIC_INPUTS_PTR end @@ -301,131 +240,104 @@ export.composition_poly_com_ptr push.COMPOSITION_POLY_COM_PTR end -#! Address to store details about the lde size. -#! -#! Memory is `[lde_size, log(lde_size), lde_g, 0]` -export.lde_domain_info_ptr - push.LDE_DOMAIN_INFO_PTR -end - -export.set_lde_domain_info - push.LDE_DOMAIN_INFO_PTR mem_storew -end - -export.get_lde_domain_info - push.LDE_DOMAIN_INFO_PTR mem_loadw -end - #! Address for the point `z` and its exponentiation `z^N` where `N=trace_len`. #! -#! Memory is `[(z_1, z_0)^n, z_1, z_0]` +#! The word stored is `[z_0, z_1, z^n_0, z^n_1]`. export.z_ptr push.Z_PTR end -export.number_queries_ptr - push.NUM_QUERIES_PTR +#! Returns the pointer to the capacity word of the RPO-based random coin. +export.c_ptr + push.C_PTR end -export.set_number_queries - push.NUM_QUERIES_PTR mem_store +#! Returns the pointer to the first rate word of the RPO-based random coin. +export.r1_ptr + push.R1_PTR end -export.get_number_queries - push.NUM_QUERIES_PTR mem_load +#! Returns the pointer to the second rate word of the RPO-based random coin. +export.r2_ptr + push.R2_PTR end -export.remainder_poly_size_ptr - push.REMAINDER_POLY_SIZE_PTR +export.zero_word_ptr + push.ZERO_WORD_PTR end -export.set_remainder_poly_size - push.REMAINDER_POLY_SIZE_PTR mem_store +export.zero_zero_zero_four_word_ptr + push.ZERO_ZERO_ZERO_FOUR_PTR end -export.get_remainder_poly_size - push.REMAINDER_POLY_SIZE_PTR mem_load +export.zero_zero_zero_five_word_ptr + push.ZERO_ZERO_ZERO_FIVE_PTR end -export.num_fri_layers_ptr - push.NUM_FRI_LAYERS_PTR +export.zero_zero_zero_six_word_ptr + push.ZERO_ZERO_ZERO_SIX_PTR end -export.set_num_fri_layers - push.NUM_FRI_LAYERS_PTR mem_store +export.zero_zero_zero_seven_word_ptr + push.ZERO_ZERO_ZERO_SEVEN_PTR end -export.get_num_fri_layers - push.NUM_FRI_LAYERS_PTR mem_load +export.deep_rand_alpha_inv_ptr + push.ALPHA_INV end -export.remainder_poly_address_ptr - push.REMAINDER_POLY_ADDRESS_PTR +export.deep_rand_alpha_1_ptr + push.ALPHA_POWER_1_PTR end -export.set_remainder_poly_address - push.REMAINDER_POLY_ADDRESS_PTR mem_store +export.deep_rand_alpha_2_ptr + push.ALPHA_POWER_2_PTR end -export.get_remainder_poly_address - push.REMAINDER_POLY_ADDRESS_PTR mem_load +export.deep_rand_alpha_3_ptr + push.ALPHA_POWER_3_PTR end -export.fri_queries_address_ptr - push.FRI_QUERIES_ADDRESS_PTR +export.deep_rand_alpha_4_ptr + push.ALPHA_POWER_4_PTR end -export.set_fri_queries_address - push.FRI_QUERIES_ADDRESS_PTR mem_store +export.deep_rand_alpha_5_ptr + push.ALPHA_POWER_5_PTR end -export.get_fri_queries_address - push.FRI_QUERIES_ADDRESS_PTR mem_load +export.deep_rand_alpha_6_ptr + push.ALPHA_POWER_6_PTR end -export.trace_length_ptr - push.TRACE_LENGTH_PTR +export.deep_rand_alpha_7_ptr + push.ALPHA_POWER_7_PTR end -export.trace_length_log_ptr - push.TRACE_LENGTH_LOG_PTR +export.deep_rand_alpha_77_ptr + push.ALPHA_POWER_77_PTR end -export.grinding_factor_ptr - push.GRINDING_FACTOR_PTR +export.deep_rand_alpha_77_0_ptr + push.ALPHA_POWER_77_0_PTR end -export.zero_word - push.ZERO_WORD_PTR +export.deep_rand_alpha_77_1_ptr + push.ALPHA_POWER_77_1_PTR end -#! Returns the pointer to the capacity word of the random coin. -#! -#! Note: The random coin is implemented using a hash function, this returns the -#! capacity portion of the RPO. -export.c_ptr - push.C_PTR +export.deep_rand_alpha_85_ptr + push.ALPHA_POWER_85_PTR end -#! Returns the pointer to the first rate word of the random coin. -#! -#! Note: The random coin is implemented using a hash function, this returns the -#! first rate word of the RPO. -export.r1_ptr - push.R1_PTR +export.deep_rand_alpha_85_0_ptr + push.ALPHA_POWER_85_0_PTR end -#! Returns the pointer to the second rate word of the random coin. -#! -#! Note: The random coin is implemented using a hash function, this returns the -#! second rate word of the RPO. -export.r2_ptr - push.R2_PTR +export.deep_rand_alpha_85_1_ptr + push.ALPHA_POWER_85_1_PTR end -#! Address to store details to compute deep query denominators. -#! -#! Memory is `[gz1, gz0, z_1, z_0]` export.tmp1 push.TMP1 end @@ -442,102 +354,116 @@ export.tmp4 push.TMP4 end -export.tmp5 - push.TMP5 +#! Store details about the LDE domain. +#! +#! The info stored is `[lde_size, log(lde_size), lde_g, 0]`. +export.set_lde_domain_info_word + push.LDE_DOMAIN_INFO_PTR mem_storew end -export.tmp6 - push.TMP6 +#! Load details about the LDE domain. +#! +#! The info stored is `[lde_size, log(lde_size), lde_g, 0]`. +export.get_lde_domain_info_word + push.LDE_DOMAIN_INFO_PTR mem_loadw end -export.tmp7 - push.TMP7 +export.get_root_unity + push.ROOT_UNITY end -export.tmp8 - push.TMP8 +export.get_num_aux_trace_coefs + push.NUM_AUX_TRACE_COEFS end -export.tmp9 - push.TMP9 +export.get_domain_offset + push.DOMAIN_OFFSET end -export.tmp10 - push.TMP10 +export.get_domain_offset_inv + push.DOMAIN_OFFSET_INV end -export.zero_zero_zero_four_word - push.ZERO_ZERO_ZERO_FOUR_PTR +export.get_num_constraints + push.NUM_CONSTRAINTS end -export.zero_zero_zero_five_word - push.ZERO_ZERO_ZERO_FIVE_PTR +export.set_trace_domain_generator + push.TRACE_DOMAIN_GENERATOR_PTR mem_store end -export.zero_zero_zero_six_word - push.ZERO_ZERO_ZERO_SIX_PTR +export.get_trace_domain_generator + push.TRACE_DOMAIN_GENERATOR_PTR mem_load end -export.zero_zero_zero_seven_word - push.ZERO_ZERO_ZERO_SEVEN_PTR +export.set_lde_domain_generator + push.LDE_DOMAIN_GEN_PTR mem_store end -export.deep_rand_alpha_inv - push.ALPHA_INV +export.get_lde_domain_generator + push.LDE_DOMAIN_GEN_PTR mem_load end -export.ood_constraint_evals_next_ptr - push.OOD_TRACE_NEXT_PTR +export.set_number_queries + push.NUM_QUERIES_PTR mem_store end -export.deep_rand_alpha_1 - push.ALPHA_POWER_1_PTR +export.get_number_queries + push.NUM_QUERIES_PTR mem_load end -export.deep_rand_alpha_2 - push.ALPHA_POWER_2_PTR +export.set_remainder_poly_size + push.REMAINDER_POLY_SIZE_PTR mem_store end -export.deep_rand_alpha_3 - push.ALPHA_POWER_3_PTR +export.get_remainder_poly_size + push.REMAINDER_POLY_SIZE_PTR mem_load end -export.deep_rand_alpha_4 - push.ALPHA_POWER_4_PTR +export.set_num_fri_layers + push.NUM_FRI_LAYERS_PTR mem_store end -export.deep_rand_alpha_5 - push.ALPHA_POWER_5_PTR +export.get_num_fri_layers + push.NUM_FRI_LAYERS_PTR mem_load end -export.deep_rand_alpha_6 - push.ALPHA_POWER_6_PTR +export.set_remainder_poly_address + push.REMAINDER_POLY_ADDRESS_PTR mem_store end -export.deep_rand_alpha_7 - push.ALPHA_POWER_7_PTR +export.get_remainder_poly_address + push.REMAINDER_POLY_ADDRESS_PTR mem_load end -export.deep_rand_alpha_77 - push.ALPHA_POWER_77_PTR +export.set_fri_queries_address + push.FRI_QUERIES_ADDRESS_PTR mem_store end -export.deep_rand_alpha_77_0 - push.ALPHA_POWER_77_0_PTR +export.get_fri_queries_address + push.FRI_QUERIES_ADDRESS_PTR mem_load end -export.deep_rand_alpha_77_1 - push.ALPHA_POWER_77_1_PTR +export.set_trace_length + push.TRACE_LENGTH_PTR mem_store end -export.deep_rand_alpha_85 - push.ALPHA_POWER_85_PTR +export.get_trace_length + push.TRACE_LENGTH_PTR mem_load end -export.deep_rand_alpha_85_0 - push.ALPHA_POWER_85_0_PTR +export.set_trace_length_log + push.TRACE_LENGTH_LOG_PTR mem_store end -export.deep_rand_alpha_85_1 - push.ALPHA_POWER_85_1_PTR -end \ No newline at end of file +export.get_trace_length_log + push.TRACE_LENGTH_LOG_PTR mem_load +end + +export.set_grinding_factor + push.GRINDING_FACTOR_PTR mem_store +end + +export.get_grinding_factor + push.GRINDING_FACTOR_PTR mem_load +end diff --git a/stdlib/asm/crypto/stark/deep_queries.masm b/stdlib/asm/crypto/stark/deep_queries.masm index 69b03022a..3c8a28c92 100644 --- a/stdlib/asm/crypto/stark/deep_queries.masm +++ b/stdlib/asm/crypto/stark/deep_queries.masm @@ -26,7 +26,7 @@ proc.compute_adjustment_power_z_quotients ## a) First power dup.1 dup.1 - exec.constants::deep_rand_alpha_1 + exec.constants::deep_rand_alpha_1_ptr mem_storew # => [alpha_1, alpha_0, alpha_1, alpha_0, ...] @@ -34,7 +34,7 @@ proc.compute_adjustment_power_z_quotients dup.1 dup.1 ext2mul dup.1 dup.1 - exec.constants::deep_rand_alpha_2 + exec.constants::deep_rand_alpha_2_ptr mem_storew drop drop # => [alpha2_1, alpha2_0, alpha_1, alpha_0, ...] @@ -43,7 +43,7 @@ proc.compute_adjustment_power_z_quotients dup.3 dup.3 ext2mul dup.1 dup.1 - exec.constants::deep_rand_alpha_3 + exec.constants::deep_rand_alpha_3_ptr mem_storew drop drop # => [alpha3_1, alpha3_0, alpha_1, alpha_0, ...] @@ -52,7 +52,7 @@ proc.compute_adjustment_power_z_quotients dup.3 dup.3 ext2mul dup.1 dup.1 - exec.constants::deep_rand_alpha_4 + exec.constants::deep_rand_alpha_4_ptr mem_storew drop drop # => [alpha4_1, alpha4_0, alpha_1, alpha_0, ...] @@ -61,7 +61,7 @@ proc.compute_adjustment_power_z_quotients dup.3 dup.3 ext2mul dup.1 dup.1 - exec.constants::deep_rand_alpha_5 + exec.constants::deep_rand_alpha_5_ptr mem_storew drop drop # => [alpha5_1, alpha5_0, alpha_1, alpha_0, ...] @@ -70,7 +70,7 @@ proc.compute_adjustment_power_z_quotients dup.3 dup.3 ext2mul dup.1 dup.1 - exec.constants::deep_rand_alpha_6 + exec.constants::deep_rand_alpha_6_ptr mem_storew movdn.5 movdn.5 # => [alpha6_1, alpha6_0, alpha_1, alpha_0, alpha6_1, alpha6_0, ...] @@ -79,7 +79,7 @@ proc.compute_adjustment_power_z_quotients dup.3 dup.3 ext2mul dup.1 dup.1 - exec.constants::deep_rand_alpha_7 + exec.constants::deep_rand_alpha_7_ptr mem_storew drop drop # => [alpha7_1, alpha7_0, alpha_1, alpha_0, alpha6_1, alpha6_0, ...] @@ -113,7 +113,7 @@ proc.compute_adjustment_power_z_quotients # => [alpha77_1, alpha77_0, alpha7_1, alpha7_0, alpha_1, alpha_0, ...] dup.1 dup.1 - exec.constants::deep_rand_alpha_77 + exec.constants::deep_rand_alpha_77_ptr mem_storew drop drop # => [alpha77_1, alpha77_0, alpha7_1, alpha7_0, alpha_1, alpha_0, ...] @@ -121,7 +121,7 @@ proc.compute_adjustment_power_z_quotients # 5) Compute alpha^85 ext2mul ext2mul dup.1 dup.1 - exec.constants::deep_rand_alpha_85 + exec.constants::deep_rand_alpha_85_ptr mem_storew dropw # => [...] @@ -157,7 +157,7 @@ proc.compute_q_z_p_gz_at_alpha drop drop ext2inv dup.1 dup.1 - exec.constants::deep_rand_alpha_inv mem_storew + exec.constants::deep_rand_alpha_inv_ptr mem_storew # II) Compute Q^z(alpha) @@ -166,9 +166,8 @@ proc.compute_q_z_p_gz_at_alpha ### a) Set up the initial accumulator and the pointers to alpha^{-1} and a memory region ### from which to load the OOD. push.0.0 - exec.constants::deep_rand_alpha_inv + exec.constants::deep_rand_alpha_inv_ptr exec.constants::ood_trace_current_ptr - exec.constants::tmp2 mem_storew ### b) Set up the rest of the stack swapw @@ -231,7 +230,7 @@ proc.compute_q_z_p_gz_at_alpha ### i) Process the last 2 extension field elements movdnw.2 # => [h7`, h6`, h5`, h4`, h15`, h14`, h13`, h12`, h11`, h10`, h9`, h8`, U, ...] - exec.constants::zero_word mem_loadw + exec.constants::zero_word_ptr mem_loadw horner_eval_ext # => [Y, Y, Y, ptr_ood, ptr_alpha, acc1, acc0, ...] @@ -243,10 +242,10 @@ proc.compute_q_z_p_gz_at_alpha drop drop ### a) Load alpha^85 - exec.constants::deep_rand_alpha_85 mem_loadw + exec.constants::deep_rand_alpha_85_ptr mem_loadw ### b) Load alpha^2 - push.0.0 exec.constants::deep_rand_alpha_2 mem_loadw drop drop + push.0.0 exec.constants::deep_rand_alpha_2_ptr mem_loadw drop drop ### c) Multiply the two adjustment factors ext2mul @@ -267,7 +266,7 @@ proc.compute_q_z_p_gz_at_alpha ## 1) Set up the stack for `horner_eval_ext` push.0.0 - exec.constants::deep_rand_alpha_inv + exec.constants::deep_rand_alpha_inv_ptr exec.constants::ood_trace_next_ptr padw swapdw @@ -282,7 +281,7 @@ proc.compute_q_z_p_gz_at_alpha ## 3) Load and process the last 2 extension field elements. ## We use `mem_stream` but we will discard the last 4 field elements. mem_stream - exec.constants::zero_word mem_loadw + exec.constants::zero_word_ptr mem_loadw horner_eval_ext ## 5) Multiply the accumulator by the adjustment factor in order to get P^gz(alpha) @@ -293,12 +292,12 @@ proc.compute_q_z_p_gz_at_alpha ### a) Load alpha^77 swapdw drop drop - exec.constants::deep_rand_alpha_77 + exec.constants::deep_rand_alpha_77_ptr mem_loadw ### b) Load alpha^2 push.0.0 - exec.constants::deep_rand_alpha_2 + exec.constants::deep_rand_alpha_2_ptr mem_loadw drop drop @@ -369,7 +368,7 @@ proc.load_query_row exec.constants::tmp3 mem_storew adv.push_mapval #=>[V, R, depth, index, query_ptr, ...] - exec.constants::tmp10 mem_loadw + exec.constants::tmp2 mem_loadw swapw #=>[V, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr, ...] @@ -378,7 +377,7 @@ proc.load_query_row ## a single random value alpha. ### a) Load the first 64 columns in 8 batches of 8 base field elements - exec.constants::zero_zero_zero_seven_word mem_loadw + exec.constants::zero_zero_zero_seven_word_ptr mem_loadw padw padw #=> [Y, Y, 0, 0, 0, 7, ptr, y, y, y] @@ -419,7 +418,7 @@ proc.load_query_row ## Since the evaluation point is alpha^{-1}, we thus need to multiply by alpha. ## In general, we have to multiply by alpha^num_missing_coefficients, where ## `num_missing_coefficients` is in 1..=7 - exec.constants::deep_rand_alpha_1 mem_loadw + exec.constants::deep_rand_alpha_1_ptr mem_loadw movup.7 movup.7 #=> [acc1, acc0, adj1, adj0, y, y, ptr_x, ptr_alpha_inv, Y, depth, index, query_ptr, ...] ext2mul @@ -443,7 +442,7 @@ proc.load_query_row ## 3) Load the values of the auxiliary segment of the execution trace at the current query. ### a) Set up the stack - exec.constants::zero_zero_zero_six_word mem_loadw + exec.constants::zero_zero_zero_six_word_ptr mem_loadw swapw movupw.3 #=> [Y, Y, C, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr, ...] @@ -482,7 +481,7 @@ proc.load_query_row ## Since the evaluation point is alpha^{-1}, we thus need to multiply by alpha. ## In general, we have to multiply by alpha^num_missing_coefficients, where ## `num_missing_coefficients` is in 1..=3 - exec.constants::deep_rand_alpha_1 mem_loadw drop drop + exec.constants::deep_rand_alpha_1_ptr mem_loadw drop drop movup.5 movup.5 #=> [acc1, acc0, adj1, adj0, ptr_x, ptr_alpha_inv, Y, depth, index, query_ptr, ...] ext2mul @@ -495,7 +494,7 @@ proc.load_query_row ## 1) Load and multiply by alpha^77 swapw - exec.constants::deep_rand_alpha_77 mem_loadw + exec.constants::deep_rand_alpha_77_ptr mem_loadw #=> [alpha77_1, alpha77_0, y, y, ptr_x, ptr_alpha_inv, acc1, acc0, depth, index, query_ptr, ...] dup.7 dup.7 ext2mul @@ -549,8 +548,8 @@ proc.load_query_row ## 1) Load alpha^(71 + 7 + 8 - 1) i.e., alpha^85 swapw drop drop - exec.constants::deep_rand_alpha_85_0 mem_load - exec.constants::deep_rand_alpha_85_1 mem_load + exec.constants::deep_rand_alpha_85_0_ptr mem_load + exec.constants::deep_rand_alpha_85_1_ptr mem_load #=> [alpha77_1, alpha77_0, acc1, acc0, Y, depth, index, query_ptr, ...] ## 2) Multiply by alpha^85 @@ -575,12 +574,12 @@ end #! Cycles: 58 proc.compute_denominators # Compute x = offset * domain_gen^index - exec.constants::lde_domain_info_ptr mem_loadw + exec.constants::get_lde_domain_info_word #=> [lde_size, depth, domain_gen, 0, Y, index, ...] movup.2 dup.8 exp.u32 - exec.constants::domain_offset mul + exec.constants::get_domain_offset mul #=> [x, lde_size, depth, 0, Y, index, ...] # Get z and gz from memory @@ -671,9 +670,9 @@ export.compute_deep_composition_polynomial_queries # Store pointers to alpha_inv, memory region to store trace row for current query and a fresh # accumulator value i.e., (0, 0). push.0.0 - exec.constants::deep_rand_alpha_inv + exec.constants::deep_rand_alpha_inv_ptr exec.constants::current_trace_row_ptr - exec.constants::tmp10 mem_storew + exec.constants::tmp2 mem_storew # Compute the negations of z and gz where z is the OOD point # We do it here as this computation is common to all queries. @@ -729,7 +728,7 @@ export.compute_deep_composition_polynomial_queries ## ## Cycles: 4 movup.3 movup.3 - exec.constants::domain_offset_inv mul + exec.constants::get_domain_offset_inv mul #=> [poe, index, eval1, eval0, query_ptr, query_end_ptr, W, query_ptr, ...] ## b) Store [eval0, eval1, index, poe] diff --git a/stdlib/asm/crypto/stark/public_inputs.masm b/stdlib/asm/crypto/stark/public_inputs.masm index 0c519740f..0e0cad62e 100644 --- a/stdlib/asm/crypto/stark/public_inputs.masm +++ b/stdlib/asm/crypto/stark/public_inputs.masm @@ -1,18 +1,26 @@ use.std::crypto::stark::constants +use.std::crypto::hashes::rpo #! Load the public inputs in memory starting from the address referenced by `public_inputs_ptr`. #! In parallel, compute the hash of the public inputs being loaded. The hashing starts with #! capacity registers of the hash function set to `C` resulting from hashing the proof context. -#! The output D is the digest of the hashing. +#! The output D is the digest of the hashing of the public inputs. #! #! Input: [C, ...] #! Output: [D, ...] -#! Cycles: 38 +#! Cycles: ~40 export.load - # Unhash the public inputs from the advice provider. - # The public inputs are made up of the input operand stack and the output operand stack - # both of length 16 field elements. + # Load the public inputs from the advice provider. + # The public inputs are made up of: + # + # 1. the input operand stack and the output operand stack both of length 16 field elements, + # 2. the digest of the program + # 3. the digests of procedures making up the kernel + # + # While loading the public inputs, we also absorb them in the Fiat-Shamir transcript. + + # 1) Load the input and output operand stacks exec.constants::public_inputs_ptr movdn.4 padw padw @@ -22,13 +30,16 @@ export.load adv_loadw hperm end + + # 2) Load the program digest adv_loadw + + # 3) Load the kernel procedures digests + # TODO: Support non-empty kernels swapw - exec.constants::zero_word mem_loadw + exec.constants::zero_word_ptr mem_loadw hperm - dropw - swapw - dropw + exec.rpo::squeeze_digest movup.4 drop end diff --git a/stdlib/asm/crypto/stark/random_coin.masm b/stdlib/asm/crypto/stark/random_coin.masm index 7732d4c64..917e0e2cc 100644 --- a/stdlib/asm/crypto/stark/random_coin.masm +++ b/stdlib/asm/crypto/stark/random_coin.masm @@ -82,21 +82,21 @@ end export.init_seed # Save the parameters in memory for later use - dup exec.constants::trace_length_log_ptr mem_store - dup.1 exec.constants::number_queries_ptr mem_store - dup.3 exec.constants::grinding_factor_ptr mem_store + dup exec.constants::set_trace_length_log + dup.1 exec.constants::set_number_queries + dup.3 exec.constants::set_grinding_factor # Pre-load constants used by hperm into memory and initialize the state of the random coin to zeros. # Since memory beyond 3 * 2^30 does not have any special meaning, we can use the memory region # starting from address 2^32 - 1 in decreasing order to hold constants that are used throughout # the `verify` procedure. padw - exec.constants::zero_word mem_storew + exec.constants::zero_word_ptr mem_storew exec.constants::c_ptr mem_storew exec.constants::r1_ptr mem_storew exec.constants::r2_ptr mem_storew - push.6 swap.4 drop exec.constants::zero_zero_zero_six_word mem_storew - push.7 swap.4 drop exec.constants::zero_zero_zero_seven_word mem_storew + push.6 swap.4 drop exec.constants::zero_zero_zero_six_word_ptr mem_storew + push.7 swap.4 drop exec.constants::zero_zero_zero_seven_word_ptr mem_storew dropw #=> [log(trace_length), num_queries, log(blowup), grinding] @@ -110,7 +110,7 @@ export.init_seed #=> [trace_length, log(trace_length), num_queries, log(blowup), grinding] ## Save the trace length and its log to memory - dup.0 exec.constants::trace_length_ptr mem_store + dup.0 exec.constants::set_trace_length ## Assert blowup is equal to 8 swap @@ -142,7 +142,7 @@ export.init_seed #=> [lde_size, log(lde_size), lde_g, 0, trace_length, num_queries, blowup, grinding] # Save `[lde_size, log(lde_size), lde_g, 0]` - exec.constants::set_lde_domain_info + exec.constants::set_lde_domain_info_word #=> [lde_size, log(lde_size), lde_g, 0, trace_length, num_queries, blowup, grinding] # clean stack @@ -324,7 +324,7 @@ end #! Cycles: 159 export.generate_aux_randomness exec.constants::aux_rand_elem_ptr - exec.constants::num_aux_trace_coefs swap + exec.constants::get_num_aux_trace_coefs swap exec.generate_random_coefficients #=> [...] end @@ -371,7 +371,7 @@ export.generate_z_zN # Load z (first two felts of the random coin state) and log trace length N exec.constants::r1_ptr mem_loadw drop drop - exec.constants::trace_length_log_ptr mem_load + exec.constants::get_trace_length_log # => [log(trace_len), z_1, z_0, ...] dup.2 dup.2 @@ -529,11 +529,11 @@ end #! NOTE: The cycles count can be estimated, using the fact that r < 8, via the more compact formula #! 470 + 236 * (num_queries / 8) export.generate_list_indices - exec.constants::number_queries_ptr mem_load + exec.constants::get_number_queries exec.constants::get_fri_queries_address # Create mask padw - exec.constants::get_lde_domain_info + exec.constants::get_lde_domain_info_word movup.2 drop movup.2 drop sub.1 @@ -681,7 +681,7 @@ end #! Cycles: 73 export.check_pow # Load the grinding factor - exec.constants::grinding_factor_ptr mem_load + exec.constants::get_grinding_factor # Compute the mask. pow2 diff --git a/stdlib/asm/crypto/stark/utils.masm b/stdlib/asm/crypto/stark/utils.masm index 5f701da93..1b50297af 100644 --- a/stdlib/asm/crypto/stark/utils.masm +++ b/stdlib/asm/crypto/stark/utils.masm @@ -11,7 +11,7 @@ export.compute_lde_generator swap sub pow2 - exec.constants::root_unity + exec.constants::get_root_unity swap exp.u32 # => [domain_gen, ..] diff --git a/stdlib/asm/crypto/stark/verifier.masm b/stdlib/asm/crypto/stark/verifier.masm index ca81d96b5..ec58ac482 100644 --- a/stdlib/asm/crypto/stark/verifier.masm +++ b/stdlib/asm/crypto/stark/verifier.masm @@ -11,11 +11,12 @@ use.std::crypto::stark::utils #! Verify a STARK proof attesting to the correct execution of a program in the Miden VM. #! The following simplifying assumptions are currently made: #! - The blowup is set to 8. -#! - The maximal allowed degree of the remainder polynomial is 7. -#! - The public inputs are composed of the input and output stacks, of fixed size equal to 16. +#! - The maximal allowed degree of the remainder polynomial is 127. +#! - The public inputs are composed of the input and output stacks, of fixed size equal to 16, as +#! well as the program and the kernel procedures digests. #! - There are two trace segments, main and auxiliary. It is assumed that the main trace segment #! is 71 columns wide while the auxiliary trace segment is 7 columns wide. -#! - The OOD evaluation frame is composed of two interleaved rows, current and next, each composed +#! - The OOD evaluation frame is composed of two concatenated rows, current and next, each composed #! of 71 elements representing the main trace portion and 7 elements for the auxiliary trace one. #! - To boost soundness, the protocol is run on a quadratic extension field and this means that #! the OOD evaluation frame is composed of elements in a quadratic extension field i.e. tuples. diff --git a/stdlib/tests/crypto/fri/channel.rs b/stdlib/tests/crypto/fri/channel.rs index d91776623..6c5cc10d3 100644 --- a/stdlib/tests/crypto/fri/channel.rs +++ b/stdlib/tests/crypto/fri/channel.rs @@ -68,7 +68,7 @@ where self.layer_commitments.drain(..).collect() } - pub fn read_remainder( + pub fn read_remainder( &mut self, expected_commitment: &::Digest, ) -> Result, VerifierError> { diff --git a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs index ad2bd187a..70e270a23 100644 --- a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs +++ b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs @@ -16,9 +16,9 @@ use winter_fri::{ use super::channel::{MidenFriVerifierChannel, UnBatch}; -const MAX_REMAINDER_POLY_DEGREE_LOG: usize = 7; -const FRI_FOLDING_FACTOR_LOG: usize = 2; -const BLOWUP_FACTOR_LOG: usize = 3; +const MAX_REMAINDER_POLY_DEGREE: usize = 128; +const FRI_FOLDING_FACTOR: usize = 4; +const BLOWUP_FACTOR: usize = 8; const NUM_FRI_QUERIES: usize = 32; type AdvMap = Vec<(RpoDigest, Vec)>; @@ -58,12 +58,10 @@ pub struct FriResult { // a FRI proof inside the Miden VM. // The output is organized as follows: pub fn fri_prove_verify_fold4_ext2(trace_length_e: usize) -> Result { - let max_remainder_size_e = MAX_REMAINDER_POLY_DEGREE_LOG; - let folding_factor_e = FRI_FOLDING_FACTOR_LOG; let trace_length = 1 << trace_length_e; - let lde_blowup = 1 << BLOWUP_FACTOR_LOG; - let max_remainder_size = 1 << max_remainder_size_e; - let folding_factor = 1 << folding_factor_e; + let lde_blowup = BLOWUP_FACTOR; + let max_remainder_size = MAX_REMAINDER_POLY_DEGREE; + let folding_factor = FRI_FOLDING_FACTOR; let nonce = 0_u64; let options = FriOptions::new(lde_blowup, folding_factor, max_remainder_size); @@ -189,8 +187,8 @@ impl FriVerifierFold4Ext2 { options: FriOptions, max_poly_degree: usize, ) -> Result { - assert_eq!(options.blowup_factor(), 1 << BLOWUP_FACTOR_LOG); - assert_eq!(options.folding_factor(), 1 << FRI_FOLDING_FACTOR_LOG); + assert_eq!(options.blowup_factor(), BLOWUP_FACTOR); + assert_eq!(options.folding_factor(), FRI_FOLDING_FACTOR); // infer evaluation domain info let domain_size = max_poly_degree.next_power_of_two() * options.blowup_factor(); @@ -283,7 +281,7 @@ impl FriVerifierFold4Ext2 { // read the remainder from the channel and make sure it matches with the columns // of the previous layer let remainder_commitment = self.layer_commitments.last().unwrap(); - let remainder_poly = channel.read_remainder::<4>(remainder_commitment)?; + let remainder_poly = channel.read_remainder(remainder_commitment)?; let offset = Felt::GENERATOR; for &(final_pos, final_eval) in final_pos_eval.iter() { let comp_eval = eval_horner_rev( @@ -313,7 +311,7 @@ fn iterate_query_fold_4_quad_ext( let mut cur_pos = position; let mut evaluation = *evaluation; let mut domain_size = initial_domain_size; - let domain_offset = Felt::GENERATOR; + let get_domain_offset = Felt::GENERATOR; let initial_domain_generator = *domain_generator; let norm_cst = Felt::get_root_of_unity(2).inv(); @@ -327,7 +325,7 @@ fn iterate_query_fold_4_quad_ext( let mut alphas = vec![]; for depth in 0..number_of_layers { - let target_domain_size = domain_size / (1 << FRI_FOLDING_FACTOR_LOG); + let target_domain_size = domain_size / FRI_FOLDING_FACTOR; let folded_pos = cur_pos % target_domain_size; @@ -363,7 +361,7 @@ fn iterate_query_fold_4_quad_ext( 1 => init_exp * norm_cst, 2 => init_exp * (norm_cst * norm_cst), _ => init_exp * (norm_cst * norm_cst * norm_cst), - } * domain_offset; + } * get_domain_offset; init_exp = init_exp * init_exp * init_exp * init_exp; @@ -391,9 +389,9 @@ fn iterate_query_fold_4_quad_ext( alphas.push(0); alphas.push(0); - *domain_generator = (*domain_generator).exp(((1 << FRI_FOLDING_FACTOR_LOG) as u32).into()); + *domain_generator = (*domain_generator).exp((FRI_FOLDING_FACTOR as u32).into()); cur_pos = folded_pos; - domain_size /= 1 << FRI_FOLDING_FACTOR_LOG; + domain_size /= FRI_FOLDING_FACTOR; } Ok((cur_pos, evaluation, position_evaluation, alphas)) From 36abaf70bf7716f1f3ef95c9a9459ab90616753d Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Thu, 20 Mar 2025 08:05:11 +0100 Subject: [PATCH 11/14] use correct pointer name --- Cargo.lock | 35 ++++++++++++------- Cargo.toml | 11 ------ stdlib/asm/crypto/fri/frie2f4.masm | 56 ++++++++++++++++++------------ 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9364f86b5..c93380c72 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2221,9 +2221,9 @@ checksum = "1ac9aa371f599d22256307c24a9d748c041e548cbf599f35d890f9d365361790" [[package]] name = "tempfile" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "488960f40a3fd53d72c2a29a58722561dee8afdd175bd88e3db4677d7b2ba600" +checksum = "7437ac7763b9b123ccf33c338a5cc1bac6f69b45a136c19bdd8a65e3916435bf" dependencies = [ "fastrand", "getrandom 0.3.2", @@ -2934,7 +2934,8 @@ dependencies = [ [[package]] name = "winter-air" version = "0.12.1" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d7fbdcaa53d220b84811199790c1dda77c025533cdd27715cf1625af2b4027a" dependencies = [ "libm", "winter-crypto", @@ -2946,7 +2947,8 @@ dependencies = [ [[package]] name = "winter-crypto" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32247cde9f43e5bbd05362caa7274608790ea69b14f7c81cd509aae7127c5ff2" dependencies = [ "blake3", "sha3", @@ -2957,7 +2959,8 @@ dependencies = [ [[package]] name = "winter-fri" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4d09d5ac254ac54028ac04751d7ae0cbeb111c6cb08cc30c6400ff61b3203bd" dependencies = [ "winter-crypto", "winter-math", @@ -2967,7 +2970,8 @@ dependencies = [ [[package]] name = "winter-math" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "326dfe4bfa4072b7c909133a88f8807820d3e49e5dfd246f67981771f74a0ed3" dependencies = [ "winter-utils", ] @@ -2975,7 +2979,8 @@ dependencies = [ [[package]] name = "winter-maybe-async" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaa132be74e602b707f1dab5a69c38496445e54ee940e7c281c02b15007241bd" dependencies = [ "quote", "syn", @@ -2983,8 +2988,9 @@ dependencies = [ [[package]] name = "winter-prover" -version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "426be0767a25150af20a241a6ae46bad1bf2f7da86393d897e5ec9967124f760" dependencies = [ "tracing", "winter-air", @@ -2998,7 +3004,8 @@ dependencies = [ [[package]] name = "winter-rand-utils" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc6321741f063344258c80f0c0255a559ded99bc17fe99fab9577f2460065ddf" dependencies = [ "rand 0.8.5", "winter-utils", @@ -3007,15 +3014,17 @@ dependencies = [ [[package]] name = "winter-utils" version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d47518e6931955dcac73a584cacb04550b82ab2f45c72880cbbbdbe13adb63c" dependencies = [ "rayon", ] [[package]] name = "winter-verifier" -version = "0.12.0" -source = "git+https://github.com/Al-Kindi-0/winterfell/?branch=al-reverse-remainder-commitment#2fa1e44a88f4c7c7b474717fdab49c3adb0be054" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e340716f24960b7ff3713029149fe5e52f9c0dae152101528ec5847d92d73e4" dependencies = [ "winter-air", "winter-crypto", diff --git a/Cargo.toml b/Cargo.toml index c3f85bb62..dcd280ef1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,14 +36,3 @@ overflow-checks = true [workspace.dependencies] thiserror = { version = "2.0", default-features = false } - -[patch.crates-io] -winter-air = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-air" } -winter-crypto = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-crypto" } -winter-prover = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-prover" } -winter-verifier = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-verifier" } -winter-math = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-math" } -winter-fri = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-fri" } -winter-maybe-async = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-maybe-async" } -winter-utils = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-utils" } -winter-rand-utils = {git = "https://github.com/Al-Kindi-0/winterfell/", branch = "al-reverse-remainder-commitment", package = "winter-rand-utils" } \ No newline at end of file diff --git a/stdlib/asm/crypto/fri/frie2f4.masm b/stdlib/asm/crypto/fri/frie2f4.masm index e0a3295a8..afd35fc38 100644 --- a/stdlib/asm/crypto/fri/frie2f4.masm +++ b/stdlib/asm/crypto/fri/frie2f4.masm @@ -58,21 +58,21 @@ export.preprocess.16 swap.5 neq.0 end - #=> [X, x, remainder_poly_address_ptr, layer_ptr, g] + #=> [X, x, remainder_poly_ptr, layer_ptr, g] drop - #=> [X, remainder_poly_address_ptr, layer_ptr, g] + #=> [X, remainder_poly_ptr, layer_ptr, g] dup.4 movdn.5 - #=> [X, remainder_poly_address_ptr, remainder_poly_address_ptr, layer_ptr, g] + #=> [X, remainder_poly_ptr, remainder_poly_ptr, layer_ptr, g] adv_push.1 dup mul.2 exec.constants::set_remainder_poly_size sub.1 movdn.4 - #=> [X, len_remainder/2, remainder_poly_address_ptr, remainder_poly_address_ptr, layer_ptr, g] + #=> [X, len_remainder/2, remainder_poly_ptr, remainder_poly_ptr, layer_ptr, g] push.1 while.true @@ -86,9 +86,9 @@ export.preprocess.16 swap.5 neq.0 end - #=> [X, x, x, remainder_poly_address_ptr, layer_ptr, g] + #=> [X, x, x, remainder_poly_ptr, layer_ptr, g] dropw drop drop - #=> [remainder_poly_address_ptr, layer_ptr, g] + #=> [remainder_poly_ptr, layer_ptr, g] exec.constants::set_remainder_poly_address drop drop @@ -98,7 +98,7 @@ end #! was performed correctly. This also advances layer_ptr by 8 to point to the next query layer. #! #! Input: [layer_ptr, layer_ptr, poe, p, e1, e0, layer_ptr, rem_ptr, x, x, x, x, x, x, x, x, ...] -#! Output: [layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] +#! Output: [is_not_last_layer, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] #! #! Cycles: 83 export.verify_query_layer.12 @@ -173,16 +173,18 @@ export.verify_query_layer.12 dup.7 # [rem_ptr, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, ...] dup.1 # [layer_ptr+8, rem_ptr, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, ...] neq - # => [?, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] + # => [is_not_last_layer, layer_ptr+8, layer_ptr+8, poe^4, f_pos, ne1, ne0, layer_ptr+8, rem_ptr, x, x, x, x, x, x, x, x, ...] end #! Verifies one FRI query. #! #! This procedure is specialized to the case when the remainder polynomial, used in the final check, #! is expected to have degree at most 64. +#! This procedure is exactly the same as `verify_query_128` except for the remainder polynomial check, +#! thus any change to one procedure will imply an equivalent change to the other one. #! #! Input: [poe, p, e1, e0, layer_ptr, rem_ptr, ...] -#! Output: [x, x, x, x, x, x, x, x, x, x, ...] +#! Output: [x, x, x, x, x, x, x, x, x, x, x, x, ...] (12 "garbage" elements) #! #! - poe is g^p. #! - p is a query index at the first layer. @@ -240,9 +242,11 @@ end #! #! This procedure is specialized to the case when the remainder polynomial, used in the final check, #! is expected to have degree at most 128. +#! This procedure is exactly the same as `verify_query_64` except for the remainder polynomial check, +#! thus any change to one procedure will imply an equivalent change to the other one. #! #! Input: [poe, p, e1, e0, layer_ptr, rem_ptr, ...] -#! Output: [x, x, x, x, x, x, x, x, x, x, ...] +#! Output: [x, x, x, x, x, x, x, x, x, x, x, x, ...] (12 "garbage" elements) #! #! - poe is g^p. #! - p is a query index at the first layer. @@ -300,6 +304,8 @@ end #! Verifies a FRI proof where the proof was generated over the quadratic extension of the base #! field and layer folding was performed using folding factor 4 when the degree of the remainder #! polynomial is less than 64. +#! This procedure is exactly the same as `verify_128` except for the remainder polynomial check, +#! thus any change to one procedure will imply an equivalent change to the other one. #! #! Input: [query_ptr, layer_ptr, rem_ptr, g, ...] #! Output: [...] @@ -355,19 +361,20 @@ proc.verify_64.4 exec.verify_query_64 # prepare for next iteration (18 cycles) - # => [x, x, x, x, x, x, x, x, x, x, g, ...] + # => [x, x, x, x, x, x, x, x, x, x, x, x, g, ...] dropw drop + # => [x, x, x, x, x, x, x, g, ...] loc_loadw.0 # load [query_ptr, layer_ptr, rem_ptr, g] add.4 - loc_storew.0 # store [query_ptr + 1, layer_ptr, rem_ptr, g] + loc_storew.0 # store [query_ptr + 4, layer_ptr, rem_ptr, g] swapw - # => [x, x, x, x, query_ptr + 1, layer_ptr, rem_ptr, g, ...] + # => [x, x, x, x, query_ptr + 4, layer_ptr, rem_ptr, g, ...] dup.5 dup.5 neq - #=> [?, query_ptr + 1, layer_ptr, rem_ptr, g, ...] + #=> [?, x, x, x, x, query_ptr + 4, layer_ptr, rem_ptr, g, ...] end - #=> [X, ..] + #=> [x, x, x, x, x, x, x, x, ...] dropw dropw end @@ -375,6 +382,8 @@ end #! Verifies a FRI proof where the proof was generated over the quadratic extension of the base #! field and layer folding was performed using folding factor 4 when the degree of the remainder #! polynomial is less than 128. +#! This procedure is exactly the same as `verify_64` except for the remainder polynomial check, +#! thus any change to one procedure will imply an equivalent change to the other one. #! #! Input: [query_ptr, layer_ptr, rem_ptr, g, ...] #! Output: [...] @@ -430,19 +439,20 @@ proc.verify_128.4 exec.verify_query_128 # prepare for next iteration (18 cycles) - # => [x, x, x, x, x, x, x, x, x, x, g, ...] + # => [x, x, x, x, x, x, x, x, x, x, x, x, g, ...] dropw drop + # => [x, x, x, x, x, x, x, g, ...] loc_loadw.0 # load [query_ptr, layer_ptr, rem_ptr, g] add.4 - loc_storew.0 # store [query_ptr + 1, layer_ptr, rem_ptr, g] + loc_storew.0 # store [query_ptr + 4, layer_ptr, rem_ptr, g] swapw - # => [x, x, x, x, query_ptr + 1, layer_ptr, rem_ptr, g, ...] + # => [x, x, x, x, query_ptr + 4, layer_ptr, rem_ptr, g, ...] dup.5 dup.5 neq - #=> [?, x, x, x, x, query_ptr + 1, layer_ptr, rem_ptr, g, ...] + #=> [?, x, x, x, x, query_ptr + 4, layer_ptr, rem_ptr, g, ...] end - #=> [X, X, ..] + #=> [x, x, x, x, x, x, x, x, ...] dropw dropw end @@ -463,17 +473,17 @@ export.verify # (4 cycles) exec.constants::get_lde_domain_generator exec.constants::get_remainder_poly_address - # => [remainder_poly_address_ptr, g, ...] + # => [remainder_poly_ptr, g, ...] # Get the pointer to the first layer commitment # (1 cycles) exec.constants::fri_com_ptr - # => [fri_layer_ptr, remainder_poly_address_ptr, g, ...] + # => [fri_layer_ptr, remainder_poly_ptr, g, ...] # Get the pointer to the first FRI query to the top # (2 cycles) exec.constants::get_fri_queries_address - # => [query_ptr, fri_layer_ptr, remainder_poly_address_ptr, g, ...] + # => [query_ptr, fri_layer_ptr, remainder_poly_ptr, g, ...] exec.constants::get_remainder_poly_size From 1b0667b8ef2e693ff0595bbab5310ae81171dc04 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Thu, 20 Mar 2025 09:00:36 +0100 Subject: [PATCH 12/14] address feedback --- Cargo.lock | 4 ++-- stdlib/asm/crypto/stark/constants.masm | 4 ++++ stdlib/asm/crypto/stark/deep_queries.masm | 4 ++-- stdlib/asm/crypto/stark/public_inputs.masm | 2 +- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c93380c72..9e89a105c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2958,9 +2958,9 @@ dependencies = [ [[package]] name = "winter-fri" -version = "0.12.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4d09d5ac254ac54028ac04751d7ae0cbeb111c6cb08cc30c6400ff61b3203bd" +checksum = "32b346b0eea2292986a1193bfc70dd2dbcdbb6adb3e5110b71d18c6f1077df10" dependencies = [ "winter-crypto", "winter-math", diff --git a/stdlib/asm/crypto/stark/constants.masm b/stdlib/asm/crypto/stark/constants.masm index 6dbf917ed..f68734270 100644 --- a/stdlib/asm/crypto/stark/constants.masm +++ b/stdlib/asm/crypto/stark/constants.masm @@ -354,6 +354,10 @@ export.tmp4 push.TMP4 end +export.zeroize_stack_word + exec.zero_word_ptr mem_loadw +end + #! Store details about the LDE domain. #! #! The info stored is `[lde_size, log(lde_size), lde_g, 0]`. diff --git a/stdlib/asm/crypto/stark/deep_queries.masm b/stdlib/asm/crypto/stark/deep_queries.masm index 3c8a28c92..8fb3425f1 100644 --- a/stdlib/asm/crypto/stark/deep_queries.masm +++ b/stdlib/asm/crypto/stark/deep_queries.masm @@ -230,7 +230,7 @@ proc.compute_q_z_p_gz_at_alpha ### i) Process the last 2 extension field elements movdnw.2 # => [h7`, h6`, h5`, h4`, h15`, h14`, h13`, h12`, h11`, h10`, h9`, h8`, U, ...] - exec.constants::zero_word_ptr mem_loadw + exec.constants::zeroize_stack_word horner_eval_ext # => [Y, Y, Y, ptr_ood, ptr_alpha, acc1, acc0, ...] @@ -281,7 +281,7 @@ proc.compute_q_z_p_gz_at_alpha ## 3) Load and process the last 2 extension field elements. ## We use `mem_stream` but we will discard the last 4 field elements. mem_stream - exec.constants::zero_word_ptr mem_loadw + exec.constants::zeroize_stack_word horner_eval_ext ## 5) Multiply the accumulator by the adjustment factor in order to get P^gz(alpha) diff --git a/stdlib/asm/crypto/stark/public_inputs.masm b/stdlib/asm/crypto/stark/public_inputs.masm index 0e0cad62e..52e264670 100644 --- a/stdlib/asm/crypto/stark/public_inputs.masm +++ b/stdlib/asm/crypto/stark/public_inputs.masm @@ -37,7 +37,7 @@ export.load # 3) Load the kernel procedures digests # TODO: Support non-empty kernels swapw - exec.constants::zero_word_ptr mem_loadw + exec.constants::zeroize_stack_word hperm exec.rpo::squeeze_digest From 1776e98c3d5fcdad3a8363341f326b5bce6a3c35 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Thu, 20 Mar 2025 09:21:09 +0100 Subject: [PATCH 13/14] doc: minor update --- stdlib/tests/crypto/fri/verifier_fri_e2f4.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs index 70e270a23..044cc2947 100644 --- a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs +++ b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs @@ -24,10 +24,10 @@ const NUM_FRI_QUERIES: usize = 32; type AdvMap = Vec<(RpoDigest, Vec)>; pub struct FriResult { - /// contains the Merkle authentication paths used to authenticate the queries. + /// A vector containing the Merkle authentication paths used to authenticate the queries. pub partial_trees: Vec, - /// used to unhash Merkle nodes to a sequence of field elements representing the query-values. + /// A map used to unhash Merkle nodes to a sequence of field elements representing the query-values. pub advice_maps: AdvMap, /// A vector of consecutive quadruples of the form (poe, p, e1, e0) where p is index of the From 2aa70b875e679b6233382f2d612264c6723f7920 Mon Sep 17 00:00:00 2001 From: Al-Kindi-0 <82364884+Al-Kindi-0@users.noreply.github.com> Date: Thu, 20 Mar 2025 09:32:25 +0100 Subject: [PATCH 14/14] fix lints --- stdlib/tests/crypto/fri/verifier_fri_e2f4.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs index 044cc2947..f3bd8ee08 100644 --- a/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs +++ b/stdlib/tests/crypto/fri/verifier_fri_e2f4.rs @@ -27,7 +27,8 @@ pub struct FriResult { /// A vector containing the Merkle authentication paths used to authenticate the queries. pub partial_trees: Vec, - /// A map used to unhash Merkle nodes to a sequence of field elements representing the query-values. + /// A map used to unhash Merkle nodes to a sequence of field elements representing the + /// query-values. pub advice_maps: AdvMap, /// A vector of consecutive quadruples of the form (poe, p, e1, e0) where p is index of the