diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 07f039d25..1b5e77e9b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,7 +15,7 @@ concurrency: cancel-in-progress: true env: - CARGO_TERM_COLOR: always + CARGO_TERM_COLOR: always jobs: test_mpt_trie: @@ -33,7 +33,7 @@ jobs: - name: Set up rust cache uses: Swatinem/rust-cache@v2 with: - cache-on-failure: true + cache-on-failure: true - name: Test in mpt_trie subdirectory run: cargo test --manifest-path mpt_trie/Cargo.toml @@ -58,7 +58,7 @@ jobs: - name: Set up rust cache uses: Swatinem/rust-cache@v2 with: - cache-on-failure: true + cache-on-failure: true - name: Test in trace_decoder subdirectory run: cargo test --manifest-path trace_decoder/Cargo.toml @@ -83,7 +83,7 @@ jobs: - name: Set up rust cache uses: Swatinem/rust-cache@v2 with: - cache-on-failure: true + cache-on-failure: true - name: Test in proof_gen subdirectory run: cargo test --manifest-path proof_gen/Cargo.toml @@ -108,7 +108,7 @@ jobs: - name: Set up rust cache uses: Swatinem/rust-cache@v2 with: - cache-on-failure: true + cache-on-failure: true - name: Test in evm_arithmetization subdirectory run: cargo test --manifest-path evm_arithmetization/Cargo.toml @@ -119,7 +119,7 @@ jobs: RUST_BACKTRACE: 1 lints: - name: Formatting and Clippy + name: Rustdoc, Formatting and Clippy runs-on: ubuntu-latest timeout-minutes: 10 if: "! contains(toJSON(github.event.commits.*.message), '[skip-ci]')" @@ -130,15 +130,18 @@ jobs: - name: Install nightly toolchain uses: dtolnay/rust-toolchain@nightly with: - components: rustfmt, clippy + components: rustfmt, clippy - name: Set up rust cache uses: Swatinem/rust-cache@v2 with: - cache-on-failure: true + cache-on-failure: true - name: Run cargo fmt run: cargo fmt --all --check - name: Run cargo clippy run: cargo clippy --all-features --all-targets -- -D warnings -A incomplete-features + + - name: Rustdoc + run: cargo doc --all diff --git a/evm_arithmetization/src/byte_packing/byte_packing_stark.rs b/evm_arithmetization/src/byte_packing/byte_packing_stark.rs index 1a0acb51c..4c78c4b52 100644 --- a/evm_arithmetization/src/byte_packing/byte_packing_stark.rs +++ b/evm_arithmetization/src/byte_packing/byte_packing_stark.rs @@ -9,9 +9,9 @@ //! //! The length of a sequence can be retrieved for CTLs as: //! -//! sequence_length = \sum_{i=0}^31 b[i] * (i + 1) +//! `sequence_length = \sum_{i=0}^31 b[i] * (i + 1)` //! -//! where b[i] is the `i`-th byte flag. +//! where `b[i]` is the `i`-th byte flag. //! //! Because of the discrepancy in endianness between the different tables, the //! byte sequences are actually written in the trace in reverse order from the diff --git a/evm_arithmetization/src/cpu/kernel/aggregator.rs b/evm_arithmetization/src/cpu/kernel/aggregator.rs index 47a378b33..746181dfe 100644 --- a/evm_arithmetization/src/cpu/kernel/aggregator.rs +++ b/evm_arithmetization/src/cpu/kernel/aggregator.rs @@ -7,7 +7,7 @@ use super::assembler::{assemble, Kernel}; use crate::cpu::kernel::constants::evm_constants; use crate::cpu::kernel::parser::parse; -pub const NUMBER_KERNEL_FILES: usize = 153; +pub const NUMBER_KERNEL_FILES: usize = 156; pub static KERNEL_FILES: [&str; NUMBER_KERNEL_FILES] = [ "global jumped_to_0: PANIC", @@ -65,7 +65,10 @@ pub static KERNEL_FILES: [&str; NUMBER_KERNEL_FILES] = [ include_str!("asm/curve/bn254/curve_arithmetic/msm.asm"), include_str!("asm/curve/bn254/curve_arithmetic/pairing.asm"), include_str!("asm/curve/bn254/curve_arithmetic/precomputation.asm"), - include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve.asm"), + include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve_add.asm"), + include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve_checks.asm"), + include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve_endomorphism.asm"), + include_str!("asm/curve/bn254/curve_arithmetic/twisted_curve_mul.asm"), include_str!("asm/curve/bn254/field_arithmetic/degree_6_mul.asm"), include_str!("asm/curve/bn254/field_arithmetic/degree_12_mul.asm"), include_str!("asm/curve/bn254/field_arithmetic/frobenius.asm"), diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/curve_add.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/curve_add.asm index a43c4047d..98ded41f7 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/curve_add.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/curve_add.asm @@ -10,12 +10,12 @@ global bn_add: %bn_check // stack: isValid(x0, y0), x0, y0, x1, y1, retdest DUP5 - // stack: x1, isValid(x0, y0), x0, y0, x1, y1, retdest + // stack: y1, isValid(x0, y0), x0, y0, x1, y1, retdest DUP5 // stack: x1, y1, isValid(x0, y0), x0, y0, x1, y1, retdest %bn_check // stack: isValid(x1, y1), isValid(x0, y0), x0, y0, x1, y1, retdest - AND + MUL // Cheaper than AND // stack: isValid(x1, y1) & isValid(x0, y0), x0, y0, x1, y1, retdest %jumpi(bn_add_valid_points) // stack: x0, y0, x1, y1, retdest diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/pairing.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/pairing.asm index 735d001aa..4517f7cb7 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/pairing.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/pairing.asm @@ -68,9 +68,16 @@ bn254_input_check: // stack: inp_j', inp_j, j, k, inp %load_fp254_4 // stack: Q_j, inp_j, j, k, inp + %dup_bn_g2 + // stack: Q_j, Q_j, inp_j, j, k, inp %bn_check_twisted - // stack: valid?, inp_j, j, k, inp ISZERO + // stack: valid_1?, Q_j, inp_j, j, k, inp + %stack (b, Q: 4) -> (Q, b) + %bn_check_twisted_subgroup + ISZERO + // stack: valid_2?, valid_1?, inp_j, j, k, inp + ADD // Cheaper than OR %jumpi(bn_pairing_invalid_input) // stack: inp_j, j, k, inp POP diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_add.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_add.asm new file mode 100644 index 000000000..b4ff7a3eb --- /dev/null +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_add.asm @@ -0,0 +1,197 @@ +// Elliptic curve addition on the twist of BN254 curve. +// Assumption: (X0,Y0) is a valid point. +// Uses the standard affine addition formula. +global bn_twisted_add: + // stack: X0: 2, Y0: 2, X1: 2, Y1: 2, retdest + + // Check if the first point is the identity. + %dup_fp254_2_2 + // stack: Y0, X0, Y0, X1, Y1, retdest + %dup_fp254_2_2 + // stack: X0, Y0, X0, Y0, X1, Y1, retdest + %bn_check_twisted_ident + // stack: (X0,Y0)==(0,0), X0, Y0, X1, Y1, retdest + %jumpi(bn_twisted_add_fst_zero) + // stack: X0, Y0, X1, Y1, retdest + + // Check if the second point is the identity. + %dup_fp254_2_6 + // stack: Y1, X0, Y0, X1, Y1, retdest + %dup_fp254_2_6 + // stack: X1, Y1, X0, Y0, X1, Y1, retdest + %bn_check_twisted_ident + // stack: (X1,Y1)==(0,0), X0, Y0, X1, Y1, retdest + %jumpi(bn_twisted_add_snd_zero) + // stack: X0, Y0, X1, Y1, retdest + + // Check if both points have the same X-coordinate. + %dup_fp254_2_4 + // stack: X1, X0, Y0, X1, Y1, retdest + %dup_fp254_2_2 + // stack: X0, X1, X0, Y0, X1, Y1, retdest + %eq_fp254_2 + // stack: X0 == X1, X0, Y0, X1, Y1, retdest + %jumpi(bn_twisted_add_equal_first_coord) + // stack: X0, Y0, X1, Y1, retdest + + // Otherwise, we can use the standard formula. + // Compute lambda = (Y0 - Y1)/(X0 - X1) + %dup_fp254_2_6 + // stack: Y1, X0, Y0, X1, Y1, retdest + %dup_fp254_2_4 + // stack: Y0, Y1, X0, Y0, X1, Y1, retdest + %sub_fp254_2 + // stack: Y0 - Y1, X0, Y0, X1, Y1, retdest + %dup_fp254_2_6 + // stack: X1, Y0 - Y1, X0, Y0, X1, Y1, retdest + %dup_fp254_2_4 + // stack: X0, X1, Y0 - Y1, X0, Y0, X1, Y1, retdest + %sub_fp254_2 + // stack: X0 - X1, Y0 - Y1, X0, Y0, X1, Y1, retdest + %divr_fp254_2 + // stack: lambda, X0, Y0, X1, Y1, retdest + %jump(bn_twisted_add_valid_points_with_lambda) + +// BN254 twisted elliptic curve addition. +// Assumption: (X0,Y0) == (0,0) +bn_twisted_add_fst_zero: + // stack: X0: 2, Y0: 2, X1: 2, Y1: 2, retdest + // Just return (X1, Y1) + %stack (X0: 2, Y0: 2, X1: 2, Y1: 2, retdest) -> (retdest, X1, Y1) + JUMP + +// BN254 twisted elliptic curve addition. +// Assumption: (X1,Y1) == (0,0) +bn_twisted_add_snd_zero: + // stack: X0: 2, Y0: 2, X1: 2, Y1: 2, retdest + + // Just return (X0,Y0) + %stack (X0: 2, Y0: 2, X1: 2, Y1: 2, retdest) -> (retdest, X0, Y0) + JUMP + +// BN254 twisted elliptic curve addition. +// Assumption: lambda = (Y0 - Y1)/(X0 - X1) +bn_twisted_add_valid_points_with_lambda: + // stack: lambda: 2, X0: 2, Y0: 2, X1: 2, Y1: 2, retdest + + // Compute X2 = lambda^2 - X1 - X0 + %dup_fp254_2_2 + // stack: X0, lambda, X0, Y0, X1, Y1, retdest + %dup_fp254_2_8 + // stack: X1, X0, lambda, X0, Y0, X1, Y1, retdest + %dup_fp254_2_4 + // stack: lambda, X1, X0, lambda, X0, Y0, X1, Y1, retdest + %dup_fp254_2_0 + // stack: lambda, lambda, X1, X0, lambda, X0, Y0, X1, Y1, retdest + %mul_fp254_2 + // stack: lambda^2, X1, X0, lambda, X0, Y0, X1, Y1, retdest + %sub_fp254_2 + // stack: lambda^2 - X1, X0, lambda, X0, Y0, X1, Y1, retdest + %sub_fp254_2 + // stack: X2, lambda, X0, Y0, X1, Y1, retdest + + // Compute Y2 = lambda*(X1 - X2) - Y1 + %dup_fp254_2_0 + // stack: X2, X2, lambda, X0, Y0, X1, Y1, retdest + %dup_fp254_2_10 + // stack: X1, X2, X2, lambda, X0, Y0, X1, Y1, retdest + %sub_fp254_2 + // stack: X1 - X2, X2, lambda, X0, Y0, X1, Y1, retdest + %dup_fp254_2_4 + // stack: lambda, X1 - X2, X2, lambda, X0, Y0, X1, Y1, retdest + %mul_fp254_2 + // stack: lambda * (X1 - X2), X2, lambda, X0, Y0, X1, Y1, retdest + %dup_fp254_2_12 + // stack: Y1, lambda * (X1 - X2), X2, lambda, X0, Y0, X1, Y1, retdest + %stack (Y1: 2, T: 2) -> (T, Y1) + // stack: lambda * (X1 - X2), Y1, X2, lambda, X0, Y0, X1, Y1, retdest + %sub_fp254_2 + // stack: Y2, X2, lambda, X0, Y0, X1, Y1, retdest + + // Return X2, Y2 + %stack (Y2: 2, X2: 2, lambda: 2, X0: 2, Y0: 2, X1: 2, Y1: 2, retdest) -> (retdest, X2, Y2) + JUMP + +// BN254 twisted elliptic curve addition. +// Assumption: (X0,Y0) and (X1,Y1) are valid points and X0 == X1 +bn_twisted_add_equal_first_coord: + // stack: X0, Y0, X1, Y1, retdest with X0 == X1 + + // Check if the points are equal + %dup_fp254_2_2 + // stack: Y0, X0, Y0, X1, Y1, retdest + %dup_fp254_2_8 + // stack: Y1, Y0, X0, Y0, X1, Y1, retdest + %eq_fp254_2 + // stack: Y1 == Y0, X0, Y0, X1, Y1, retdest + %jumpi(bn_twisted_add_equal_points) + // stack: X0, Y0, X1, Y1, retdest + + // Otherwise, one is the negation of the other so we can return the identity. + %stack (garbage: 8, retdest) -> (retdest, 0, 0, 0, 0) + // stack: retdest, X=0, Y=0 + JUMP + + +// BN254 twisted elliptic curve addition. +// Assumption: X0 == X1 and Y0 == Y1 +// Standard doubling formula. +bn_twisted_add_equal_points: + // stack: X0, Y0, X1, Y1, retdest + + // Compute lambda = 3/2 * X0^2 / Y0 + %dup_fp254_2_0 + // stack: X0, X0, Y0, X1, Y1, retdest + %dup_fp254_2_0 + // stack: X0, X0, X0, Y0, X1, Y1, retdest + %mul_fp254_2 + // stack: X0^2, X0, Y0, X1, Y1, retdest + PUSH 0X183227397098d014dc2822db40c0ac2ecbc0b548b438e5469e10460b6c3e7ea5 // 3/2 in the base field + // stack: 3/2, X0^2, X0, Y0, X1, Y1, retdest + %scale_fp254_2 + // stack: 3/2 * X0^2, X0, Y0, X1, Y1, retdest + %dup_fp254_2_4 + // stack: Y0, 3/2 * X0^2, X0, Y0, X1, Y1, retdest + %divr_fp254_2 + // stack: lambda, X0, Y0, X1, Y1, retdest + %jump(bn_twisted_add_valid_points_with_lambda) + +// BN254 twisted elliptic curve doubling. +// Assumption: (X0,Y0) is a valid point. +// Standard doubling formula. +global bn_twisted_double: + // stack: X, Y, retdest + %dup_bn_g2 + // stack: X, Y, X, Y, retdest + %bn_check_twisted_ident + // stack: (X,Y)==(0,0), X, Y, retdest + %jumpi(ec_twisted_double_retself) + %dup_bn_g2 + // stack: X, Y, X, Y, retdest + %jump(bn_twisted_add_equal_points) + +// Convenience macro to call bn_twisted_add and return where we left off. +%macro bn_twisted_add + %stack (X0: 2, Y0: 2, X1: 2, Y1: 2) -> (X0, Y0, X1, Y1, %%after) + %jump(bn_twisted_add) +%%after: +%endmacro + +%macro bn_twisted_sub + // stack: X0: 2, Y0: 2, X1: 2, Y1: 2 + %swap_fp254_2_4 + // stack: Y1, Y0, X1, X0 + PUSH 0 PUSH 0 + %sub_fp254_2 + // stack: -Y1, Y0, X1, X0 + %stack (Y1: 2, Y0: 2, X1: 2, X0: 2) -> (X0, Y0, X1, Y1, %%after) + %jump(bn_twisted_add) +%%after: +%endmacro + +// Convenience macro to call bn_twisted_double and return where we left off. +%macro bn_twisted_double + %stack (X: 2, Y: 2) -> (X, Y, %%after) + %jump(bn_twisted_double) +%%after: +%endmacro diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_checks.asm similarity index 65% rename from evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve.asm rename to evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_checks.asm index 859c45fe3..bbd7d06cf 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_checks.asm @@ -92,3 +92,52 @@ MUL // Cheaper than AND MUL // Cheaper than AND %endmacro + +/// The `ECPAIRING` precompile requires checking that G2 +/// inputs are on the correct prime-order subgroup. +/// This macro performs this check, based on the algorithm +/// detailed in . +%macro bn_check_twisted_subgroup + // stack: Q = (X, Y) + %dup_bn_g2 + // stack: Q, Q + %bn_twisted_mul_by_z + // stack: zQ, Q + %dup_bn_g2 + // stack: zQ, zQ, Q + %swap_bn_g2_2 + // stack: Q, zQ, zQ + %bn_twisted_add + // stack: [z+1]Q, zQ + %swap_bn_g2 + // stack: zQ, [z+1]Q + %bn_endomorphism + // stack: phi(zQ), [z+1]Q + %dup_bn_g2 + // stack: phi(zQ), phi(zQ), [z+1]Q + %bn_endomorphism + // stack: phi^2(zQ), phi(zQ), [z+1]Q + %dup_bn_g2 + // stack: phi^2(zQ), phi^2(zQ), phi(zQ), [z+1]Q + %bn_endomorphism + // stack: phi^3(zQ), phi^2(zQ), phi(zQ), [z+1]Q + %bn_twisted_double + // stack: phi^3([2z]Q), phi^2(zQ), phi(zQ), [z+1]Q + %bn_twisted_sub + // stack: phi^3([2z]Q) - phi^2(zQ), phi(zQ), [z+1]Q + %bn_twisted_sub + // stack: phi^3([2z]Q) - phi^2(zQ) - phi(zQ), [z+1]Q + %bn_twisted_sub + // stack: phi^3([2z]Q) - phi^2(zQ) - phi(zQ) - [z+1]Q + %bn_check_twisted_ident + // stack: is_ident +%endmacro + +// Return [(u256::MAX, u256::MAX), (u256::MAX, u256::MAX)] which is used to indicate the input was invalid. +%macro bn_twisted_invalid_input + // stack: retdest + PUSH @U256_MAX + // stack: u256::MAX, retdest + %stack (max, retdest) -> (retdest, max, max, max, max) + JUMP +%endmacro \ No newline at end of file diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_endomorphism.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_endomorphism.asm new file mode 100644 index 000000000..dfe819ef8 --- /dev/null +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_endomorphism.asm @@ -0,0 +1,28 @@ +// Implementation of the BN254 twist endomorphism. + +/// Frobenius map over BN254 quadratic extension. +%macro frob_fp254_2 + // stack: X = (x, x_) + %conj_fp254_2 + // stack: frob(X) +%endmacro + +%macro bn_endomorphism + // stack: X: 2, Y: 2 + %frob_fp254_2 + // stack: X', Y + %swap_fp254_2 + // stack: Y, X' + %frob_fp254_2 + // stack: Y', X' + PUSH @BN_ENDO_Y_COORD_IM + PUSH @BN_ENDO_Y_COORD_RE + %mul_fp254_2 + // stack: φ_y.Y', X' + %swap_fp254_2 + // stack: X', φ_y.Y' + PUSH @BN_ENDO_X_COORD_IM + PUSH @BN_ENDO_X_COORD_RE + %mul_fp254_2 + // stack: φ_x.X', φ_y.Y' +%endmacro diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_mul.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_mul.asm new file mode 100644 index 000000000..01586b069 --- /dev/null +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/curve_arithmetic/twisted_curve_mul.asm @@ -0,0 +1,84 @@ +// BN254 elliptic curve scalar multiplication on the twist. +// Uses the naive algorithm. +global bn_twisted_mul: + // stack: X: 2, Y: 2, s, retdest + %dup_bn_g2 + // stack: X, Y, X, Y, s, retdest + %bn_check_twisted_ident + // stack: (X,Y)==(0,0), X, Y, s, retdest + %jumpi(ret_zero_ec_twisted_mul) + // stack: X, Y, s, retdest + %dup_bn_g2 + // stack: X, Y, X, Y, s, retdest + %bn_check_twisted + // stack: isValid(X, Y), X, Y, s, retdest + %jumpi(bn_twisted_mul_valid_point) + // stack: X, Y, s, retdest + %pop5 + %bn_twisted_invalid_input + +bn_twisted_mul_valid_point: + // stack: X, Y, s, retdest + DUP5 + %num_bits + // stack: n, X, Y, s, retdest + %stack (n, X: 2, Y: 2, s, retdest) -> (X, Y, s, n, retdest) + %rep 4 + PUSH 0 // identity point + %endrep +bn_twisted_mul_loop: + // stack: X', Y', X, Y, s, n, retdest + DUP10 + ISZERO + %jumpi(bn_twisted_mul_end) + // stack: X1, Y1, X, Y, s, n, retdest + %bn_twisted_double + // stack: X2, Y2, X, Y, s, n, retdest + DUP9 + // stack: s, X2, Y2, X, Y, s, n, retdest + PUSH 1 DUP12 SUB + // stack: n - 1, s, X2, Y2, X, Y, s, n, retdest + SHR + // stack: s >> n - 1, X2, Y2, X, Y, s, n, retdest + PUSH 1 + AND + // stack: nth_bit, X2, Y2, X, Y, s, n, retdest + %jumpi(bn_twisted_mul_add_base) + // stack: X2, Y2, X, Y, s, n, retdest + SWAP9 + %decrement + SWAP9 + // stack: X2, Y2, X, Y, s, n-1, retdest + %jump(bn_twisted_mul_loop) + +bn_twisted_mul_add_base: + // stack: X2, Y2, X, Y, s, n, retdest + %dup_fp254_2_6 + // stack: Y, X2, Y2, X, Y, s, n, retdest + %dup_fp254_2_6 + // stack: X, Y, X2, Y2, X, Y, s, n, retdest + %bn_twisted_add + // stack: X3, Y3, X, Y, s, n, retdest + SWAP9 + %decrement + SWAP9 + // stack: X3, Y3, X, Y, s, n-1, retdest + %jump(bn_twisted_mul_loop) + +bn_twisted_mul_end: + %stack (AX: 2, AY: 2, X: 2, Y: 2, s, n, retdest) -> (retdest, AX, AY) + JUMP + +// Convenience macro to call bn_twisted_mul and return where we left off. +%macro bn_twisted_mul + %stack (X: 2, Y: 2, s) -> (X, Y, s, %%after) + %jump(bn_twisted_mul) +%%after: +%endmacro + +// Convenience macro to call bn_twisted_mul_by_z and return where we left off. +%macro bn_twisted_mul_by_z + %stack (X: 2, Y: 2) -> (X, Y, 0x44e992b44a6909f1, %%after) + %jump(bn_twisted_mul) +%%after: +%endmacro diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/field_arithmetic/inverse.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/field_arithmetic/inverse.asm index 7c7729057..1c07a15dc 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/field_arithmetic/inverse.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/field_arithmetic/inverse.asm @@ -24,6 +24,41 @@ %endmacro +// Returns reverse order division Y/X, modulo N, in Fp2. +%macro divr_fp254_2 + // stack: X, Y + %inv_fp254_2 + // stack: X^-1, Y + %mul_fp254_2 +%endmacro + +// The inverse of an element X in BN254 quadratic extension field +// is just X'/||X||^2 since ||X||^2 = XX', where X' = conj(X). +%macro inv_fp254_2 + // stack: X = (x, x_) + %dup_fp254_2_0 + // stack: x, x_, x, x_ + DUP1 + // stack: x, x, x_, x, x_ + MULFP254 + // stack: x^2, x_, x, x_ + SWAP1 + // stack: x_, x^2, x, x_ + DUP1 + // stack: x_, x_, x^2, x, x_ + MULFP254 + // stack: x_^2, x^2, x, x_ + ADDFP254 + // stack: ||X||^2, x, x_ + %inv_fp254 + // stack: inv, x, x_ + %scale_fp254_2 + // stack: X/||X||^2 + %conj_fp254_2 + // stack: Y = 1/X +%endmacro + + global inv_fp254_12: // stack: inp, out, retdest %prover_inv_fp254_12 diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/field_arithmetic/util.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/field_arithmetic/util.asm index 897404dbf..b77cace48 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/field_arithmetic/util.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/bn254/field_arithmetic/util.asm @@ -111,6 +111,20 @@ // stack: z, z_ %endmacro +%macro sub_fp254_2 + // stack: x, x_, y, y_ + SWAP3 + // stack: y_, x_, y, x + SWAP1 + // stack: x_, y_, y, x + SUBFP254 + // stack: z_, y, x + SWAP2 + // stack: x, y, z_ + SUBFP254 + // stack: z, z_ +%endmacro + /// Given z = x + iy: Fp254_2, return complex conjugate z': Fp254_2 /// where input is represented z.re, z.im and output as z'.im, z'.re /// cost: 9; note this returns y, x for the output x + yi @@ -364,6 +378,108 @@ // stack: %endmacro +// cost: 2 +%macro dup_fp254_2_0 + // stack: f: 2 + DUP2 + DUP2 + // stack: f: 2, f: 2 +%endmacro + +// cost: 2 +%macro dup_fp254_2_2 + // stack: X: 2, f: 2 + DUP4 + DUP4 + // stack: f: 2, X: 2, f: 2 +%endmacro + +// cost: 2 +%macro dup_fp254_2_4 + // stack: X: 4, f: 2 + DUP6 + DUP6 + // stack: f: 2, X: 4, f: 2 +%endmacro + +// cost: 2 +%macro dup_fp254_2_6 + // stack: X: 6, f: 2 + DUP8 + DUP8 + // stack: f: 2, X: 6, f: 2 +%endmacro + +// cost: 2 +%macro dup_fp254_2_7 + // stack: X: 7, f: 2 + DUP9 + DUP9 + // stack: f: 2, X: 7, f: 2 +%endmacro + +// cost: 2 +%macro dup_fp254_2_8 + // stack: X: 8, f: 2 + DUP10 + DUP10 + // stack: f: 2, X: 8, f: 2 +%endmacro + +// cost: 2 +%macro dup_fp254_2_10 + // stack: X: 10, f: 2 + DUP12 + DUP12 + // stack: f: 2, X: 10, f: 2 +%endmacro + +// cost: 2 +%macro dup_fp254_2_12 + // stack: X: 12, f: 2 + DUP14 + DUP14 + // stack: f: 2, X: 12, f: 2 +%endmacro + +// cost: 4 +%macro dup_bn_g2 + // stack: X: 2, Y: 2 + %dup_fp254_2_2 + %dup_fp254_2_2 + // stack: X: 2, Y: 2, X: 2, Y: 2 +%endmacro + +%macro swap_bn_g2 + // stack: P: 4, Q: 4 + %stack (P: 4, Q: 4) -> (Q, P) + // stack: Q: 4, P: 4 +%endmacro + +%macro swap_bn_g2_2 + // stack: P: 4, T: 4, Q: 4 + %stack (P: 4, T: 4, Q: 4) -> (Q, T, P) + // stack: Q: 4, T: 4, P: 4 +%endmacro + +%macro swap_fp254_2 + // stack: X: 2, Y: 2 + %stack (x, x_, y, y_) -> (y, y_, x, x_) + // stack: Y: 2, X: 2 +%endmacro + +%macro swap_fp254_2_2 + // stack: X: 2, T: 2, Y: 2 + %stack (x, x_, t, t_, y, y_) -> (y, y_, t, t_, x, x_) + // stack: Y: 2, T: 2, X: 2 +%endmacro + +%macro swap_fp254_2_4 + // stack: X: 2, T: 4, Y: 2 + %stack (x, x_, t0, t1, t2, t3, y, y_) -> (y, y_, t0, t1, t2, t3, x, x_) + // stack: Y: 2, T: 4, X: 2 +%endmacro + // cost: 6 %macro dup_fp254_6_0 // stack: f: 6 @@ -374,7 +490,7 @@ DUP6 DUP6 // stack: f: 6, f: 6 -%endmacro +%endmacro // cost: 6 %macro dup_fp254_6_2 @@ -386,7 +502,7 @@ DUP8 DUP8 // stack: f: 6, X: 2, f: 6 -%endmacro +%endmacro // cost: 6 %macro dup_fp254_6_6 diff --git a/evm_arithmetization/src/cpu/kernel/asm/curve/common.asm b/evm_arithmetization/src/cpu/kernel/asm/curve/common.asm index 50f174fac..2899a652a 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/curve/common.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/curve/common.asm @@ -10,10 +10,19 @@ global ret_zero_ec_mul: // stack: retdest, 0, 0 JUMP +global ret_zero_ec_twisted_mul: + // stack: X: 2, Y: 2, s, retdest + %stack (garbage: 5, retdest) -> (retdest, 0, 0, 0, 0) + JUMP + global ec_double_retself: %stack (x, y, retdest) -> (retdest, x, y) JUMP +global ec_twisted_double_retself: + %stack (X: 2, Y: 2, retdest) -> (retdest, X, Y) + JUMP + // Check if (x,y)==(0,0) %macro ec_isidentity // stack: x, y diff --git a/evm_arithmetization/src/cpu/kernel/asm/memory/core.asm b/evm_arithmetization/src/cpu/kernel/asm/memory/core.asm index 070e474f6..9e18bc3e3 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/memory/core.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/memory/core.asm @@ -444,31 +444,3 @@ // stack: offset, value %mstore_kernel_u32(@SEGMENT_KERNEL_GENERAL) %endmacro - -// Load a single value from kernel general 2 memory. -%macro mload_kernel_general_2 - // stack: offset - %mload_kernel(@SEGMENT_KERNEL_GENERAL_2) - // stack: value -%endmacro - -// Load a single value from kernel general memory. -%macro mload_kernel_general_2(offset) - PUSH $offset - %mload_kernel(@SEGMENT_KERNEL_GENERAL_2) - // stack: value -%endmacro - -%macro mstore_kernel_general_2 - // stack: offset, value - %mstore_kernel(@SEGMENT_KERNEL_GENERAL_2) - // stack: (empty) -%endmacro - -%macro mstore_kernel_general_2(offset) - // stack: value - PUSH $offset - // stack: offset, value - %mstore_kernel_general_2 - // stack: (empty) -%endmacro diff --git a/evm_arithmetization/src/cpu/kernel/asm/rlp/num_bytes.asm b/evm_arithmetization/src/cpu/kernel/asm/rlp/num_bytes.asm index de0a7ca96..b1f441fe3 100644 --- a/evm_arithmetization/src/cpu/kernel/asm/rlp/num_bytes.asm +++ b/evm_arithmetization/src/cpu/kernel/asm/rlp/num_bytes.asm @@ -3,13 +3,9 @@ global num_bytes: // stack: x, retdest DUP1 ISZERO %jumpi(return_1) - // Non-deterministically guess the number of bits - PROVER_INPUT(num_bits) - %stack(num_bits, x) -> (num_bits, 1, x, num_bits) - SUB - SHR - // stack: 1, num_bits - %assert_eq_const(1) + // stack: x, retdest + %num_bits + // stack: num_bits, retdest // convert number of bits to number of bytes %add_const(7) %shr_const(3) @@ -28,3 +24,15 @@ return_1: %jump(num_bytes) %%after: %endmacro + +%macro num_bits + // Non-deterministically guess the number of bits + // stack: x + PROVER_INPUT(num_bits) + %stack (num_bits, x) -> (num_bits, x, num_bits) + %decrement + SHR + // stack: 1, num_bits + %assert_eq_const(1) + // stack: num_bits +%endmacro diff --git a/evm_arithmetization/src/cpu/kernel/constants/mod.rs b/evm_arithmetization/src/cpu/kernel/constants/mod.rs index 2b709d469..d9e6d5e37 100644 --- a/evm_arithmetization/src/cpu/kernel/constants/mod.rs +++ b/evm_arithmetization/src/cpu/kernel/constants/mod.rs @@ -120,7 +120,7 @@ const MISC_CONSTANTS: [(&str, [u8; 32]); 5] = [ // *Note*: Changing this will break some tests. ( "ENCODED_EMPTY_NODE_ADDR", - hex!("0000000000000000000000000000000000000000000000000000000c00000000"), + hex!("0000000000000000000000000000000000000000000000000000000b00000000"), ), // 0x10000 = 2^16 bytes, much larger than any RLP blob the EVM could possibly create. ( @@ -132,7 +132,7 @@ const MISC_CONSTANTS: [(&str, [u8; 32]); 5] = [ // *Note*: Changing this will break some tests. ( "INITIAL_TXN_RLP_ADDR", - hex!("0000000000000000000000000000000000000000000000000000000c00000001"), + hex!("0000000000000000000000000000000000000000000000000000000b00000001"), ), // Scaled boolean value indicating that we are in kernel mode, to be used within `kexit_info`. // It is equal to 2^32. @@ -155,7 +155,7 @@ const HASH_CONSTANTS: [(&str, [u8; 32]); 2] = [ ), ]; -const EC_CONSTANTS: [(&str, [u8; 32]); 20] = [ +const EC_CONSTANTS: [(&str, [u8; 32]); 24] = [ ( "U256_MAX", hex!("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), @@ -172,6 +172,22 @@ const EC_CONSTANTS: [(&str, [u8; 32]); 20] = [ "BN_TWISTED_IM", hex!("009713b03af0fed4cd2cafadeed8fdf4a74fa084e52d1852e4a2bd0685c315d2"), ), + ( + "BN_ENDO_X_COORD_RE", + hex!("2fb347984f7911f74c0bec3cf559b143b78cc310c2c3330c99e39557176f553d"), + ), + ( + "BN_ENDO_X_COORD_IM", + hex!("16c9e55061ebae204ba4cc8bd75a079432ae2a1d0b7c9dce1665d51c640fcba2"), + ), + ( + "BN_ENDO_Y_COORD_RE", + hex!("063cf305489af5dcdc5ec698b6e2f9b9dbaae0eda9c95998dc54014671a0135a"), + ), + ( + "BN_ENDO_Y_COORD_IM", + hex!("07c03cbcac41049a0704b5a7ec796f2b21807dc98fa25bd282d37f632623b0e3"), + ), ( "BN_SCALAR", hex!("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001"), diff --git a/evm_arithmetization/src/cpu/kernel/tests/bn254.rs b/evm_arithmetization/src/cpu/kernel/tests/bn254.rs index 67052bedb..a253fa815 100644 --- a/evm_arithmetization/src/cpu/kernel/tests/bn254.rs +++ b/evm_arithmetization/src/cpu/kernel/tests/bn254.rs @@ -1,16 +1,19 @@ use anyhow::Result; +use env_logger::{try_init_from_env, Env, DEFAULT_FILTER_ENV}; use ethereum_types::U256; +use hex_literal::hex; use plonky2::field::goldilocks_field::GoldilocksField as F; use rand::Rng; use super::{run_interpreter_with_memory, InterpreterMemoryInitialization}; +use crate::cpu::kernel::aggregator::KERNEL; use crate::cpu::kernel::interpreter::Interpreter; use crate::curve_pairings::{ bn254::{final_exponent, miller_loop}, gen_fp12_sparse, CurveAff, CyclicGroup, }; use crate::extension_tower::{FieldExt, Fp12, Fp2, Fp6, Stack, BN254}; -use crate::memory::segments::Segment::BnPairing; +use crate::memory::segments::Segment::{self, BnPairing}; fn run_bn_mul_fp6(f: Fp6, g: Fp6, label: &str) -> Fp6 { let mut stack = f.to_stack(); @@ -251,3 +254,98 @@ fn test_bn_pairing() -> Result<()> { assert_eq!(interpreter.stack()[0], U256::one()); Ok(()) } + +fn run_bn_g2_op( + p: CurveAff>, + q: CurveAff>, + label: &str, +) -> CurveAff> { + let mut stack = p.to_stack(); + if label == "bn_twisted_add" { + stack.extend(&q.to_stack()); + } + stack.push(U256::from(0xdeadbeefu32)); + let setup = InterpreterMemoryInitialization { + label: label.to_string(), + stack, + segment: BnPairing, + memory: vec![], + }; + let interpreter = run_interpreter_with_memory::(setup).unwrap(); + let output: Vec = interpreter.stack().iter().rev().cloned().collect(); + CurveAff::>::from_stack(&output) +} + +#[test] +fn test_bn_g2_ops() -> Result<()> { + let mut rng = rand::thread_rng(); + let p: CurveAff> = rng.gen::>>(); + let q: CurveAff> = rng.gen::>>(); + + let output_add: CurveAff> = run_bn_g2_op(p, q, "bn_twisted_add"); + let output_double: CurveAff> = run_bn_g2_op(p, p, "bn_twisted_double"); + + assert_eq!(output_add, p + q); + assert_eq!(output_double, p + p); + + let unit = CurveAff::>::unit(); + let output_add_unit: CurveAff> = run_bn_g2_op(unit, unit, "bn_twisted_add"); + let output_double_unit: CurveAff> = run_bn_g2_op(unit, unit, "bn_twisted_double"); + + assert_eq!(unit, output_add_unit); + assert_eq!(unit, output_double_unit); + + let output_add_with_unit_left: CurveAff> = run_bn_g2_op(unit, p, "bn_twisted_add"); + let output_add_with_unit_right: CurveAff> = run_bn_g2_op(p, unit, "bn_twisted_add"); + + assert_eq!(p, output_add_with_unit_left); + assert_eq!(p, output_add_with_unit_right); + + Ok(()) +} + +/// Test cases taken from . +const ECPAIRING_PRECOMPILE_INVALID_INPUTS: [[u8; 192]; 4] = [ + // invalid_g1_point + hex!("30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa"), + // invalid_g2_point + hex!("000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffff0000000000000000ffffffffffffffffffff"), + // invalid_g2_subgroup + hex!("000000000000000000000000000000000000000000000000000000000000000130644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4530644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd4500000000000000000000000000000000000000000000000000000000000000020833e47a2eaa8bbe12d33b2da1a4fa8d763f5c567fe0da6c5c9da2e246f2096f28dc125bf7443bc1826c69fe4c7bf30c26ec60882350e784c4848c822726eb43"), + // invalid_g2_subgroup + hex!("111f95e1632a3624dd29bbc012e6462b7836eb9c80e281b9381e103aebe632372b38b76d492b3af692eb99d03cd8dcfd8a8c3a6e4a161037c42f542af5564c41198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c21a76dae6d3272396d0cbe61fced2bc532edac647851e3ac53ce1cc9c7e645a8305b993046905746641a19b500ebbbd30cf0068a845bfbee9de55b8fe57d1dee8243ef33537f73ef4ace4279d86344d93a5dc8c20c69045865c0fa3b924933879"), +]; + +#[test] +fn test_ecpairing_precompile_invalid_input() -> Result<()> { + init_logger(); + + let pairing_label = KERNEL.global_labels["bn254_pairing"]; + let mut stack = vec![1.into(), 0.into(), 100.into(), U256::from(0xdeadbeefu32)]; // k, inp, out, retdest + stack.reverse(); + + for bytes in ECPAIRING_PRECOMPILE_INVALID_INPUTS.iter() { + let mut interpreter: Interpreter = Interpreter::new(pairing_label, stack.clone()); + let preloaded_memory = vec![ + U256::from_big_endian(&bytes[0..32]), // Px + U256::from_big_endian(&bytes[32..64]), // Py + U256::from_big_endian(&bytes[64..96]), // Qx_re + U256::from_big_endian(&bytes[96..128]), // Qx_im + U256::from_big_endian(&bytes[128..160]), // Qy_re + U256::from_big_endian(&bytes[160..192]), // Qy_im + ]; + interpreter.set_memory_segment(Segment::BnPairing, preloaded_memory); + interpreter.run().unwrap(); + + let post_stack = interpreter.stack(); + assert!(post_stack.len() == 1); + + assert_eq!(post_stack[0], U256::MAX); // invalid inputs + } + + Ok(()) +} + +fn init_logger() { + let _ = try_init_from_env(Env::default().filter_or(DEFAULT_FILTER_ENV, "debug")); +} diff --git a/evm_arithmetization/src/extension_tower.rs b/evm_arithmetization/src/extension_tower.rs index 686be2dde..3638c8c74 100644 --- a/evm_arithmetization/src/extension_tower.rs +++ b/evm_arithmetization/src/extension_tower.rs @@ -429,7 +429,7 @@ impl Fp2 { /// z -> z^p /// since p == 3 mod 4 and hence /// i^p = i^(4k) * i^3 = 1*(-i) = -i - fn conj(self) -> Self { + pub(crate) fn conj(self) -> Self { Fp2 { re: self.re, im: -self.im, diff --git a/evm_arithmetization/src/memory/segments.rs b/evm_arithmetization/src/memory/segments.rs index 896d5571f..8c687ea93 100644 --- a/evm_arithmetization/src/memory/segments.rs +++ b/evm_arithmetization/src/memory/segments.rs @@ -26,63 +26,61 @@ pub(crate) enum Segment { /// In general, calling a helper function can result in this memory being /// clobbered. KernelGeneral = 7 << SEGMENT_SCALING_FACTOR, - /// Another segment for general purpose kernel use. - KernelGeneral2 = 8 << SEGMENT_SCALING_FACTOR, /// Segment to hold account code for opcodes like `CODESIZE, CODECOPY,...`. - KernelAccountCode = 9 << SEGMENT_SCALING_FACTOR, + KernelAccountCode = 8 << SEGMENT_SCALING_FACTOR, /// Contains normalized transaction fields; see `NormalizedTxnField`. - TxnFields = 10 << SEGMENT_SCALING_FACTOR, + TxnFields = 9 << SEGMENT_SCALING_FACTOR, /// Contains the data field of a transaction. - TxnData = 11 << SEGMENT_SCALING_FACTOR, + TxnData = 10 << SEGMENT_SCALING_FACTOR, /// A buffer used to hold raw RLP data. - RlpRaw = 12 << SEGMENT_SCALING_FACTOR, + RlpRaw = 11 << SEGMENT_SCALING_FACTOR, /// Contains all trie data. It is owned by the kernel, so it only lives on /// context 0. - TrieData = 13 << SEGMENT_SCALING_FACTOR, - ShiftTable = 14 << SEGMENT_SCALING_FACTOR, - JumpdestBits = 15 << SEGMENT_SCALING_FACTOR, - EcdsaTable = 16 << SEGMENT_SCALING_FACTOR, - BnWnafA = 17 << SEGMENT_SCALING_FACTOR, - BnWnafB = 18 << SEGMENT_SCALING_FACTOR, - BnTableQ = 19 << SEGMENT_SCALING_FACTOR, - BnPairing = 20 << SEGMENT_SCALING_FACTOR, + TrieData = 12 << SEGMENT_SCALING_FACTOR, + ShiftTable = 13 << SEGMENT_SCALING_FACTOR, + JumpdestBits = 14 << SEGMENT_SCALING_FACTOR, + EcdsaTable = 15 << SEGMENT_SCALING_FACTOR, + BnWnafA = 16 << SEGMENT_SCALING_FACTOR, + BnWnafB = 17 << SEGMENT_SCALING_FACTOR, + BnTableQ = 18 << SEGMENT_SCALING_FACTOR, + BnPairing = 19 << SEGMENT_SCALING_FACTOR, /// List of addresses that have been accessed in the current transaction. - AccessedAddresses = 21 << SEGMENT_SCALING_FACTOR, + AccessedAddresses = 20 << SEGMENT_SCALING_FACTOR, /// List of storage keys that have been accessed in the current transaction. - AccessedStorageKeys = 22 << SEGMENT_SCALING_FACTOR, + AccessedStorageKeys = 21 << SEGMENT_SCALING_FACTOR, /// List of addresses that have called SELFDESTRUCT in the current /// transaction. - SelfDestructList = 23 << SEGMENT_SCALING_FACTOR, + SelfDestructList = 22 << SEGMENT_SCALING_FACTOR, /// Contains the bloom filter of a transaction. - TxnBloom = 24 << SEGMENT_SCALING_FACTOR, + TxnBloom = 23 << SEGMENT_SCALING_FACTOR, /// Contains the bloom filter present in the block header. - GlobalBlockBloom = 25 << SEGMENT_SCALING_FACTOR, + GlobalBlockBloom = 24 << SEGMENT_SCALING_FACTOR, /// List of log pointers pointing to the LogsData segment. - Logs = 26 << SEGMENT_SCALING_FACTOR, - LogsData = 27 << SEGMENT_SCALING_FACTOR, + Logs = 25 << SEGMENT_SCALING_FACTOR, + LogsData = 26 << SEGMENT_SCALING_FACTOR, /// Journal of state changes. List of pointers to `JournalData`. Length in /// `GlobalMetadata`. - Journal = 28 << SEGMENT_SCALING_FACTOR, - JournalData = 29 << SEGMENT_SCALING_FACTOR, - JournalCheckpoints = 30 << SEGMENT_SCALING_FACTOR, + Journal = 27 << SEGMENT_SCALING_FACTOR, + JournalData = 28 << SEGMENT_SCALING_FACTOR, + JournalCheckpoints = 29 << SEGMENT_SCALING_FACTOR, /// List of addresses that have been touched in the current transaction. - TouchedAddresses = 31 << SEGMENT_SCALING_FACTOR, + TouchedAddresses = 30 << SEGMENT_SCALING_FACTOR, /// List of checkpoints for the current context. Length in /// `ContextMetadata`. - ContextCheckpoints = 32 << SEGMENT_SCALING_FACTOR, + ContextCheckpoints = 31 << SEGMENT_SCALING_FACTOR, /// List of 256 previous block hashes. - BlockHashes = 33 << SEGMENT_SCALING_FACTOR, + BlockHashes = 32 << SEGMENT_SCALING_FACTOR, // The transient storage of the current transaction. - TransientStorage = 34 << SEGMENT_SCALING_FACTOR, + TransientStorage = 33 << SEGMENT_SCALING_FACTOR, /// List of contracts which have been created during the current /// transaction. - CreatedContracts = 35 << SEGMENT_SCALING_FACTOR, + CreatedContracts = 34 << SEGMENT_SCALING_FACTOR, /// Blob versioned hashes specified in a type-3 transaction. - TxnBlobVersionedHashes = 36 << SEGMENT_SCALING_FACTOR, + TxnBlobVersionedHashes = 35 << SEGMENT_SCALING_FACTOR, } impl Segment { - pub(crate) const COUNT: usize = 37; + pub(crate) const COUNT: usize = 36; /// Unscales this segment by `SEGMENT_SCALING_FACTOR`. pub(crate) const fn unscale(&self) -> usize { @@ -99,7 +97,6 @@ impl Segment { Self::GlobalMetadata, Self::ContextMetadata, Self::KernelGeneral, - Self::KernelGeneral2, Self::KernelAccountCode, Self::TxnFields, Self::TxnData, @@ -142,7 +139,6 @@ impl Segment { Segment::GlobalMetadata => "SEGMENT_GLOBAL_METADATA", Segment::ContextMetadata => "SEGMENT_CONTEXT_METADATA", Segment::KernelGeneral => "SEGMENT_KERNEL_GENERAL", - Segment::KernelGeneral2 => "SEGMENT_KERNEL_GENERAL_2", Segment::KernelAccountCode => "SEGMENT_KERNEL_ACCOUNT_CODE", Segment::TxnFields => "SEGMENT_NORMALIZED_TXN", Segment::TxnData => "SEGMENT_TXN_DATA", @@ -184,7 +180,6 @@ impl Segment { Segment::GlobalMetadata => 256, Segment::ContextMetadata => 256, Segment::KernelGeneral => 256, - Segment::KernelGeneral2 => 256, Segment::KernelAccountCode => 8, Segment::TxnFields => 256, Segment::TxnData => 8, diff --git a/mpt_trie/src/debug_tools/common.rs b/mpt_trie/src/debug_tools/common.rs deleted file mode 100644 index cb38d5c47..000000000 --- a/mpt_trie/src/debug_tools/common.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Common utilities for the debugging tools. -use crate::{ - nibbles::Nibbles, - partial_trie::{Node, PartialTrie}, -}; - -/// Get the key piece from the given node if applicable. -/// -/// Note that there is no specific [`Nibble`] associated with a branch like -/// there are [`Nibbles`] with [Extension][`Node::Extension`] and -/// [Leaf][`Node::Leaf`] nodes, and the only way to get the `Nibble` -/// "associated" with a branch is to look at the next `Nibble` in the current -/// key as we traverse down it. -pub(super) fn get_key_piece_from_node_pulling_from_key_for_branches( - n: &Node, - curr_key: &Nibbles, -) -> Nibbles { - match n { - Node::Empty | Node::Hash(_) => Nibbles::default(), - Node::Branch { .. } => curr_key.get_next_nibbles(1), - Node::Extension { nibbles, child: _ } | Node::Leaf { nibbles, value: _ } => *nibbles, - } -} - -/// Get the key piece from the given node if applicable. Note that -/// [branch][`Node::Branch`]s have no [`Nibble`] directly associated with them. -pub(super) fn get_key_piece_from_node(n: &Node) -> Nibbles { - match n { - Node::Empty | Node::Hash(_) | Node::Branch { .. } => Nibbles::default(), - Node::Extension { nibbles, child: _ } | Node::Leaf { nibbles, value: _ } => *nibbles, - } -} diff --git a/mpt_trie/src/debug_tools/diff.rs b/mpt_trie/src/debug_tools/diff.rs index 6ceec00a1..c6a8458db 100644 --- a/mpt_trie/src/debug_tools/diff.rs +++ b/mpt_trie/src/debug_tools/diff.rs @@ -30,7 +30,6 @@ use std::{fmt::Display, ops::Deref}; use ethereum_types::H256; -use super::common::get_key_piece_from_node; use crate::utils::{get_segment_from_node_and_key_piece, TriePath}; use crate::{ nibbles::Nibbles, @@ -38,6 +37,15 @@ use crate::{ utils::TrieNodeType, }; +/// Get the key piece from the given node if applicable. Note that +/// [branch][`Node::Branch`]s have no [`Nibble`] directly associated with them. +fn get_key_piece_from_node(n: &Node) -> Nibbles { + match n { + Node::Empty | Node::Hash(_) | Node::Branch { .. } => Nibbles::default(), + Node::Extension { nibbles, child: _ } | Node::Leaf { nibbles, value: _ } => *nibbles, + } +} + #[derive(Debug, Eq, PartialEq)] /// The difference between two Tries, represented as the highest /// point of a structural divergence. diff --git a/mpt_trie/src/debug_tools/mod.rs b/mpt_trie/src/debug_tools/mod.rs index 8e25c6ae2..32a4fc985 100644 --- a/mpt_trie/src/debug_tools/mod.rs +++ b/mpt_trie/src/debug_tools/mod.rs @@ -1,7 +1,6 @@ //! Additional methods that may be useful when diagnosing tries from this //! library. -pub mod common; pub mod diff; pub mod query; pub mod stats; diff --git a/mpt_trie/src/debug_tools/query.rs b/mpt_trie/src/debug_tools/query.rs index c531dd4e8..753900262 100644 --- a/mpt_trie/src/debug_tools/query.rs +++ b/mpt_trie/src/debug_tools/query.rs @@ -5,13 +5,30 @@ use std::fmt::{self, Display}; use ethereum_types::H256; -use super::common::get_key_piece_from_node_pulling_from_key_for_branches; use crate::{ nibbles::Nibbles, partial_trie::{Node, PartialTrie, WrappedNode}, utils::{get_segment_from_node_and_key_piece, TriePath, TrieSegment}, }; +/// Get the key piece from the given node if applicable. +/// +/// Note that there is no specific [`Nibble`](crate::nibbles::Nibble) associated +/// with a branch like there are [`Nibbles`] with [Extension][`Node::Extension`] +/// and [Leaf][`Node::Leaf`] nodes, and the only way to get the `Nibble` +/// "associated" with a branch is to look at the next `Nibble` in the current +/// key as we traverse down it. +fn get_key_piece_from_node_pulling_from_key_for_branches( + n: &Node, + curr_key: &Nibbles, +) -> Nibbles { + match n { + Node::Empty | Node::Hash(_) => Nibbles::default(), + Node::Branch { .. } => curr_key.get_next_nibbles(1), + Node::Extension { nibbles, child: _ } | Node::Leaf { nibbles, value: _ } => *nibbles, + } +} + /// Params controlling how much information is reported in the query output. /// /// By default, the node type along with its key piece is printed out per node diff --git a/mpt_trie/src/nibbles.rs b/mpt_trie/src/nibbles.rs index e388cb78e..a417dca4e 100644 --- a/mpt_trie/src/nibbles.rs +++ b/mpt_trie/src/nibbles.rs @@ -72,7 +72,7 @@ pub trait ToNibbles { } } -#[derive(Debug, Error)] +#[derive(Clone, Debug, Error)] /// Errors encountered when converting from `Bytes` to `Nibbles`. pub enum BytesToNibblesError { #[error("Tried constructing `Nibbles` from a zero byte slice")] @@ -97,7 +97,7 @@ pub enum FromHexPrefixError { } /// Error type for conversion. -#[derive(Debug, Error)] +#[derive(Clone, Debug, Error)] pub enum NibblesToTypeError { #[error("Overflow encountered when converting to U256: {0}")] /// Overflow encountered. diff --git a/mpt_trie/src/partial_trie.rs b/mpt_trie/src/partial_trie.rs index a593f57c8..f03f3d2fa 100644 --- a/mpt_trie/src/partial_trie.rs +++ b/mpt_trie/src/partial_trie.rs @@ -44,15 +44,7 @@ impl From> for WrappedNode { /// A trait for any types that are Tries. pub trait PartialTrie: - Clone - + Debug - + Default - + Deref> - + DerefMut> - + Eq - + PartialEq - + TrieNodeIntern - + Sized + Clone + Debug + Default + DerefMut> + Eq + TrieNodeIntern { /// Creates a new partial trie from a node. fn new(n: Node) -> Self; diff --git a/mpt_trie/src/trie_ops.rs b/mpt_trie/src/trie_ops.rs index 2f0e794d7..5f94fc942 100644 --- a/mpt_trie/src/trie_ops.rs +++ b/mpt_trie/src/trie_ops.rs @@ -1,5 +1,5 @@ //! Defines various operations for -//! [`PartialTrie`][crate::partial_trie::PartialTrie]. +//! [`PartialTrie`]. use std::{fmt::Display, mem::size_of}; @@ -19,7 +19,7 @@ use crate::{ pub type TrieOpResult = Result; /// An error type for trie operation. -#[derive(Debug, Error)] +#[derive(Clone, Debug, Error)] pub enum TrieOpError { /// An error that occurs when a hash node is found during an insert /// operation. diff --git a/trace_decoder/src/compact/compact_prestate_processing.rs b/trace_decoder/src/compact/compact_prestate_processing.rs index 84e821b8e..397be5b12 100644 --- a/trace_decoder/src/compact/compact_prestate_processing.rs +++ b/trace_decoder/src/compact/compact_prestate_processing.rs @@ -123,8 +123,8 @@ pub enum CompactParsingError { KeyError(#[from] FromHexPrefixError), /// Failure due to an incompatible version. - #[error("Incompatible version, expected: {0}, actual: {1}")] - IncompatibleVersion(u8, u8), + #[error("Incompatible version, expected one of: {0:?}, actual: {1}")] + IncompatibleVersion(Vec, u8), /// Failure due to a trie operation error. #[error("Trie operation error: {0}")] diff --git a/trace_decoder/src/decoding.rs b/trace_decoder/src/decoding.rs index e5ac34a3c..1a81357a0 100644 --- a/trace_decoder/src/decoding.rs +++ b/trace_decoder/src/decoding.rs @@ -143,7 +143,7 @@ impl TraceParsingError { /// An error reason for trie parsing. #[derive(Debug, Error)] pub enum TraceParsingErrorReason { - /// Failure to decode an Ethereum [Account]. + /// Failure to decode an Ethereum Account. #[error("Failed to decode RLP bytes ({0}) as an Ethereum account due to the error: {1}")] AccountDecode(String, String), @@ -187,7 +187,7 @@ impl From for TraceParsingError { } } -/// An enum to cover all Ethereum trie types (see https://ethereum.github.io/yellowpaper/paper.pdf for details). +/// An enum to cover all Ethereum trie types (see for details). #[derive(Debug)] pub enum TrieType { /// State trie. diff --git a/trace_decoder/src/lib.rs b/trace_decoder/src/lib.rs index ff83fe4eb..f154bcd91 100644 --- a/trace_decoder/src/lib.rs +++ b/trace_decoder/src/lib.rs @@ -116,6 +116,12 @@ #![deny(missing_debug_implementations)] #![deny(missing_docs)] +#[cfg(doc)] +use { + trace_protocol::{BlockTrace, TxnInfo}, + types::OtherBlockData, +}; + /// Provides debugging tools and a compact representation of state and storage /// tries, used in tests. pub mod compact; diff --git a/trace_decoder/src/processed_block_trace.rs b/trace_decoder/src/processed_block_trace.rs index 7b697403c..c63057c39 100644 --- a/trace_decoder/src/processed_block_trace.rs +++ b/trace_decoder/src/processed_block_trace.rs @@ -33,7 +33,7 @@ pub(crate) struct ProcessedBlockTrace { pub(crate) withdrawals: Vec<(Address, U256)>, } -const COMPATIBLE_HEADER_VERSION: u8 = 1; +const COMPATIBLE_HEADER_VERSIONS: [u8; 2] = [0, 1]; impl BlockTrace { /// Processes and returns the [GenerationInputs] for all transactions in the @@ -80,9 +80,17 @@ impl BlockTrace { }) .collect(); + let code_db = { + let mut code_db = self.code_db.unwrap_or_default(); + if let Some(code_mappings) = pre_image_data.extra_code_hash_mappings { + code_db.extend(code_mappings); + } + code_db + }; + let mut code_hash_resolver = CodeHashResolving { client_code_hash_resolve_f: &p_meta.resolve_code_hash_fn, - extra_code_hash_mappings: pre_image_data.extra_code_hash_mappings.unwrap_or_default(), + extra_code_hash_mappings: code_db, }; let last_tx_idx = self.txn_info.len().saturating_sub(1); @@ -196,17 +204,26 @@ fn process_single_combined_storage_tries( } fn process_multiple_storage_tries( - _tries: HashMap, + tries: HashMap, ) -> HashMap { - todo!() + tries + .into_iter() + .map(|(k, v)| match v { + SeparateTriePreImage::Uncompressed(_) => todo!(), + SeparateTriePreImage::Direct(t) => (k, t.0), + }) + .collect() } fn process_compact_trie(trie: TrieCompact) -> CompactParsingResult { let out = process_compact_prestate_debug(trie)?; - if !out.header.version_is_compatible(COMPATIBLE_HEADER_VERSION) { + if !COMPATIBLE_HEADER_VERSIONS + .iter() + .any(|&v| out.header.version_is_compatible(v)) + { return Err(CompactParsingError::IncompatibleVersion( - COMPATIBLE_HEADER_VERSION, + COMPATIBLE_HEADER_VERSIONS.to_vec(), out.header.version, )); } diff --git a/trace_decoder/src/trace_protocol.rs b/trace_decoder/src/trace_protocol.rs index 1035c13b8..ca991e80f 100644 --- a/trace_decoder/src/trace_protocol.rs +++ b/trace_decoder/src/trace_protocol.rs @@ -42,6 +42,10 @@ pub struct BlockTrace { /// The trie pre-images (state & storage) in multiple possible formats. pub trie_pre_images: BlockTraceTriePreImages, + /// The code_db is a map of code hashes to the actual code. This is needed + /// to execute transactions. + pub code_db: Option>>, + /// Traces and other info per txn. The index of the txn corresponds to the /// slot in this vec. pub txn_info: Vec,