diff --git a/.cargo/config b/.cargo/config new file mode 100644 index 000000000..37971c663 --- /dev/null +++ b/.cargo/config @@ -0,0 +1,2 @@ +[target.riscv32imac-unknown-xous-elf] +rustflags = ["--cfg",'curve25519_dalek_backend="u32e_backend"'] diff --git a/.github/workflows/cross.yml b/.github/workflows/cross.yml new file mode 100644 index 000000000..40e89f40a --- /dev/null +++ b/.github/workflows/cross.yml @@ -0,0 +1,44 @@ +name: Cross + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ '**' ] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + +jobs: + + test-cross: + name: Test + strategy: + matrix: + include: + # ARM32 + - target: armv7-unknown-linux-gnueabihf + rust: stable + + # ARM64 + - target: aarch64-unknown-linux-gnu + rust: stable + + # PPC32 + - target: powerpc-unknown-linux-gnu + rust: stable + + # TODO: We only test x/ed/curve for cross as derive is platform specifics + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: ${{ matrix.deps }} + - uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ matrix.rust }} + targets: ${{ matrix.target }} + - uses: RustCrypto/actions/cross-install@master + - run: cross test -p curve25519-dalek --release --target ${{ matrix.target }} + - run: cross test -p ed25519-dalek --release --target ${{ matrix.target }} + - run: cross test -p x25519-dalek --release --target ${{ matrix.target }} diff --git a/.github/workflows/curve25519-dalek.yml b/.github/workflows/curve25519-dalek.yml new file mode 100644 index 000000000..1fb13aa3e --- /dev/null +++ b/.github/workflows/curve25519-dalek.yml @@ -0,0 +1,145 @@ +name: curve25519 Rust + +on: + push: + branches: [ '**' ] + paths: + - 'curve25519-dalek/**' + - '.github/workflows/curve25519-dalek.yml' + pull_request: + branches: [ '**' ] + paths: + - 'curve25519-dalek/**' + - '.github/workflows/curve25519-dalek.yml' + +defaults: + run: + working-directory: curve25519-dalek + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + +jobs: + + test-fiat: + name: Test fiat backend + runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + + # 64-bit target + - target: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' + run: cargo test --target ${{ matrix.target }} + + # Default no_std test only tests using serial across all crates + build-nostd-fiat: + name: Build fiat on no_std target (thumbv7em-none-eabi) + runs-on: ubuntu-latest + strategy: + matrix: + include: + - crate: curve25519-dalek + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - uses: taiki-e/install-action@cargo-hack + # No default features build + - name: no_std fiat / no feat ${{ matrix.crate }} + env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' + run: cargo build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --no-default-features + - name: no_std fiat / cargo hack ${{ matrix.crate }} + env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="fiat"' + run: cargo hack build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std,getrandom + + test-serial: + name: Test serial backend + runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + + # 64-bit target + - target: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - env: + RUSTFLAGS: '--cfg curve25519_dalek_backend="serial"' + run: cargo test --target ${{ matrix.target }} + + build-script: + name: Test Build Script + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: wasm32-unknown-unknown,x86_64-unknown-linux-gnu,i686-unknown-linux-gnu + - run: bash tests/build_tests.sh + + test-simd-nightly: + name: Test simd backend (nightly) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - env: + # This will: + # 1) build all of the x86_64 SIMD code, + # 2) run all of the SIMD-specific tests that the test runner supports, + # 3) run all of the normal tests using the best available SIMD backend. + # This should automatically pick up the simd backend in a x84_64 runner + RUSTFLAGS: '-C target_cpu=native' + run: cargo test --target x86_64-unknown-linux-gnu + + test-simd-stable: + name: Test simd backend (stable) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - env: + # This will run AVX2-specific tests and run all of the normal tests + # with the AVX2 backend, even if the runner supports AVX512. + # This should automatically pick up the simd backend in a x86_64 runner + # It should pick AVX2 due to stable toolchain used since AVX512 requires nigthly + RUSTFLAGS: '-C target_feature=+avx2' + run: cargo test --no-default-features --features alloc,precomputed-tables,zeroize,group-bits --target x86_64-unknown-linux-gnu + + msrv: + name: Current MSRV is 1.60.0 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + # Re-resolve Cargo.lock with minimal versions + - uses: dtolnay/rust-toolchain@nightly + - run: cargo update -Z minimal-versions + # Now check that `cargo build` works with respect to the oldest possible + # deps and the stated MSRV + - uses: dtolnay/rust-toolchain@1.60.0 + - run: cargo build --no-default-features --features serde + # Also make sure the AVX2 build works + - run: cargo build --target x86_64-unknown-linux-gnu diff --git a/.github/workflows/ed25519-dalek.yml b/.github/workflows/ed25519-dalek.yml new file mode 100644 index 000000000..a49d83450 --- /dev/null +++ b/.github/workflows/ed25519-dalek.yml @@ -0,0 +1,33 @@ +name: ed25519 Rust + +on: + push: + branches: [ '**' ] + paths: 'ed25519-dalek/**' + pull_request: + branches: [ '**' ] + paths: 'ed25519-dalek/**' + +defaults: + run: + working-directory: ed25519-dalek + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + RUSTDOCFLAGS: '-D warnings' + +jobs: + + msrv: + name: Current MSRV is 1.60.0 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + # Re-resolve Cargo.lock with minimal versions + - uses: dtolnay/rust-toolchain@nightly + - run: cargo update -Z minimal-versions + # Now check that `cargo build` works with respect to the oldest possible + # deps and the stated MSRV + - uses: dtolnay/rust-toolchain@1.60.0 + - run: cargo build diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml deleted file mode 100644 index 2214f4bc8..000000000 --- a/.github/workflows/rust.yml +++ /dev/null @@ -1,131 +0,0 @@ -name: Rust - -on: - push: - branches: [ '*' ] - pull_request: - branches: [ main, develop ] - -env: - CARGO_TERM_COLOR: always - -jobs: - test-u32: - name: Test u32 backend - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u32_backend" - - test-u64: - name: Test u64 backend - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std u64_backend" - - test-simd: - name: Test simd backend (nightly) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --no-default-features --features "std simd_backend" - - test-defaults-serde: - name: Test default feature selection and serde - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "serde" - - test-alloc-u32: - name: Test no_std+alloc with u32 backend - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --lib --no-default-features --features "alloc u32_backend" - - nightly: - name: Test nightly compiler - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: nightly - override: true - - uses: actions-rs/cargo@v1 - with: - command: test - args: --features "nightly" - - msrv: - name: Current MSRV is 1.41 - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: 1.41 - override: true - - uses: actions-rs/cargo@v1 - with: - command: build - - bench: - name: Check that benchmarks compile - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - uses: actions-rs/toolchain@v1 - with: - profile: minimal - toolchain: stable - override: true - - uses: actions-rs/cargo@v1 - with: - command: bench - # This filter selects no benchmarks, so we don't run any, only build them. - args: "DONTRUNBENCHMARKS" diff --git a/.github/workflows/workspace.yml b/.github/workflows/workspace.yml new file mode 100644 index 000000000..b8e44dc50 --- /dev/null +++ b/.github/workflows/workspace.yml @@ -0,0 +1,111 @@ +name: All + +on: + push: + branches: [ '**' ] + pull_request: + branches: [ '**' ] + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + +jobs: + test-stable: + name: Test 32/64 bit stable + runs-on: ubuntu-latest + strategy: + matrix: + include: + # 32-bit target + - target: i686-unknown-linux-gnu + deps: sudo apt update && sudo apt install gcc-multilib + + # 64-bit target + - target: x86_64-unknown-linux-gnu + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - run: rustup target add ${{ matrix.target }} + - run: ${{ matrix.deps }} + - run: cargo test --target ${{ matrix.target }} --no-default-features + - run: cargo test --target ${{ matrix.target }} + - run: cargo test --target ${{ matrix.target }} --all-features + + test-nightly: + name: Test Nightly + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@nightly + - run: cargo test + + bench: + name: Check that benchmarks compile + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + - name: Build u32 bench + env: + RUSTFLAGS: '--cfg curve25519_dalek_bits="32"' + run: cargo build --benches + - name: Build u64 bench + env: + RUSTFLAGS: '--cfg curve25519_dalek_bits="64"' + run: cargo build --benches + - name: Build default (host native) bench + run: cargo build --benches + + # Test no_std with serial (default) + build-nostd-serial: + name: Build serial on no_std target (thumbv7em-none-eabi) + runs-on: ubuntu-latest + strategy: + matrix: + include: + - crate: curve25519-dalek + - crate: ed25519-dalek + - crate: x25519-dalek + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + targets: thumbv7em-none-eabi + - uses: taiki-e/install-action@cargo-hack + # No default features build + - name: no_std / no feat ${{ matrix.crate }} + run: cargo build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --no-default-features + - name: no_std / cargo hack ${{ matrix.crate }} + run: cargo hack build -p ${{ matrix.crate }} --target thumbv7em-none-eabi --release --each-feature --exclude-features default,std,getrandom + + clippy: + name: Check that clippy is happy + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@1.73.0 + with: + components: clippy + - run: cargo clippy --target x86_64-unknown-linux-gnu --all-features + + rustfmt: + name: Check formatting + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + components: rustfmt + - run: cargo fmt --all -- --check + + doc: + name: Check docs + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: dtolnay/rust-toolchain@stable + with: + toolchain: stable + - run: cargo doc --all-features diff --git a/.github/workflows/x25519-dalek.yml b/.github/workflows/x25519-dalek.yml new file mode 100644 index 000000000..0ece0dcd1 --- /dev/null +++ b/.github/workflows/x25519-dalek.yml @@ -0,0 +1,33 @@ +name: x25519 Rust + +on: + push: + branches: [ '**' ] + paths: 'x25519-dalek/**' + pull_request: + branches: [ '**' ] + paths: 'x25519-dalek/**' + +defaults: + run: + working-directory: x25519-dalek + +env: + CARGO_TERM_COLOR: always + RUSTFLAGS: '-D warnings' + RUSTDOCFLAGS: '-D warnings' + +jobs: + + msrv: + name: Current MSRV is 1.60.0 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + # Re-resolve Cargo.lock with minimal versions + - uses: dtolnay/rust-toolchain@nightly + - run: cargo update -Z minimal-versions + # Now check that `cargo build` works with respect to the oldest possible + # deps and the stated MSRV + - uses: dtolnay/rust-toolchain@1.60.0 + - run: cargo build diff --git a/.gitignore b/.gitignore index 0fde7ec54..1950608da 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ +*/target/* target Cargo.lock - +*/Cargo.lock +build*.txt *~ \#* .\#* diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index f2411e005..000000000 --- a/.travis.yml +++ /dev/null @@ -1,41 +0,0 @@ -language: rust - -rust: - - stable - - nightly - -env: - # Tests the u32 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u32_backend' - # Tests the u64 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' - # Tests the fiat_u32 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u32_backend' - # Tests the fiat_u64 backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std fiat_u64_backend' - # Tests the simd backend - - TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend' - # Tests serde support and default feature selection - - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde' - # Tests building without std. We have to select a backend, so we select the one - # most likely to be useful in an embedded environment. - - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend' - # Tests no_std+alloc usage using the most embedded-friendly backend - - TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend' - -matrix: - exclude: - # Test the simd backend only on nightly - - rust: stable - env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std simd_backend' - # Test no_std+alloc only on nightly - - rust: stable - env: TEST_COMMAND=test EXTRA_FLAGS='--lib --no-default-features' FEATURES='alloc u32_backend' - -script: - - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS - -notifications: - slack: - rooms: - - dalek-cryptography:Xxv9WotKYWdSoKlgKNqXiHoD#dalek-bots diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md deleted file mode 100644 index a802fde53..000000000 --- a/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,8 +0,0 @@ -# Code of Conduct - -We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html), -with the following additional clauses: - -* We respect the rights to privacy and anonymity for contributors and people in - the community. If someone wishes to contribute under a pseudonym different to - their primary identity, that wish is to be respected by all contributors. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d4e0ff8e5..243e927f2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,7 +12,7 @@ Patches are welcomed as pull requests on email (preferably sent to all of the authors listed in `Cargo.toml`). All issues on curve25519-dalek are mentored, if you want help with a bug just -ask @isislovecruft or @hdevalence. +ask @rozbb or @tarcieri. Some issues are easier than others. The `easy` label can be used to find the easy issues. If you want to work on an issue, please leave a comment so that we diff --git a/Cargo.toml b/Cargo.toml index e73d382d4..dcd2bbc48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,103 +1,21 @@ -[package] -name = "curve25519-dalek" -# Before incrementing: -# - update CHANGELOG -# - update html_root_url -# - update README if required by semver -# - if README was updated, also update module documentation in src/lib.rs -version = "3.2.1" -authors = ["Isis Lovecruft ", - "Henry de Valence "] -readme = "README.md" -license = "BSD-3-Clause" -repository = "https://github.com/dalek-cryptography/curve25519-dalek" -homepage = "https://dalek.rs/curve25519-dalek" -documentation = "https://docs.rs/curve25519-dalek" -categories = ["cryptography", "no-std"] -keywords = ["cryptography", "crypto", "ristretto", "curve25519", "ristretto255"] -description = "A pure-Rust implementation of group operations on ristretto255 and Curve25519" -exclude = ["**/.gitignore", ".gitignore", ".travis.yml"] - -[package.metadata.docs.rs] -# Disabled for now since this is borked; tracking https://github.com/rust-lang/docs.rs/issues/302 -# rustdoc-args = ["--html-in-header", ".cargo/registry/src/github.com-1ecc6299db9ec823/curve25519-dalek-0.13.2/rustdoc-include-katex-header.html"] -features = ["nightly", "simd_backend"] - -[badges] -travis-ci = { repository = "dalek-cryptography/curve25519-dalek", branch = "master" } - -[dev-dependencies] -sha2 = { version = "0.9", default-features = false } -bincode = "1" -criterion = { version = "0.3.0", features = ["html_reports"] } -hex = "0.4.2" -rand = "0.7" - -[[bench]] -name = "dalek_benchmarks" -harness = false - -[dependencies] -rand_core = { version = "0.5", default-features = false } -byteorder = { version = "^1.2.3", default-features = false, features = [ - "i128", -] } -digest = { version = "0.9", default-features = false } -subtle = { version = "^2.2.1", default-features = false } -serde = { version = "1.0", default-features = false, optional = true, features = [ - "derive", -] } -# The original packed_simd package was orphaned, see -# https://github.com/rust-lang/packed_simd/issues/303#issuecomment-701361161 -packed_simd = { version = "0.3.4", package = "packed_simd_2", features = ["into_bits"], optional = true } -zeroize = { version = ">=1, <1.4", default-features = false } -fiat-crypto = { version = "0.1.6", optional = true} - -# Betrusted/Precursor dependency set -log = { version = "0.4", optional = true } -[dependencies.engine-25519] -git = "https://github.com/betrusted-io/xous-engine-25519.git" -rev = "63d3d1f30736022e791deaacf4dd62c00b42fe2e" -optional = true - -[dependencies.utralib] -version = "0.1.0" # this is bogus -- must be patched in the invoking build environment -#path="../betrusted-soc/boot/utralib/" -optional = true - -[dependencies.engine25519-as] -git = "https://github.com/betrusted-io/engine25519-as.git" -rev = "d249c967556b02ab5439eacb5078fa00c60b93d6" -default-features = false -features = [] -optional = true - -[dev-dependencies.engine25519-as] -git = "https://github.com/betrusted-io/engine25519-as.git" -rev = "d249c967556b02ab5439eacb5078fa00c60b93d6" - -[features] -nightly = ["subtle/nightly"] -default = ["std", "u32_backend"] -std = ["alloc", "subtle/std", "rand_core/std"] -alloc = ["zeroize/alloc"] - -# The u32 backend uses u32s with u64 products. -u32_backend = [] -# The u32e backend uses u32s with u64 products + field25519 accelerator. -u32e_backend = ["engine25519-as", "utralib"] -# The u64 backend uses u64s with u128 products. -u64_backend = [] -# fiat-u64 backend (with formally-verified field arith) uses u64s with u128 products. -fiat_u64_backend = ["fiat-crypto"] -# fiat-u32 backend (with formally-verified field arith) uses u32s with u64 products. -fiat_u32_backend = ["fiat-crypto"] -# The SIMD backend uses parallel formulas, using either AVX2 or AVX512-IFMA. -simd_backend = ["nightly", "u64_backend", "packed_simd"] -# DEPRECATED: this is now an alias for `simd_backend` and may be removed -# in some future release. -avx2_backend = ["simd_backend"] -# the betrusted backend uses the curve25519 hardware accelerator in betrusted-soc -betrusted = ["engine-25519", "engine25519-as", "log"] - [workspace] +members = [ + "curve25519-dalek", + "curve25519-dalek-derive", + "ed25519-dalek", + "x25519-dalek" +] +resolver = "2" + +[profile.dev] + +opt-level = 2 + +[patch.crates-io.getrandom] +path = "../xous-core/imports/getrandom" + +# Until they release 0.5.2, we need to use master due to is-terminal +[patch.crates-io.criterion] +git = "https://github.com/bheisler/criterion.rs" +rev = "b913e232edd98780961ecfbae836ec77ede49259" +features = ["html_reports"] diff --git a/Makefile b/Makefile deleted file mode 100644 index 7d870571f..000000000 --- a/Makefile +++ /dev/null @@ -1,8 +0,0 @@ -FEATURES := nightly simd_backend - -doc: - cargo rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html - -doc-internal: - cargo rustdoc --features "$(FEATURES)" -- --html-in-header docs/assets/rustdoc-include-katex-header.html --document-private-items - diff --git a/README.md b/README.md index acad0f9b7..aced37391 100644 --- a/README.md +++ b/README.md @@ -1,226 +1,31 @@ - -# curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/badge/dynamic/json.svg?label=docs&uri=https%3A%2F%2Fcrates.io%2Fapi%2Fv1%2Fcrates%2Fcurve25519-dalek%2Fversions&query=%24.versions%5B0%5D.num&colorB=4F74A6)](https://doc.dalek.rs) [![](https://travis-ci.org/dalek-cryptography/curve25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/curve25519-dalek) - +

- -**A pure-Rust implementation of group operations on Ristretto and Curve25519.** - -`curve25519-dalek` is a library providing group operations on the Edwards and -Montgomery forms of Curve25519, and on the prime-order Ristretto group. - -`curve25519-dalek` is not intended to provide implementations of any particular -crypto protocol. Rather, implementations of those protocols (such as -[`x25519-dalek`][x25519-dalek] and [`ed25519-dalek`][ed25519-dalek]) should use -`curve25519-dalek` as a library. - -`curve25519-dalek` is intended to provide a clean and safe _mid-level_ API for use -implementing a wide range of ECC-based crypto protocols, such as key agreement, -signatures, anonymous credentials, rangeproofs, and zero-knowledge proof -systems. - -In particular, `curve25519-dalek` implements Ristretto, which constructs a -prime-order group from a non-prime-order Edwards curve. This provides the -speed and safety benefits of Edwards curve arithmetic, without the pitfalls of -cofactor-related abstraction mismatches. - -# Documentation - -The semver-stable, public-facing `curve25519-dalek` API is documented -[here][docs-external]. In addition, the unstable internal implementation -details are documented [here][docs-internal]. - -The `curve25519-dalek` documentation requires a custom HTML header to include -KaTeX for math support. Unfortunately `cargo doc` does not currently support -this, but docs can be built using -```sh -make doc -make doc-internal -``` - -# Use - -To import `curve25519-dalek`, add the following to the dependencies section of -your project's `Cargo.toml`: -```toml -curve25519-dalek = "3" -``` - -The sole breaking change in the `3.x` series was an update to the `digest` -version, and in terms of non-breaking changes it includes: - -* support for using `alloc` instead of `std` on stable Rust, -* the Elligator2 encoding for Edwards points, -* a fix to use `packed_simd2`, -* various documentation fixes and improvements, -* support for configurably-sized, precomputed lookup tables for basepoint scalar - multiplication, -* two new formally-verified field arithmetic backends which use the Fiat Crypto - Rust code, which is generated from proofs of functional correctness checked by - the Coq theorem proving system, and -* support for explicitly calling the `zeroize` traits for all point types. - -The `2.x` series has API almost entirely unchanged from the `1.x` series, -except that: - -* an error in the data modeling for the (optional) `serde` feature was - corrected, so that when the `2.x`-series `serde` implementation is used - with `serde-bincode`, the derived serialization matches the usual X/Ed25519 - formats; -* the `rand` version was updated. - -See `CHANGELOG.md` for more details. - -# Backends and Features - -The `nightly` feature enables features available only when using a Rust nightly -compiler. In particular, it is required for rendering documentation and for -the SIMD backends. - -Curve arithmetic is implemented using one of the following backends: + alt="dalek-cryptography logo: a dalek with edwards curves as sparkles coming out of its radar-schnozzley blaster thingies" + width="200px" + src="https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png"/> +

-* a `u32` backend using serial formulas and `u64` products; -* a `u64` backend using serial formulas and `u128` products; -* an `avx2` backend using [parallel formulas][parallel_doc] and `avx2` instructions (sets speed records); -* an `ifma` backend using [parallel formulas][parallel_doc] and `ifma` instructions (sets speed records); +# Dalek elliptic curve cryptography -By default the `u64` backend is selected. To select a specific backend, use: -```sh -cargo build --no-default-features --features "std u32_backend" -cargo build --no-default-features --features "std u64_backend" -# Requires nightly, RUSTFLAGS="-C target_feature=+avx2" to use avx2 -cargo build --no-default-features --features "std simd_backend" -# Requires nightly, RUSTFLAGS="-C target_feature=+avx512ifma" to use ifma -cargo build --no-default-features --features "std simd_backend" -``` -Crates using `curve25519-dalek` can either select a backend on behalf of their -users, or expose feature flags that control the `curve25519-dalek` backend. +This repo contains pure-Rust crates for elliptic curve cryptography: -The `std` feature is enabled by default, but it can be disabled for no-`std` -builds using `--no-default-features`. Note that this requires explicitly -selecting an arithmetic backend using one of the `_backend` features. -If no backend is selected, compilation will fail. +| Crate | Description | Crates.io | Docs | CI | +-------------------------------------------|----------------|-----------|------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +| [`curve25519‑dalek`](./curve25519-dalek) | A library for arithmetic over the Curve25519 and Ristretto elliptic curves and their associated scalars. | [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) | [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) | +| [`ed25519‑dalek`](./ed25519-dalek) | An implementation of the EdDSA digital signature scheme over Curve25519. | [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) | [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml) | +| [`x25519‑dalek`](./x25519-dalek) | An implementation of elliptic curve Diffie-Hellman key exchange over Curve25519. | [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) | [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) | [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml) | -# Safety - -The `curve25519-dalek` types are designed to make illegal states -unrepresentable. For example, any instance of an `EdwardsPoint` is -guaranteed to hold a point on the Edwards curve, and any instance of a -`RistrettoPoint` is guaranteed to hold a valid point in the Ristretto -group. - -All operations are implemented using constant-time logic (no -secret-dependent branches, no secret-dependent memory accesses), -unless specifically marked as being variable-time code. -We believe that our constant-time logic is lowered to constant-time -assembly, at least on `x86_64` targets. - -As an additional guard against possible future compiler optimizations, -the `subtle` crate places an optimization barrier before every -conditional move or assignment. More details can be found in [the -documentation for the `subtle` crate][subtle_doc]. - -Some functionality (e.g., multiscalar multiplication or batch -inversion) requires heap allocation for temporary buffers. All -heap-allocated buffers of potentially secret data are explicitly -zeroed before release. - -However, we do not attempt to zero stack data, for two reasons. -First, it's not possible to do so correctly: we don't have control -over stack allocations, so there's no way to know how much data to -wipe. Second, because `curve25519-dalek` provides a mid-level API, -the correct place to start zeroing stack data is likely not at the -entrypoints of `curve25519-dalek` functions, but at the entrypoints of -functions in other crates. - -The implementation is memory-safe, and contains no significant -`unsafe` code. The SIMD backend uses `unsafe` internally to call SIMD -intrinsics. These are marked `unsafe` only because invoking them on an -inappropriate CPU would cause `SIGILL`, but the entire backend is only -compiled with appropriate `target_feature`s, so this cannot occur. - -# Performance - -Benchmarks are run using [`criterion.rs`][criterion]: - -```sh -cargo bench --no-default-features --features "std u32_backend" -cargo bench --no-default-features --features "std u64_backend" -# Uses avx2 or ifma only if compiled for an appropriate target. -export RUSTFLAGS="-C target_cpu=native" -cargo bench --no-default-features --features "std simd_backend" -``` - -Performance is a secondary goal behind correctness, safety, and -clarity, but we aim to be competitive with other implementations. - -# FFI - -Unfortunately, we have no plans to add FFI to `curve25519-dalek` directly. The -reason is that we use Rust features to provide an API that maintains safety -invariants, which are not possible to maintain across an FFI boundary. For -instance, as described in the _Safety_ section above, invalid points are -impossible to construct, and this would not be the case if we exposed point -operations over FFI. - -However, `curve25519-dalek` is designed as a *mid-level* API, aimed at -implementing other, higher-level primitives. Instead of providing FFI at the -mid-level, our suggestion is to implement the higher-level primitive (a -signature, PAKE, ZKP, etc) in Rust, using `curve25519-dalek` as a dependency, -and have that crate provide a minimal, byte-buffer-oriented FFI specific to -that primitive. +There is also the [`curve25519-dalek-derive`](./curve25519-dalek-derive) crate, which is just a helper crate with some macros that make curve25519-dalek easier to write. # Contributing -Please see [CONTRIBUTING.md][contributing]. - -Patches and pull requests should be make against the `develop` -branch, **not** `main`. - -# About - -**SPOILER ALERT:** *The Twelfth Doctor's first encounter with the Daleks is in -his second full episode, "Into the Dalek". A beleaguered ship of the "Combined -Galactic Resistance" has discovered a broken Dalek that has turned "good", -desiring to kill all other Daleks. The Doctor, Clara and a team of soldiers -are miniaturized and enter the Dalek, which the Doctor names Rusty. They -repair the damage, but accidentally restore it to its original nature, causing -it to go on the rampage and alert the Dalek fleet to the whereabouts of the -rebel ship. However, the Doctor manages to return Rusty to its previous state -by linking his mind with the Dalek's: Rusty shares the Doctor's view of the -universe's beauty, but also his deep hatred of the Daleks. Rusty destroys the -other Daleks and departs the ship, determined to track down and bring an end -to the Dalek race.* - -`curve25519-dalek` is authored by Isis Agora Lovecruft and Henry de Valence. - -Portions of this library were originally a port of [Adam Langley's -Golang ed25519 library](https://github.com/agl/ed25519), which was in -turn a port of the reference `ref10` implementation. Most of this code, -including the 32-bit field arithmetic, has since been rewritten. - -The fast `u32` and `u64` scalar arithmetic was implemented by Andrew Moon, and -the addition chain for scalar inversion was provided by Brian Smith. The -optimised batch inversion was contributed by Sean Bowe and Daira Hopwood. - -The `no_std` and `zeroize` support was contributed by Tony Arcieri. +Please see [`CONTRIBUTING.md`](./CONTRIBUTING.md). -The formally verified backends, `fiat_u32_backend` and `fiat_u64_backend`, which -integrate with the Rust generated by the -[Fiat Crypto project](https://github.com/mit-plv/fiat-crypto) were contributed -by François Garillot. +# Code of Conduct -Thanks also to Ashley Hauck, Lucas Salibian, Manish Goregaokar, Jack Grigg, -Pratyush Mishra, Michael Rosenberg, and countless others for their -contributions. +We follow the [Rust Code of Conduct](http://www.rust-lang.org/conduct.html), +with the following additional clauses: -[ed25519-dalek]: https://github.com/dalek-cryptography/ed25519-dalek -[x25519-dalek]: https://github.com/dalek-cryptography/x25519-dalek -[contributing]: https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md -[docs-external]: https://doc.dalek.rs/curve25519_dalek/ -[docs-internal]: https://doc-internal.dalek.rs/curve25519_dalek/ -[criterion]: https://github.com/japaric/criterion.rs -[parallel_doc]: https://doc-internal.dalek.rs/curve25519_dalek/backend/vector/avx2/index.html -[subtle_doc]: https://doc.dalek.rs/subtle/ +* We respect the rights to privacy and anonymity for contributors and people in + the community. If someone wishes to contribute under a pseudonym different to + their primary identity, that wish is to be respected by all contributors. diff --git a/curve25519-dalek-derive/CHANGELOG.md b/curve25519-dalek-derive/CHANGELOG.md new file mode 100644 index 000000000..8a0915b84 --- /dev/null +++ b/curve25519-dalek-derive/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog + +Entries are listed in reverse chronological order per undeprecated +major series. + +### 0.1.1 + +* Copied over license files from [original](https://github.com/koute/unsafe_target_feature/tree/389ae00d34cf0ff589cb8d9b38a85ae1b05ebfdc) repo diff --git a/curve25519-dalek-derive/Cargo.toml b/curve25519-dalek-derive/Cargo.toml new file mode 100644 index 000000000..938144a0f --- /dev/null +++ b/curve25519-dalek-derive/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "curve25519-dalek-derive" +version = "0.1.1" +edition = "2021" + +repository = "https://github.com/dalek-cryptography/curve25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" +documentation = "https://docs.rs/curve25519-dalek-derive" +license = "MIT/Apache-2.0" +readme = "README.md" +description = "curve25519-dalek Derives" + +[lib] +proc-macro = true + +[dependencies] +proc-macro2 = "1.0.66" +quote = "1.0.31" +syn = { version = "2.0.27", features = ["full"] } diff --git a/curve25519-dalek-derive/LICENSE-APACHE b/curve25519-dalek-derive/LICENSE-APACHE new file mode 100644 index 000000000..16fe87b06 --- /dev/null +++ b/curve25519-dalek-derive/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/curve25519-dalek-derive/LICENSE-MIT b/curve25519-dalek-derive/LICENSE-MIT new file mode 100644 index 000000000..31aa79387 --- /dev/null +++ b/curve25519-dalek-derive/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/curve25519-dalek-derive/README.md b/curve25519-dalek-derive/README.md new file mode 100644 index 000000000..69bde71c3 --- /dev/null +++ b/curve25519-dalek-derive/README.md @@ -0,0 +1,198 @@ +# A more convenient `#[target_feature]` replacement + +To get good performance out of SIMD everything on the SIMD codepath must be inlined. +With how SIMD is currently implemented in Rust one of two things have to be true for +a function using SIMD to be inlinable: (and this includes the SIMD intrinsics themselves) + + a) The whole program has to be compiled with the relevant `-C target-cpu` or `-C target-feature` flags. + + b) SIMD support must be automatically detected at runtime, and every function on the SIMD codepath must be marked with `#[target_feature]`. + +Both have their downsides. Setting the `target-cpu` or `target-features` makes the resulting binary +incompatible with older CPUs, while using `#[target_feature]` is incredibly inconvenient. + +This crate is meant to make `#[target_feature]` less painful to use. + +## Problems with `#[target_feature]` + +When we're not compiling with the relevant `target-cpu`/`target-feature` flags everything on +the SIMD codepath must be marked with the `#[target_feature]` attribute. This is not a problem +when all of your SIMD code is neatly encapsulated inside of a single function, but once you start +to build out more elaborate abstractions it starts to become painful to use. + + * It can only be used on `unsafe` functions, so everything on your SIMD codepath now has to be `unsafe`. + + In theory this is nice - these functions require the relevant SIMD instructions to be present at runtime, + so calling them without checking is obviously unsafe! But in practice this is rarely what you want. When + you build an abstraction over SIMD code you usually want to assume that *internally* within your module + all of the necessary SIMD instructions are available, and you only want to check this at the boundaries + when you're first entering your module. You do *not* want to infect everything *inside* of the module with + `unsafe` since you've already checked this invariant at the module's API boundary. + + * It cannot be used on non-`unsafe` trait methods. + + If you're implementing a trait, say for example `std::ops::Add`, then you cannot mark the method `unsafe` + unless the original trait also has it marked as `unsafe`, and usually it doesn't. + + * It makes it impossible to abstract over a given SIMD instruction set using a trait. + + For example, let's assume you want to abstract over which SIMD instructions you use using a trait in the following way: + + ```rust + trait Backend { + unsafe fn sum(input: &[u32]) -> u32; + } + + struct AVX; + # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + impl Backend for AVX { + #[target_feature(enable = "avx")] + unsafe fn sum(xs: &[u32]) -> u32 { + // ... + todo!(); + } + } + + struct AVX2; + # #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + impl Backend for AVX2 { + #[target_feature(enable = "avx2")] + unsafe fn sum(xs: &[u32]) -> u32 { + // ... + todo!(); + } + } + + // And now you want a have function which calls into that trait: + unsafe fn do_calculations(xs: &[u32]) -> u32 where B: Backend { + let value = B::sum(xs); + // ...do some more calculations here... + value + } + ``` + + We have a problem here. This has to be marked with `#[target_feature]`, and that has to specify the concrete + feature flag for a given SIMD instruction set, but this function is generic so we can't do that! + +## How does this crate make it better? + +### You can now mark safe functions with `#[target_feature]` + +This crate exposes an `#[unsafe_target_feature]` macro which works just like `#[target_feature]` except +it moves the `unsafe` from the function prototype into the macro name, and can be used on safe functions. + +```rust,compile_fail +// ERROR: `#[target_feature(..)]` can only be applied to `unsafe` functions +#[target_feature(enable = "avx2")] +fn func() {} +``` + +```rust +// It works, but must be `unsafe` +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[target_feature(enable = "avx2")] +unsafe fn func() {} +``` + +```rust +use curve25519_dalek_derive::unsafe_target_feature; + +// No `unsafe` on the function itself! +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[unsafe_target_feature("avx2")] +fn func() {} +``` + +It can also be used to mark functions inside of impls: + +```rust,compile_fail +struct S; + +impl core::ops::Add for S { + type Output = S; + // ERROR: method `add` has an incompatible type for trait + #[target_feature(enable = "avx2")] + unsafe fn add(self, rhs: S) -> S { + S + } +} +``` + +```rust +use curve25519_dalek_derive::unsafe_target_feature; + +struct S; + +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[unsafe_target_feature("avx2")] +impl core::ops::Add for S { + type Output = S; + // No `unsafe` on the function itself! + fn add(self, rhs: S) -> S { + S + } +} + +``` + +### You can generate specialized copies of a module for each target feature + +```rust +use curve25519_dalek_derive::unsafe_target_feature_specialize; + +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", nightly))] +mod simd { + #[for_target_feature("sse2")] + pub const CONSTANT: u32 = 1; + + #[for_target_feature("avx2")] + pub const CONSTANT: u32 = 2; + + #[for_target_feature("avx512ifma")] + pub const CONSTANT: u32 = 3; + + pub fn func() { /* ... */ } +} + +# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn entry_point() { + #[cfg(nightly)] + if std::is_x86_feature_detected!("avx512ifma") { + return simd_avx512ifma::func(); + } + + if std::is_x86_feature_detected!("avx2") { + return simd_avx2::func(); + } + + if std::is_x86_feature_detected!("sse2") { + return simd_sse2::func(); + } + + unimplemented!(); +} +``` + +## How to use `#[unsafe_target_feature]`? + + - Can be used on `fn`s, `impl`s and `mod`s. + - When used on a function will only apply to that function; it won't apply to any nested functions, traits, mods, etc. + - When used on an `impl` will only apply to all of the functions directly defined inside of that `impl`. + - When used on a `mod` will only apply to all of the `fn`s and `impl`s directly defined inside of that `mod`. + - Cannot be used on methods which use `self` or `Self`; instead use it on the `impl` in which the method is defined. + +## License + +Licensed under either of + + * Apache License, Version 2.0, [LICENSE-APACHE](LICENSE-APACHE) + * MIT license ([LICENSE-MIT](LICENSE-MIT)) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/curve25519-dalek-derive/src/lib.rs b/curve25519-dalek-derive/src/lib.rs new file mode 100644 index 000000000..6e5920bb5 --- /dev/null +++ b/curve25519-dalek-derive/src/lib.rs @@ -0,0 +1,466 @@ +#![doc = include_str!("../README.md")] + +use proc_macro::TokenStream; +use proc_macro2::TokenStream as TokenStream2; +use syn::spanned::Spanned; + +macro_rules! unsupported_if_some { + ($value:expr) => { + if let Some(value) = $value { + return syn::Error::new(value.span(), "unsupported by #[unsafe_target_feature(...)]") + .into_compile_error() + .into(); + } + }; +} + +macro_rules! unsupported { + ($value: expr) => { + return syn::Error::new( + $value.span(), + "unsupported by #[unsafe_target_feature(...)]", + ) + .into_compile_error() + .into() + }; +} + +mod kw { + syn::custom_keyword!(conditional); +} + +enum SpecializeArg { + LitStr(syn::LitStr), + Conditional(Conditional), +} + +impl SpecializeArg { + fn lit(&self) -> &syn::LitStr { + match self { + SpecializeArg::LitStr(lit) => lit, + SpecializeArg::Conditional(conditional) => &conditional.lit, + } + } + + fn condition(&self) -> Option<&TokenStream2> { + match self { + SpecializeArg::LitStr(..) => None, + SpecializeArg::Conditional(conditional) => Some(&conditional.attr), + } + } +} + +struct Conditional { + lit: syn::LitStr, + attr: TokenStream2, +} + +impl syn::parse::Parse for Conditional { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lit = input.parse()?; + input.parse::()?; + let attr = input.parse()?; + + Ok(Conditional { lit, attr }) + } +} + +impl syn::parse::Parse for SpecializeArg { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + let lookahead = input.lookahead1(); + if lookahead.peek(kw::conditional) { + input.parse::()?; + + let content; + syn::parenthesized!(content in input); + + let conditional = content.parse()?; + Ok(SpecializeArg::Conditional(conditional)) + } else { + Ok(SpecializeArg::LitStr(input.parse()?)) + } + } +} + +struct SpecializeArgs(syn::punctuated::Punctuated); + +impl syn::parse::Parse for SpecializeArgs { + fn parse(input: syn::parse::ParseStream) -> syn::Result { + Ok(Self(syn::punctuated::Punctuated::parse_terminated(input)?)) + } +} + +#[proc_macro_attribute] +pub fn unsafe_target_feature(attributes: TokenStream, input: TokenStream) -> TokenStream { + let attributes = syn::parse_macro_input!(attributes as syn::LitStr); + let item = syn::parse_macro_input!(input as syn::Item); + process_item(&attributes, item, true) +} + +#[proc_macro_attribute] +pub fn unsafe_target_feature_specialize( + attributes: TokenStream, + input: TokenStream, +) -> TokenStream { + let attributes = syn::parse_macro_input!(attributes as SpecializeArgs); + let item_mod = syn::parse_macro_input!(input as syn::ItemMod); + + let mut out = Vec::new(); + for attributes in attributes.0 { + let features: Vec<_> = attributes + .lit() + .value() + .split(',') + .map(|feature| feature.replace(' ', "")) + .collect(); + let name = format!("{}_{}", item_mod.ident, features.join("_")); + let ident = syn::Ident::new(&name, item_mod.ident.span()); + let mut attrs = item_mod.attrs.clone(); + if let Some(condition) = attributes.condition() { + attrs.push(syn::Attribute { + pound_token: Default::default(), + style: syn::AttrStyle::Outer, + bracket_token: Default::default(), + meta: syn::Meta::List(syn::MetaList { + path: syn::Ident::new("cfg", attributes.lit().span()).into(), + delimiter: syn::MacroDelimiter::Paren(Default::default()), + tokens: condition.clone(), + }), + }); + } + + let item_mod = process_mod( + attributes.lit(), + syn::ItemMod { + attrs, + ident, + ..item_mod.clone() + }, + Some(features), + ); + + out.push(item_mod); + } + + quote::quote! { + #(#out)* + } + .into() +} + +fn process_item(attributes: &syn::LitStr, item: syn::Item, strict: bool) -> TokenStream { + match item { + syn::Item::Fn(function) => process_function(attributes, function, None), + syn::Item::Impl(item_impl) => process_impl(attributes, item_impl), + syn::Item::Mod(item_mod) => process_mod(attributes, item_mod, None).into(), + item => { + if strict { + unsupported!(item) + } else { + quote::quote! { #item }.into() + } + } + } +} + +fn process_mod( + attributes: &syn::LitStr, + mut item_mod: syn::ItemMod, + spec_features: Option>, +) -> TokenStream2 { + if let Some((_, ref mut content)) = item_mod.content { + 'next_item: for item in content { + if let Some(ref spec_features) = spec_features { + match item { + syn::Item::Const(syn::ItemConst { ref mut attrs, .. }) + | syn::Item::Enum(syn::ItemEnum { ref mut attrs, .. }) + | syn::Item::ExternCrate(syn::ItemExternCrate { ref mut attrs, .. }) + | syn::Item::Fn(syn::ItemFn { ref mut attrs, .. }) + | syn::Item::ForeignMod(syn::ItemForeignMod { ref mut attrs, .. }) + | syn::Item::Impl(syn::ItemImpl { ref mut attrs, .. }) + | syn::Item::Macro(syn::ItemMacro { ref mut attrs, .. }) + | syn::Item::Mod(syn::ItemMod { ref mut attrs, .. }) + | syn::Item::Static(syn::ItemStatic { ref mut attrs, .. }) + | syn::Item::Struct(syn::ItemStruct { ref mut attrs, .. }) + | syn::Item::Trait(syn::ItemTrait { ref mut attrs, .. }) + | syn::Item::TraitAlias(syn::ItemTraitAlias { ref mut attrs, .. }) + | syn::Item::Type(syn::ItemType { ref mut attrs, .. }) + | syn::Item::Union(syn::ItemUnion { ref mut attrs, .. }) + | syn::Item::Use(syn::ItemUse { ref mut attrs, .. }) => { + let mut index = 0; + while index < attrs.len() { + let attr = &attrs[index]; + if matches!(attr.style, syn::AttrStyle::Outer) { + match attr.meta { + syn::Meta::List(ref list) + if is_path_eq(&list.path, "for_target_feature") => + { + let feature: syn::LitStr = match list.parse_args() { + Ok(feature) => feature, + Err(error) => { + return error.into_compile_error(); + } + }; + + let feature = feature.value(); + if !spec_features + .iter() + .any(|enabled_feature| feature == *enabled_feature) + { + *item = syn::Item::Verbatim(Default::default()); + continue 'next_item; + } + + attrs.remove(index); + continue; + } + _ => {} + } + } + + index += 1; + continue; + } + } + _ => { + unsupported!(item_mod); + } + } + } + + *item = syn::Item::Verbatim( + process_item( + attributes, + std::mem::replace(item, syn::Item::Verbatim(Default::default())), + false, + ) + .into(), + ); + } + } + + quote::quote! { + #item_mod + } +} + +fn process_impl(attributes: &syn::LitStr, mut item_impl: syn::ItemImpl) -> TokenStream { + unsupported_if_some!(item_impl.defaultness); + unsupported_if_some!(item_impl.unsafety); + + let mut items = Vec::new(); + for item in item_impl.items.drain(..) { + match item { + syn::ImplItem::Fn(function) => { + unsupported_if_some!(function.defaultness); + let function = syn::ItemFn { + attrs: function.attrs, + vis: function.vis, + sig: function.sig, + block: Box::new(function.block), + }; + let output_item = process_function( + attributes, + function, + Some((item_impl.generics.clone(), item_impl.self_ty.clone())), + ); + items.push(syn::ImplItem::Verbatim(output_item.into())); + } + item => items.push(item), + } + } + + item_impl.items = items; + quote::quote! { + #item_impl + } + .into() +} + +fn is_path_eq(path: &syn::Path, ident: &str) -> bool { + let segments: Vec<_> = ident.split("::").collect(); + path.segments.len() == segments.len() + && path + .segments + .iter() + .zip(segments.iter()) + .all(|(segment, expected)| segment.ident == expected && segment.arguments.is_none()) +} + +fn process_function( + attributes: &syn::LitStr, + function: syn::ItemFn, + outer: Option<(syn::Generics, Box)>, +) -> TokenStream { + if function.sig.unsafety.is_some() { + return quote::quote! { + #[target_feature(enable = #attributes)] + #function + } + .into(); + } + + unsupported_if_some!(function.sig.constness); + unsupported_if_some!(function.sig.asyncness); + unsupported_if_some!(function.sig.abi); + unsupported_if_some!(function.sig.variadic); + + let function_visibility = function.vis; + let function_name = function.sig.ident; + let function_return = function.sig.output; + let function_inner_name = + syn::Ident::new(&format!("_impl_{}", function_name), function_name.span()); + let function_args = function.sig.inputs; + let function_body = function.block; + let mut function_call_args = Vec::new(); + let mut function_args_outer = Vec::new(); + let mut function_args_inner = Vec::new(); + for (index, arg) in function_args.iter().enumerate() { + match arg { + syn::FnArg::Receiver(receiver) => { + unsupported_if_some!(receiver.attrs.first()); + unsupported_if_some!(receiver.colon_token); + + if outer.is_none() { + return syn::Error::new(receiver.span(), "unsupported by #[unsafe_target_feature(...)]; put the attribute on the outer `impl`").into_compile_error().into(); + } + + function_args_inner.push(syn::FnArg::Receiver(receiver.clone())); + function_args_outer.push(syn::FnArg::Receiver(receiver.clone())); + function_call_args.push(syn::Ident::new("self", receiver.self_token.span())); + } + syn::FnArg::Typed(ty) => { + unsupported_if_some!(ty.attrs.first()); + + match &*ty.pat { + syn::Pat::Ident(pat_ident) => { + unsupported_if_some!(pat_ident.attrs.first()); + + function_args_inner.push(arg.clone()); + function_args_outer.push(syn::FnArg::Typed(syn::PatType { + attrs: Vec::new(), + pat: Box::new(syn::Pat::Ident(syn::PatIdent { + attrs: Vec::new(), + by_ref: None, + mutability: None, + ident: pat_ident.ident.clone(), + subpat: None, + })), + colon_token: ty.colon_token, + ty: ty.ty.clone(), + })); + function_call_args.push(pat_ident.ident.clone()); + } + syn::Pat::Wild(pat_wild) => { + unsupported_if_some!(pat_wild.attrs.first()); + + let ident = syn::Ident::new( + &format!("__arg_{}__", index), + pat_wild.underscore_token.span(), + ); + function_args_inner.push(arg.clone()); + function_args_outer.push(syn::FnArg::Typed(syn::PatType { + attrs: Vec::new(), + pat: Box::new(syn::Pat::Ident(syn::PatIdent { + attrs: Vec::new(), + by_ref: None, + mutability: None, + ident: ident.clone(), + subpat: None, + })), + colon_token: ty.colon_token, + ty: ty.ty.clone(), + })); + function_call_args.push(ident); + } + _ => unsupported!(arg), + } + } + } + } + + let mut maybe_inline = quote::quote! {}; + let mut maybe_outer_attributes = Vec::new(); + let mut maybe_cfg = quote::quote! {}; + for attribute in function.attrs { + match &attribute.meta { + syn::Meta::Path(path) if is_path_eq(path, "inline") => { + maybe_inline = quote::quote! { #[inline] }; + } + syn::Meta::Path(path) if is_path_eq(path, "test") => { + maybe_outer_attributes.push(attribute); + maybe_cfg = quote::quote! { #[cfg(target_feature = #attributes)] }; + } + syn::Meta::List(syn::MetaList { path, tokens, .. }) + if is_path_eq(path, "inline") && tokens.to_string() == "always" => + { + maybe_inline = quote::quote! { #[inline] }; + } + syn::Meta::NameValue(syn::MetaNameValue { path, .. }) if is_path_eq(path, "doc") => { + maybe_outer_attributes.push(attribute); + } + syn::Meta::List(syn::MetaList { path, .. }) + if is_path_eq(path, "cfg") + || is_path_eq(path, "allow") + || is_path_eq(path, "deny") => + { + maybe_outer_attributes.push(attribute); + } + syn::Meta::Path(path) if is_path_eq(path, "rustfmt::skip") => { + maybe_outer_attributes.push(attribute); + } + _ => unsupported!(attribute), + } + } + + let (fn_impl_generics, fn_ty_generics, fn_where_clause) = + function.sig.generics.split_for_impl(); + let fn_call_generics = fn_ty_generics.as_turbofish(); + + if let Some((generics, self_ty)) = outer { + let (outer_impl_generics, outer_ty_generics, outer_where_clause) = + generics.split_for_impl(); + let trait_ident = + syn::Ident::new(&format!("__Impl_{}__", function_name), function_name.span()); + let item_trait = quote::quote! { + #[allow(non_camel_case_types)] + trait #trait_ident #outer_impl_generics #outer_where_clause { + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause; + } + }; + + let item_trait_impl = quote::quote! { + impl #outer_impl_generics #trait_ident #outer_ty_generics for #self_ty #outer_where_clause { + #[target_feature(enable = #attributes)] + #maybe_inline + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_inner),*) #function_return #fn_where_clause #function_body + } + }; + + quote::quote! { + #[inline(always)] + #(#maybe_outer_attributes)* + #function_visibility fn #function_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause { + #item_trait + #item_trait_impl + unsafe { + ::#function_inner_name #fn_call_generics (#(#function_call_args),*) + } + } + }.into() + } else { + quote::quote! { + #[inline(always)] + #maybe_cfg + #(#maybe_outer_attributes)* + #function_visibility fn #function_name #fn_impl_generics (#(#function_args_outer),*) #function_return #fn_where_clause { + #[target_feature(enable = #attributes)] + #maybe_inline + unsafe fn #function_inner_name #fn_impl_generics (#(#function_args_inner),*) #function_return #fn_where_clause #function_body + unsafe { + #function_inner_name #fn_call_generics (#(#function_call_args),*) + } + } + }.into() + } +} diff --git a/curve25519-dalek-derive/tests/tests.rs b/curve25519-dalek-derive/tests/tests.rs new file mode 100644 index 000000000..1516b3527 --- /dev/null +++ b/curve25519-dalek-derive/tests/tests.rs @@ -0,0 +1,148 @@ +#![cfg(any(target_arch = "x86", target_arch = "x86_64"))] +#![allow(dead_code)] +#![allow(unused_imports)] + +use curve25519_dalek_derive::{unsafe_target_feature, unsafe_target_feature_specialize}; + +#[unsafe_target_feature("sse2")] +/// A doc comment. +fn function(a: u32, b: u32) -> u32 { + a - b +} + +#[unsafe_target_feature("sse2")] +fn function_with_const_arg(b: u32) -> u32 { + N - b +} + +#[unsafe_target_feature("sse2")] +fn function_with_where_clause(a: T, b: T) -> T::Output +where + T: Copy + core::ops::Sub, +{ + a - b +} + +#[unsafe_target_feature("sse2")] +#[cfg(feature = "dummy")] +fn function_with_cfg() {} + +#[unsafe_target_feature("sse2")] +#[rustfmt::skip] +fn function_with_rustfmt_skip() {} + +struct Struct { + a: u32, +} + +#[unsafe_target_feature("sse2")] +impl Struct { + #[allow(unused_mut)] + fn member_function(&self, mut b: u32) -> u32 { + self.a - b + } + + fn member_function_with_const_arg(self) -> u32 { + self.a - N + } + + #[cfg(feature = "dummy")] + fn member_function_with_cfg() {} +} + +struct StructWithGenerics +where + T: Copy + core::ops::Sub, +{ + a: T, +} + +#[unsafe_target_feature("sse2")] +impl StructWithGenerics +where + T: Copy + core::ops::Sub, +{ + #[inline] + fn member_function(&self, b: T) -> T::Output { + self.a - b + } +} + +struct StructWithGenericsNoWhere { + a: T, +} + +#[unsafe_target_feature("sse2")] +impl StructWithGenericsNoWhere { + #[inline(always)] + fn member_function(&self, b: T) -> T::Output { + self.a - b + } +} + +#[unsafe_target_feature("sse2")] +#[allow(dead_code)] +impl<'a> From<&'a Struct> for () { + fn from(_: &'a Struct) -> Self {} +} + +#[unsafe_target_feature("sse2")] +mod inner { + fn inner_function(a: u32, b: u32) -> u32 { + a - b + } +} + +#[unsafe_target_feature_specialize("sse2", "avx2", conditional("avx512ifma", disabled))] +mod inner_spec { + #[for_target_feature("sse2")] + const CONST: u32 = 1; + + #[for_target_feature("avx2")] + const CONST: u32 = 2; + + pub fn spec_function(a: u32, b: u32) -> u32 { + a - b - CONST + } + + #[for_target_feature("sse2")] + const IS_AVX2: bool = false; + + #[for_target_feature("avx2")] + const IS_AVX2: bool = true; + + #[test] + fn test_specialized() { + assert!(!IS_AVX2); + } + + #[cfg(test)] + mod tests { + #[test] + fn test_specialized_inner() { + assert!(!super::IS_AVX2); + } + } +} + +#[unsafe_target_feature("sse2")] +#[test] +fn test_sse2_only() {} + +#[unsafe_target_feature("avx2")] +#[test] +fn test_avx2_only() { + compile_error!(); +} + +#[test] +fn test_function() { + assert_eq!(function(10, 3), 7); + assert_eq!(function_with_where_clause(10, 3), 7); + assert_eq!(function_with_const_arg::<10>(3), 7); + assert_eq!(Struct { a: 10 }.member_function(3), 7); + assert_eq!(StructWithGenerics { a: 10 }.member_function(3), 7); + assert_eq!(StructWithGenericsNoWhere { a: 10 }.member_function(3), 7); + assert_eq!(inner_spec_sse2::spec_function(10, 3), 6); + assert_eq!(inner_spec_avx2::spec_function(10, 3), 5); +} diff --git a/CHANGELOG.md b/curve25519-dalek/CHANGELOG.md similarity index 73% rename from CHANGELOG.md rename to curve25519-dalek/CHANGELOG.md index 000b9654c..a4c8452cc 100644 --- a/CHANGELOG.md +++ b/curve25519-dalek/CHANGELOG.md @@ -3,6 +3,65 @@ Entries are listed in reverse chronological order per undeprecated major series. +## 4.x series + +### 4.1.2 + +* Fix nightly SIMD build + +### 4.1.1 + +* Mark `constants::BASEPOINT_ORDER` deprecated from pub API +* Add implementation for `PrimeFieldBits`, behind the `group-bits` feature flag. + +### 4.1.0 + +* Add arbitrary integer multiplication with `MontgomeryPoint::mul_bits_be` +* Add implementations of the `ff` and `group` traits, behind the `group` feature flag +* Adapt to new types introduced in `fiat-crypto` 0.2 in `fiat` backend +* Fix `no_std` for `fiat` backend +* Mark `Scalar::clamp_integer` as `#[must_use]` +* Various documentation fixes + +### 4.0.0 + +#### Breaking changes + +* Update the MSRV from 1.41 to 1.60 +* Provide SemVer policy +* Make `digest` an optional feature +* Make `rand_core` an optional feature +* Remove `std` feature flag +* Remove `nightly` feature flag +* Automatic serial backend selection between `u32` and `u64` over the default `u32` +* Backend `simd` is now automatically selected over `serial` when a supported CPU is detected +* Backend override is now via cfg(curve25519_dalek_backend) over additive features +* Provide override to select `u32` or `u64` backend via cfg(curve25519_dalek_bits) +* Replace methods `Scalar::{zero, one}` with constants `Scalar::{ZERO, ONE}` +* Deprecate `EdwardsPoint::hash_from_bytes` and rename it `EdwardsPoint::nonspec_map_to_curve` +* Require including a new trait, `use curve25519_dalek::traits::BasepointTable` + whenever using `EdwardsBasepointTable` or `RistrettoBasepointTable` +* `Scalar::from_canonical_bytes` now returns `CtOption` +* `Scalar::is_canonical` now returns `Choice` +* Remove `Scalar::from_bytes_clamped` and `Scalar::reduce` +* Deprecate and feature-gate `Scalar::from_bits` behind `legacy_compatibility` + +#### Other changes + +* Add `EdwardsPoint::{mul_base, mul_base_clamped}`, `MontgomeryPoint::{mul_base, mul_base_clamped}`, and `BasepointTable::mul_base_clamped` +* Add `precomputed-tables` feature +* Update Maintenance Policies for SemVer +* Migrate documentation to docs.rs hosted +* Fix backend documentation generation +* Fix panic when `Ristretto::double_and_compress_batch` receives the identity point +* Remove `byteorder` dependency +* Update the `criterion` dependency to 0.4.0 +* Include README.md into crate Documentation +* Update the `rand_core` dependency version and the `rand` dev-dependency + version. +* Relax the `zeroize` dependency to `^1` +* Update the edition from 2015 to 2021 + ## 3.x series ### 3.2.0 @@ -53,6 +112,8 @@ major series. ### 3.0.0 +#### Breaking changes + * Update the `digest` dependency to `0.9`. This requires a major version because the `digest` traits are part of the public API, but there are otherwise no changes to the API. @@ -66,7 +127,7 @@ major series. ### 2.1.2 -* Multiple documenation typo fixes. +* Multiple documentation typo fixes. * Fix `alloc` feature working with stable rust. ### 2.1.1 @@ -80,12 +141,20 @@ major series. ### 2.0.0 +The only significant change is the data model change to the `serde` feature; +besides the `rand_core` version bump, there are no other user-visible changes. + +#### Breaking changes + * Fix a data modeling error in the `serde` feature pointed out by Trevor Perrin which caused points and scalars to be serialized with length fields rather than as fixed-size 32-byte arrays. This is a breaking change, but it fixes compatibility with `serde-json` and ensures that the `serde-bincode` encoding matches the conventional encoding for X/Ed25519. * Update `rand_core` to `0.5`, allowing use with new `rand` versions. + +#### Other changes + * Switch from `clear_on_drop` to `zeroize` (by Tony Arcieri). * Require `subtle = ^2.2.1` and remove the note advising nightly Rust, which is no longer required as of that version of `subtle`. See the `subtle` @@ -94,9 +163,6 @@ major series. * Remove the `build.rs` hack which loaded the entire crate into its own `build.rs` to generate constants, and keep the constants in the source code. -The only significant change is the data model change to the `serde` feature; -besides the `rand_core` version bump, there are no other user-visible changes. - ## 1.x series ### 1.2.6 diff --git a/curve25519-dalek/Cargo.toml b/curve25519-dalek/Cargo.toml new file mode 100644 index 000000000..e08e3928c --- /dev/null +++ b/curve25519-dalek/Cargo.toml @@ -0,0 +1,80 @@ +[package] +name = "curve25519-dalek" +# Before incrementing: +# - update CHANGELOG +# - update README if required by semver +# - if README was updated, also update module documentation in src/lib.rs +version = "4.1.2" +edition = "2021" +rust-version = "1.60.0" +authors = ["Isis Lovecruft ", + "Henry de Valence "] +readme = "README.md" +license = "BSD-3-Clause" +repository = "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/curve25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" +documentation = "https://docs.rs/curve25519-dalek" +categories = ["cryptography", "no-std"] +keywords = ["cryptography", "crypto", "ristretto", "curve25519", "ristretto255"] +description = "A pure-Rust implementation of group operations on ristretto255 and Curve25519" +exclude = [ + "**/.gitignore", + ".gitignore", +] + +[package.metadata.docs.rs] +rustdoc-args = [ + "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", + "--cfg", "docsrs", +] +features = ["serde", "rand_core", "digest", "legacy_compatibility", "group-bits"] + +[dev-dependencies] +sha2 = { version = "0.10", default-features = false } +bincode = "1" +criterion = { version = "0.5", features = ["html_reports"] } +hex = "0.4.2" +rand = "0.8" +rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } + +[build-dependencies] +rustc_version = "0.4.0" + +[[bench]] +name = "dalek_benchmarks" +harness = false +required-features = ["alloc", "rand_core"] + +[dependencies] +cfg-if = "1" +ff = { version = "0.13", default-features = false, optional = true } +group = { version = "0.13", default-features = false, optional = true } +rand_core = { version = "0.6.4", default-features = false, optional = true } +digest = { version = "0.10", default-features = false, optional = true } +subtle = { version = "2.3.0", default-features = false } +serde = { version = "1.0", default-features = false, optional = true, features = ["derive"] } +zeroize = { version = "1", default-features = false, optional = true } + +# Betrusted/Precursor dependency set, enabled by backend_u32e feature +[target.'cfg(curve25519_dalek_backend = "u32e_backend")'.dependencies] +log = { version = "0.4"} +engine25519-as = {git = "https://github.com/betrusted-io/engine25519-as.git", rev = "d249c967556b02ab5439eacb5078fa00c60b93d6", default-features = false, features = []} +utralib = {version = "0.1.24", default-features = false} +zeroize = { version = "1", default-features = false } +xous = "0.9.58" + +[target.'cfg(target_arch = "x86_64")'.dependencies] +cpufeatures = "0.2.6" + +fiat-crypto = { version = "0.2.1", default-features = false , optional = true} + +[features] +default = ["alloc", "precomputed-tables", "zeroize"] +alloc = ["zeroize?/alloc"] +precomputed-tables = [] +legacy_compatibility = [] +group = ["dep:group", "rand_core"] +group-bits = ["group", "ff/bits"] + +[target.'cfg(all(not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "serial"), target_arch = "x86_64"))'.dependencies] +curve25519-dalek-derive = { version = "0.1", path = "../curve25519-dalek-derive" } diff --git a/LICENSE b/curve25519-dalek/LICENSE similarity index 100% rename from LICENSE rename to curve25519-dalek/LICENSE diff --git a/curve25519-dalek/Makefile b/curve25519-dalek/Makefile new file mode 100644 index 000000000..bb61cc844 --- /dev/null +++ b/curve25519-dalek/Makefile @@ -0,0 +1,11 @@ +FEATURES := serde rand_core digest legacy_compatibility + +export RUSTDOCFLAGS := \ + --cfg docsrs \ + --html-in-header docs/assets/rustdoc-include-katex-header.html + +doc: + cargo +nightly rustdoc --features "$(FEATURES)" + +doc-internal: + cargo +nightly rustdoc --features "$(FEATURES)" -- --document-private-items diff --git a/curve25519-dalek/README.md b/curve25519-dalek/README.md new file mode 100644 index 000000000..c918d6959 --- /dev/null +++ b/curve25519-dalek/README.md @@ -0,0 +1,323 @@ + +# curve25519-dalek [![](https://buildstats.info/crate/curve25519-dalek)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/docsrs/curve25519-dalek)](https://docs.rs/curve25519-dalek) [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/curve25519-dalek.yml) + +

+dalek-cryptography logo: a dalek with edwards curves as sparkles coming out of its radar-schnozzley blaster thingies +

+ +**A pure-Rust implementation of group operations on Ristretto and Curve25519.** + +`curve25519-dalek` is a library providing group operations on the Edwards and +Montgomery forms of Curve25519, and on the prime-order Ristretto group. + +`curve25519-dalek` is not intended to provide implementations of any particular +crypto protocol. Rather, implementations of those protocols (such as +[`x25519-dalek`][x25519-dalek] and [`ed25519-dalek`][ed25519-dalek]) should use +`curve25519-dalek` as a library. + +`curve25519-dalek` is intended to provide a clean and safe _mid-level_ API for use +implementing a wide range of ECC-based crypto protocols, such as key agreement, +signatures, anonymous credentials, rangeproofs, and zero-knowledge proof +systems. + +In particular, `curve25519-dalek` implements Ristretto, which constructs a +prime-order group from a non-prime-order Edwards curve. This provides the +speed and safety benefits of Edwards curve arithmetic, without the pitfalls of +cofactor-related abstraction mismatches. + +# Use + +## Stable + +To import `curve25519-dalek`, add the following to the dependencies section of +your project's `Cargo.toml`: +```toml +curve25519-dalek = "4" +``` + +If opting into [SemVer-exempted features](#public-api-semver-exemptions) a range +can be used to scope the tested compatible version range e.g.: +```toml +curve25519-dalek = ">= 4.0, < 4.2" +``` + +## Feature Flags + +| Feature | Default? | Description | +| :--- | :---: | :--- | +| `alloc` | ✓ | Enables Edwards and Ristretto multiscalar multiplication, batch scalar inversion, and batch Ristretto double-and-compress. Also enables `zeroize`. | +| `zeroize` | ✓ | Enables [`Zeroize`][zeroize-trait] for all scalar and curve point types. | +| `precomputed-tables` | ✓ | Includes precomputed basepoint multiplication tables. This speeds up `EdwardsPoint::mul_base` and `RistrettoPoint::mul_base` by ~4x, at the cost of ~30KB added to the code size. | +| `rand_core` | | Enables `Scalar::random` and `RistrettoPoint::random`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. | +| `digest` | | Enables `RistrettoPoint::{from_hash, hash_from_bytes}` and `Scalar::{from_hash, hash_from_bytes}`. This is an optional dependency whose version is not subject to SemVer. See [below](#public-api-semver-exemptions) for more details. | +| `serde` | | Enables `serde` serialization/deserialization for all the point and scalar types. | +| `legacy_compatibility`| | Enables `Scalar::from_bits`, which allows the user to build unreduced scalars whose arithmetic is broken. Do not use this unless you know what you're doing. | +| `group` | | Enables external `group` and `ff` crate traits | + +To disable the default features when using `curve25519-dalek` as a dependency, +add `default-features = false` to the dependency in your `Cargo.toml`. To +disable it when running `cargo`, add the `--no-default-features` CLI flag. + +## Major Version API Changes + +Breaking changes for each major version release can be found in +[`CHANGELOG.md`](CHANGELOG.md), under the "Breaking changes" subheader. The +latest breaking changes in high level are below: + +### Breaking changes in 4.0.0 + +* Update the MSRV from 1.41 to 1.60 +* Provide SemVer policy +* Make `digest` and `rand_core` optional features +* Remove `std` and `nightly` features +* Replace backend selection - See [CHANGELOG.md](CHANGELOG.md) and [backends](#backends) +* Replace methods `Scalar::{zero, one}` with constants `Scalar::{ZERO, ONE}` +* `Scalar::from_canonical_bytes` now returns `CtOption` +* `Scalar::is_canonical` now returns `Choice` +* Remove `Scalar::from_bytes_clamped` and `Scalar::reduce` +* Deprecate and feature-gate `Scalar::from_bits` behind `legacy_compatibility` +* Deprecate `EdwardsPoint::hash_from_bytes` and rename it + `EdwardsPoint::nonspec_map_to_curve` +* Require including a new trait, `use curve25519_dalek::traits::BasepointTable` + whenever using `EdwardsBasepointTable` or `RistrettoBasepointTable` + +This release also does a lot of dependency updates and relaxations to unblock upstream build issues. + +# Backends + +Curve arithmetic is implemented and used by one of the following backends: + +| Backend | Selection | Implementation | Bits / Word sizes | +| :--- | :--- | :--- | :--- | +| `serial` | Automatic | An optimized, non-parllel implementation | `32` and `64` | +| `fiat` | Manual | Formally verified field arithmetic from [fiat-crypto] | `32` and `64` | +| `simd` | Automatic | Intel AVX2 / AVX512 IFMA accelerated backend | `64` only | + +At runtime, `curve25519-dalek` selects an arithmetic backend from the set of backends it was compiled to support. For Intel x86-64 targets, unless otherwise specified, it will build itself with `simd` support, and default to `serial` at runtime if the appropriate CPU features aren't detected. See [SIMD backend] for more details. + +In the future, `simd` backend may be extended to cover more instruction sets. This change will be non-breaking as this is considered as implementation detail. + +## Manual Backend Override + +You can force the crate to compile with specific backend support, e.g., `serial` for x86-64 targets to save code size, or `fiat` to force the runtime to use verified code. To do this, set the environment variable: +```sh +RUSTFLAGS='--cfg curve25519_dalek_backend="BACKEND"' +``` +Equivalently, you can write to +`~/.cargo/config`: +```toml +[build] +rustflags = ['--cfg=curve25519_dalek_backend="BACKEND"'] +``` +More info [here](https://doc.rust-lang.org/cargo/reference/config.html#buildrustflags). + +Note for contributors: The target backends are not entirely independent of each +other. The [SIMD backend] directly depends on parts of the serial backend to +function. + +## Bits / Word size + +`curve25519-dalek` will automatically choose the word size for the `fiat` and +`serial` backends, based on the build target. +For example, building for a 64-bit machine, the default 64 bit word size is +automatically chosen when either the `serial` or `fiat` backend is selected. + +In some targets it might be required to override the word size for better +performance. +Backend word size can be overridden for `serial` and `fiat` by setting the +environment variable: +```sh +RUSTFLAGS='--cfg curve25519_dalek_bits="SIZE"' +``` +`SIZE` is `32` or `64`. As in the above section, this can also be placed +in `~/.cargo/config`. + +Note: The [SIMD backend] requires a word size of 64 bits. Attempting to set bits=32 and backend=`simd` will yield a compile error. + +### Cross-compilation + +Because backend selection is done by target, cross-compiling will select the correct word size automatically. For example, if a x86-64 Linux machine runs the following commands, `curve25519-dalek` will be compiled with the 32-bit `serial` backend. +```console +$ sudo apt install gcc-multilib # (or whatever package manager you use) +$ rustup target add i686-unknown-linux-gnu +$ cargo build --target i686-unknown-linux-gnu +``` + +## SIMD backend + +The specific SIMD backend (AVX512 / AVX2 / `serial` default) is selected automatically at runtime, depending on the currently available CPU features, and whether Rust nightly is being used for compilation. The precise conditions are specified below. + +For a given CPU feature, you can also specify an appropriate `-C target_feature` to build a binary which assumes the required SIMD instructions are always available. Don't do this if you don't have a good reason. + +| Backend | `RUSTFLAGS` | Requires nightly? | +| :--- | :--- | :--- | +| avx2 | `-C target_feature=+avx2` | no | +| avx512 | `-C target_feature=+avx512ifma,+avx512vl` | yes | + +If compiled on a non-nightly compiler, `curve25519-dalek` will not include AVX512 code, and therefore will never select it at runtime. + +# Documentation + +The semver-stable, public-facing `curve25519-dalek` API is documented [here][docs]. + +## Building Docs Locally + +The `curve25519-dalek` documentation requires a custom HTML header to include +KaTeX for math support. Unfortunately `cargo doc` does not currently support +this, but docs can be built using +```sh +make doc +``` +for regular docs, and +```sh +make doc-internal +``` +for docs that include private items. + +# Maintenance Policies + +All on-by-default features of this library are covered by +[semantic versioning][semver] (SemVer). SemVer exemptions are outlined below +for MSRV and public API. + +## Minimum Supported Rust Version + +| Releases | MSRV | +| :--- |:-------| +| 4.x | 1.60.0 | +| 3.x | 1.41.0 | + +From 4.x and on, MSRV changes will be accompanied by a minor version bump. + +## Public API SemVer Exemptions + +Breaking changes to SemVer-exempted components affecting the public API will be accompanied by +_some_ version bump. Below are the specific policies: + +| Releases | Public API Component(s) | Policy | +| :--- | :--- | :--- | +| 4.x | Dependencies `group`, `digest` and `rand_core` | Minor SemVer bump | + +# Safety + +The `curve25519-dalek` types are designed to make illegal states +unrepresentable. For example, any instance of an `EdwardsPoint` is +guaranteed to hold a point on the Edwards curve, and any instance of a +`RistrettoPoint` is guaranteed to hold a valid point in the Ristretto +group. + +All operations are implemented using constant-time logic (no +secret-dependent branches, no secret-dependent memory accesses), +unless specifically marked as being variable-time code. +We believe that our constant-time logic is lowered to constant-time +assembly, at least on `x86_64` targets. + +As an additional guard against possible future compiler optimizations, +the `subtle` crate places an optimization barrier before every +conditional move or assignment. More details can be found in [the +documentation for the `subtle` crate][subtle_doc]. + +Some functionality (e.g., multiscalar multiplication or batch +inversion) requires heap allocation for temporary buffers. All +heap-allocated buffers of potentially secret data are explicitly +zeroed before release. + +However, we do not attempt to zero stack data, for two reasons. +First, it's not possible to do so correctly: we don't have control +over stack allocations, so there's no way to know how much data to +wipe. Second, because `curve25519-dalek` provides a mid-level API, +the correct place to start zeroing stack data is likely not at the +entrypoints of `curve25519-dalek` functions, but at the entrypoints of +functions in other crates. + +The implementation is memory-safe, and contains no significant +`unsafe` code. The SIMD backend uses `unsafe` internally to call SIMD +intrinsics. These are marked `unsafe` only because invoking them on an +inappropriate CPU would cause `SIGILL`, but the entire backend is only +invoked when the appropriate CPU features are detected at runtime, or +when the whole program is compiled with the appropriate `target_feature`s. + +# Performance + +Benchmarks are run using [`criterion.rs`][criterion]: + +```sh +cargo bench --features "rand_core" +export RUSTFLAGS='-C target_cpu=native' +cargo +nightly bench --features "rand_core" +``` + +Performance is a secondary goal behind correctness, safety, and +clarity, but we aim to be competitive with other implementations. + +# FFI + +Unfortunately, we have no plans to add FFI to `curve25519-dalek` directly. The +reason is that we use Rust features to provide an API that maintains safety +invariants, which are not possible to maintain across an FFI boundary. For +instance, as described in the _Safety_ section above, invalid points are +impossible to construct, and this would not be the case if we exposed point +operations over FFI. + +However, `curve25519-dalek` is designed as a *mid-level* API, aimed at +implementing other, higher-level primitives. Instead of providing FFI at the +mid-level, our suggestion is to implement the higher-level primitive (a +signature, PAKE, ZKP, etc) in Rust, using `curve25519-dalek` as a dependency, +and have that crate provide a minimal, byte-buffer-oriented FFI specific to +that primitive. + +# Contributing + +Please see [CONTRIBUTING.md][contributing]. + +# About + +**SPOILER ALERT:** *The Twelfth Doctor's first encounter with the Daleks is in +his second full episode, "Into the Dalek". A beleaguered ship of the "Combined +Galactic Resistance" has discovered a broken Dalek that has turned "good", +desiring to kill all other Daleks. The Doctor, Clara and a team of soldiers +are miniaturized and enter the Dalek, which the Doctor names Rusty. They +repair the damage, but accidentally restore it to its original nature, causing +it to go on the rampage and alert the Dalek fleet to the whereabouts of the +rebel ship. However, the Doctor manages to return Rusty to its previous state +by linking his mind with the Dalek's: Rusty shares the Doctor's view of the +universe's beauty, but also his deep hatred of the Daleks. Rusty destroys the +other Daleks and departs the ship, determined to track down and bring an end +to the Dalek race.* + +`curve25519-dalek` is authored by Isis Agora Lovecruft and Henry de Valence. + +Portions of this library were originally a port of [Adam Langley's +Golang ed25519 library](https://github.com/agl/ed25519), which was in +turn a port of the reference `ref10` implementation. Most of this code, +including the 32-bit field arithmetic, has since been rewritten. + +The fast `u32` and `u64` scalar arithmetic was implemented by Andrew Moon, and +the addition chain for scalar inversion was provided by Brian Smith. The +optimised batch inversion was contributed by Sean Bowe and Daira Hopwood. + +The `no_std` and `zeroize` support was contributed by Tony Arcieri. + +The formally verified `fiat_backend` integrates Rust code generated by the +[Fiat Crypto project](https://github.com/mit-plv/fiat-crypto) and was +contributed by François Garillot. + +Thanks also to Ashley Hauck, Lucas Salibian, Manish Goregaokar, Jack Grigg, +Pratyush Mishra, Michael Rosenberg, @pinkforest, and countless others for their +contributions. + +[ed25519-dalek]: https://github.com/dalek-cryptography/curve25519-dalek/tree/main/ed25519-dalek +[x25519-dalek]: https://github.com/dalek-cryptography/curve25519-dalek/tree/main/x25519-dalek +[docs]: https://docs.rs/curve25519-dalek/ +[contributing]: https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md +[criterion]: https://github.com/japaric/criterion.rs +[parallel_doc]: https://docs.rs/curve25519-dalek/latest/curve25519_dalek/backend/vector/index.html +[subtle_doc]: https://docs.rs/subtle +[fiat-crypto]: https://github.com/mit-plv/fiat-crypto +[semver]: https://semver.org/spec/v2.0.0.html +[rngcorestd]: https://github.com/rust-random/rand/tree/7aa25d577e2df84a5156f824077bb7f6bdf28d97/rand_core#crate-features +[zeroize-trait]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html +[SIMD backend]: #simd-backend diff --git a/benches/dalek_benchmarks.rs b/curve25519-dalek/benches/dalek_benchmarks.rs similarity index 61% rename from benches/dalek_benchmarks.rs rename to curve25519-dalek/benches/dalek_benchmarks.rs index 308545cb9..62a6280f4 100644 --- a/benches/dalek_benchmarks.rs +++ b/curve25519-dalek/benches/dalek_benchmarks.rs @@ -1,18 +1,10 @@ #![allow(non_snake_case)] -extern crate rand; -use rand::rngs::OsRng; -use rand::thread_rng; +use rand::{rngs::OsRng, thread_rng}; -#[macro_use] -extern crate criterion; - -use criterion::measurement::Measurement; -use criterion::BatchSize; -use criterion::Criterion; -use criterion::{BenchmarkGroup, BenchmarkId}; - -extern crate curve25519_dalek; +use criterion::{ + criterion_main, measurement::Measurement, BatchSize, BenchmarkGroup, BenchmarkId, Criterion, +}; use curve25519_dalek::constants; use curve25519_dalek::scalar::Scalar; @@ -25,27 +17,26 @@ mod edwards_benches { use curve25519_dalek::edwards::EdwardsPoint; - fn compress(c: &mut Criterion) { + fn compress(c: &mut BenchmarkGroup) { let B = &constants::ED25519_BASEPOINT_POINT; c.bench_function("EdwardsPoint compression", move |b| b.iter(|| B.compress())); } - fn decompress(c: &mut Criterion) { + fn decompress(c: &mut BenchmarkGroup) { let B_comp = &constants::ED25519_BASEPOINT_COMPRESSED; c.bench_function("EdwardsPoint decompression", move |b| { b.iter(|| B_comp.decompress().unwrap()) }); } - fn consttime_fixed_base_scalar_mul(c: &mut Criterion) { - let B = &constants::ED25519_BASEPOINT_TABLE; + fn consttime_fixed_base_scalar_mul(c: &mut BenchmarkGroup) { let s = Scalar::from(897987897u64).invert(); c.bench_function("Constant-time fixed-base scalar mul", move |b| { - b.iter(|| B * &s) + b.iter(|| EdwardsPoint::mul_base(&s)) }); } - fn consttime_variable_base_scalar_mul(c: &mut Criterion) { + fn consttime_variable_base_scalar_mul(c: &mut BenchmarkGroup) { let B = &constants::ED25519_BASEPOINT_POINT; let s = Scalar::from(897987897u64).invert(); c.bench_function("Constant-time variable-base scalar mul", move |b| { @@ -53,10 +44,10 @@ mod edwards_benches { }); } - fn vartime_double_base_scalar_mul(c: &mut Criterion) { + fn vartime_double_base_scalar_mul(c: &mut BenchmarkGroup) { c.bench_function("Variable-time aA+bB, A variable, B fixed", |bench| { let mut rng = thread_rng(); - let A = &Scalar::random(&mut rng) * &constants::ED25519_BASEPOINT_TABLE; + let A = EdwardsPoint::mul_base(&Scalar::random(&mut rng)); bench.iter_batched( || (Scalar::random(&mut rng), Scalar::random(&mut rng)), |(a, b)| EdwardsPoint::vartime_double_scalar_mul_basepoint(&a, &A, &b), @@ -65,15 +56,15 @@ mod edwards_benches { }); } - criterion_group! { - name = edwards_benches; - config = Criterion::default(); - targets = - compress, - decompress, - consttime_fixed_base_scalar_mul, - consttime_variable_base_scalar_mul, - vartime_double_base_scalar_mul, + pub(crate) fn edwards_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("edwards benches"); + + compress(&mut g); + decompress(&mut g); + consttime_fixed_base_scalar_mul(&mut g); + consttime_variable_base_scalar_mul(&mut g); + vartime_double_base_scalar_mul(&mut g); } } @@ -94,14 +85,10 @@ mod multiscalar_benches { fn construct_points(n: usize) -> Vec { let mut rng = thread_rng(); (0..n) - .map(|_| &Scalar::random(&mut rng) * &constants::ED25519_BASEPOINT_TABLE) + .map(|_| EdwardsPoint::mul_base(&Scalar::random(&mut rng))) .collect() } - fn construct(n: usize) -> (Vec, Vec) { - (construct_scalars(n), construct_points(n)) - } - fn consttime_multiscalar_mul(c: &mut BenchmarkGroup) { for multiscalar_size in &MULTISCALAR_SIZES { c.bench_with_input( @@ -153,21 +140,21 @@ mod multiscalar_benches { c.bench_with_input( BenchmarkId::new( "Variable-time fixed-base multiscalar multiplication", - &multiscalar_size, + multiscalar_size, ), &multiscalar_size, move |b, &&total_size| { let static_size = total_size; let static_points = construct_points(static_size); - let precomp = VartimeEdwardsPrecomputation::new(&static_points); + let precomp = VartimeEdwardsPrecomputation::new(static_points); // Rerandomize the scalars for every call to prevent // false timings from better caching (e.g., the CPU // cache lifts exactly the right table entries for the // benchmark into the highest cache levels). b.iter_batched( || construct_scalars(static_size), - |scalars| precomp.vartime_multiscalar_mul(&scalars), + |scalars| precomp.vartime_multiscalar_mul(scalars), BatchSize::SmallInput, ); }, @@ -182,66 +169,59 @@ mod multiscalar_benches { for multiscalar_size in &MULTISCALAR_SIZES { let bench_id = BenchmarkId::new( "Variable-time mixed-base", - format!("(size: {:?}), ({:.0}pct dyn)", multiscalar_size, 100.0 * dynamic_fraction), + format!( + "(size: {:?}), ({:.0}pct dyn)", + multiscalar_size, + 100.0 * dynamic_fraction + ), ); - c.bench_with_input(bench_id, &multiscalar_size, - move |b, &&total_size| { - let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize; - let static_size = total_size - dynamic_size; - - let static_points = construct_points(static_size); - let dynamic_points = construct_points(dynamic_size); - let precomp = VartimeEdwardsPrecomputation::new(&static_points); - // Rerandomize the scalars for every call to prevent - // false timings from better caching (e.g., the CPU - // cache lifts exactly the right table entries for the - // benchmark into the highest cache levels). Timings - // should be independent of points so we don't - // randomize them. - b.iter_batched( - || { - ( - construct_scalars(static_size), - construct_scalars(dynamic_size), - ) - }, - |(static_scalars, dynamic_scalars)| { - precomp.vartime_mixed_multiscalar_mul( - &static_scalars, - &dynamic_scalars, - &dynamic_points, - ) - }, - BatchSize::SmallInput, - ); - }, - ); + c.bench_with_input(bench_id, &multiscalar_size, move |b, &&total_size| { + let dynamic_size = ((total_size as f64) * dynamic_fraction) as usize; + let static_size = total_size - dynamic_size; + + let static_points = construct_points(static_size); + let dynamic_points = construct_points(dynamic_size); + let precomp = VartimeEdwardsPrecomputation::new(static_points); + // Rerandomize the scalars for every call to prevent + // false timings from better caching (e.g., the CPU + // cache lifts exactly the right table entries for the + // benchmark into the highest cache levels). Timings + // should be independent of points so we don't + // randomize them. + b.iter_batched( + || { + ( + construct_scalars(static_size), + construct_scalars(dynamic_size), + ) + }, + |(static_scalars, dynamic_scalars)| { + precomp.vartime_mixed_multiscalar_mul( + &static_scalars, + &dynamic_scalars, + &dynamic_points, + ) + }, + BatchSize::SmallInput, + ); + }); } } - fn multiscalar_multiplications(c: &mut Criterion) { - let mut group: BenchmarkGroup<_> = c.benchmark_group("Multiscalar multiplications"); + pub(crate) fn multiscalar_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("multiscalar benches"); - consttime_multiscalar_mul(&mut group); - vartime_multiscalar_mul(&mut group); - vartime_precomputed_pure_static(&mut group); + consttime_multiscalar_mul(&mut g); + vartime_multiscalar_mul(&mut g); + vartime_precomputed_pure_static(&mut g); let dynamic_fracs = [0.0, 0.2, 0.5]; for frac in dynamic_fracs.iter() { - vartime_precomputed_helper(&mut group, *frac); + vartime_precomputed_helper(&mut g, *frac); } - - group.finish(); - } - - criterion_group! { - name = multiscalar_benches; - // Lower the sample size to run the benchmarks faster - config = Criterion::default().sample_size(15); - targets = - multiscalar_multiplications, } } @@ -249,14 +229,14 @@ mod ristretto_benches { use super::*; use curve25519_dalek::ristretto::RistrettoPoint; - fn compress(c: &mut Criterion) { + fn compress(c: &mut BenchmarkGroup) { c.bench_function("RistrettoPoint compression", |b| { let B = &constants::RISTRETTO_BASEPOINT_POINT; b.iter(|| B.compress()) }); } - fn decompress(c: &mut Criterion) { + fn decompress(c: &mut BenchmarkGroup) { c.bench_function("RistrettoPoint decompression", |b| { let B_comp = &constants::RISTRETTO_BASEPOINT_COMPRESSED; b.iter(|| B_comp.decompress().unwrap()) @@ -279,26 +259,21 @@ mod ristretto_benches { } } - fn double_and_compress_group(c: &mut Criterion) { - let mut group: BenchmarkGroup<_> = c.benchmark_group("double & compress batched"); - double_and_compress_batch(&mut group); - group.finish(); - } + pub(crate) fn ristretto_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("ristretto benches"); - criterion_group! { - name = ristretto_benches; - config = Criterion::default(); - targets = - compress, - decompress, - double_and_compress_group, + compress(&mut g); + decompress(&mut g); + double_and_compress_batch(&mut g); } } mod montgomery_benches { use super::*; + use curve25519_dalek::montgomery::MontgomeryPoint; - fn montgomery_ladder(c: &mut Criterion) { + fn montgomery_ladder(c: &mut BenchmarkGroup) { c.bench_function("Montgomery pseudomultiplication", |b| { let B = constants::X25519_BASEPOINT; let s = Scalar::from(897987897u64).invert(); @@ -306,21 +281,53 @@ mod montgomery_benches { }); } - criterion_group! { - name = montgomery_benches; - config = Criterion::default(); - targets = montgomery_ladder, + fn consttime_fixed_base_scalar_mul(c: &mut BenchmarkGroup) { + let s = Scalar::from(897987897u64).invert(); + c.bench_function("Constant-time fixed-base scalar mul", move |b| { + b.iter(|| MontgomeryPoint::mul_base(&s)) + }); + } + + pub(crate) fn montgomery_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("montgomery benches"); + + montgomery_ladder(&mut g); + consttime_fixed_base_scalar_mul(&mut g); } } mod scalar_benches { use super::*; - fn scalar_inversion(c: &mut Criterion) { + fn scalar_arith(c: &mut BenchmarkGroup) { + let mut rng = thread_rng(); + c.bench_function("Scalar inversion", |b| { let s = Scalar::from(897987897u64).invert(); b.iter(|| s.invert()); }); + c.bench_function("Scalar addition", |b| { + b.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| a + b, + BatchSize::SmallInput, + ); + }); + c.bench_function("Scalar subtraction", |b| { + b.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| a - b, + BatchSize::SmallInput, + ); + }); + c.bench_function("Scalar multiplication", |b| { + b.iter_batched( + || (Scalar::random(&mut rng), Scalar::random(&mut rng)), + |(a, b)| a * b, + BatchSize::SmallInput, + ); + }); } fn batch_scalar_inversion(c: &mut BenchmarkGroup) { @@ -341,18 +348,12 @@ mod scalar_benches { } } - fn batch_scalar_inversion_group(c: &mut Criterion) { - let mut group: BenchmarkGroup<_> = c.benchmark_group("batch scalar inversion"); - batch_scalar_inversion(&mut group); - group.finish(); - } + pub(crate) fn scalar_benches() { + let mut c = Criterion::default(); + let mut g = c.benchmark_group("scalar benches"); - criterion_group! { - name = scalar_benches; - config = Criterion::default(); - targets = - scalar_inversion, - batch_scalar_inversion_group, + scalar_arith(&mut g); + batch_scalar_inversion(&mut g); } } diff --git a/curve25519-dalek/build.rs b/curve25519-dalek/build.rs new file mode 100644 index 000000000..a04f76bd0 --- /dev/null +++ b/curve25519-dalek/build.rs @@ -0,0 +1,145 @@ +//! This selects the curve25519_dalek_bits either by default from target_pointer_width or explicitly set + +#![deny(clippy::unwrap_used, dead_code)] + +use platforms::Platform; +use platforms::target; + +#[allow(non_camel_case_types)] +#[derive(PartialEq, Debug)] +enum DalekBits { + Dalek32, + Dalek64, +} + +//TODO: remove debugging before merging +macro_rules! build_debug { + ($($tokens: tt)*) => { + println!("cargo:warning={}", format!($($tokens)*)) + } +} + +fn main() { + let target_triplet = std::env::var("TARGET").unwrap(); + let platform = platforms::Platform::find(&target_triplet).unwrap(); + let curve25519_dalek_bits = match std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref() { + Ok("32") => DalekBits::Dalek32, + Ok("64") => DalekBits::Dalek64, + _ => deterministic::determine_curve25519_dalek_bits(&target_arch), + }; + build_debug!("CARGO_CFG_CURVE25519_DALEK_BITS: {:?}", std::env::var("CARGO_CFG_CURVE25519_DALEK_BITS").as_deref()); + build_debug!("curve25519_dalek_bits {:?}", curve25519_dalek_bits); + + println!("cargo:rustc-cfg=curve25519_dalek_bits=\"{curve25519_dalek_bits}\""); + + if rustc_version::version_meta() + .expect("failed to detect rustc version") + .channel + == rustc_version::Channel::Nightly + { + println!("cargo:rustc-cfg=nightly"); + } + + let rustc_version = rustc_version::version().expect("failed to detect rustc version"); + if rustc_version.major == 1 && rustc_version.minor <= 64 { + // Old versions of Rust complain when you have an `unsafe fn` and you use `unsafe {}` inside, + // so for those we want to apply the `#[allow(unused_unsafe)]` attribute to get rid of that warning. + println!("cargo:rustc-cfg=allow_unused_unsafe"); + } + + let target_arch = match std::env::var("CARGO_CFG_TARGET_ARCH") { + Ok(arch) => arch, + _ => "".to_string(), + }; + build_debug!("target_arch {}",target_arch); + + // Backend overrides / defaults + let curve25519_dalek_backend = + match std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref() { + Ok("fiat") => "fiat", + Ok("serial") => "serial", + Ok("simd") => { + // simd can only be enabled on x86_64 & 64bit target_pointer_width + match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + // If override is not possible this must result to compile error + // See: issues/532 + false => panic!("Could not override curve25519_dalek_backend to simd"), + } + }, + //coprocessor for Precursor + Ok("u32e_backend") => { + if curve25519_dalek_bits != DalekBits::Dalek32{ + panic!("u32e_backend only supports 32 bit bits"); + } + "u32e_backend" + }, + // default between serial / simd (if potentially capable) + _ => match is_precursor(platform) { + true => "u32e_backend", + false => match is_capable_simd(&target_arch, curve25519_dalek_bits) { + true => "simd", + false => "serial", + }, + } + }; + build_debug!("CARGO_CFG_CURVE25519_DALEK_BACKEND: {:?}", std::env::var("CARGO_CFG_CURVE25519_DALEK_BACKEND").as_deref()); + build_debug!("curve25519_dalek_backend {:?}", curve25519_dalek_backend); + println!("cargo:rustc-cfg=curve25519_dalek_backend=\"{curve25519_dalek_backend}\""); +} + +// Is the target arch & curve25519_dalek_bits potentially simd capable ? +fn is_capable_simd(arch: &str, bits: DalekBits) -> bool { + arch == "x86_64" && bits == DalekBits::Dalek64 +} +// Is the target the Precursor? +fn is_precursor(platform: &Platform) -> bool { + platform.target_os == target::OS::Xous && platform.target_arch == target::Arch::Riscv32 +} + +// Deterministic cfg(curve25519_dalek_bits) when this is not explicitly set. +mod deterministic { + + use super::*; + + // Custom Rust non-cargo build tooling needs to set CARGO_CFG_TARGET_POINTER_WIDTH + static ERR_MSG_NO_POINTER_WIDTH: &str = + "Standard Cargo TARGET_POINTER_WIDTH environment variable is not set."; + + // When either non-32 or 64 TARGET_POINTER_WIDTH detected + static ERR_MSG_UNKNOWN_POINTER_WIDTH: &str = "Unknown TARGET_POINTER_WIDTH detected."; + + // Warning when the curve25519_dalek_bits cannot be determined + fn determine_curve25519_dalek_bits_warning(cause: &str) { + println!("cargo:warning=\"Defaulting to curve25519_dalek_bits=32: {cause}\""); + } + + // Determine the curve25519_dalek_bits based on Rust standard TARGET triplet + pub(super) fn determine_curve25519_dalek_bits(target_arch: &String) -> DalekBits { + let target_pointer_width = match std::env::var("CARGO_CFG_TARGET_POINTER_WIDTH") { + Ok(pw) => pw, + Err(_) => { + determine_curve25519_dalek_bits_warning(ERR_MSG_NO_POINTER_WIDTH); + return DalekBits::Dalek32; + } + }; + + #[allow(clippy::match_single_binding)] + match &target_arch { + //Issues: 449 and 456 + //TODO: When adding arch defaults use proper types not String match + //TODO(Arm): Needs tests + benchmarks to back this up + //TODO(Wasm32): Needs tests + benchmarks to back this up + _ => match target_pointer_width.as_ref() { + "64" => DalekBits::Dalek64, + "32" => DalekBits::Dalek32, + // Intended default solely for non-32/64 target pointer widths + // Otherwise known target platforms only. + _ => { + determine_curve25519_dalek_bits_warning(ERR_MSG_UNKNOWN_POINTER_WIDTH); + DalekBits::Dalek32 + } + }, + } + } +} diff --git a/curve25519-dalek/docs/assets/rustdoc-include-katex-header.html b/curve25519-dalek/docs/assets/rustdoc-include-katex-header.html new file mode 100644 index 000000000..d240432aa --- /dev/null +++ b/curve25519-dalek/docs/assets/rustdoc-include-katex-header.html @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/docs/avx2-notes.md b/curve25519-dalek/docs/avx2-notes.md similarity index 100% rename from docs/avx2-notes.md rename to curve25519-dalek/docs/avx2-notes.md diff --git a/docs/ifma-notes.md b/curve25519-dalek/docs/ifma-notes.md similarity index 99% rename from docs/ifma-notes.md rename to curve25519-dalek/docs/ifma-notes.md index c6fd3b3a8..faf89280a 100644 --- a/docs/ifma-notes.md +++ b/curve25519-dalek/docs/ifma-notes.md @@ -351,7 +351,7 @@ This computation requires 25 `vpmadd52luq` and 25 `vpmadd52huq` operations. For 256-bit vectors, IFMA operations execute on an i3-8121U with latency 4 cycles, throughput 0.5 cycles, so executing 50 instructions requires 25 cycles' worth of throughput. Accumulating -terms with coefficient \\(1\\) and \\(2\\) seperately means that the +terms with coefficient \\(1\\) and \\(2\\) separately means that the longest dependency chain has length 5, so the critical path has length 20 cycles and the bottleneck is throughput. diff --git a/docs/parallel-formulas.md b/curve25519-dalek/docs/parallel-formulas.md similarity index 97% rename from docs/parallel-formulas.md rename to curve25519-dalek/docs/parallel-formulas.md index f84d1ccd4..70aadc38c 100644 --- a/docs/parallel-formulas.md +++ b/curve25519-dalek/docs/parallel-formulas.md @@ -145,16 +145,16 @@ This costs \\( 2\mathbf M + 1 \mathbf D\\). ## Readdition -If the point \\( P_2 = (X\_2 : Y\_2 : Z\_2 : T\_2) \\) is fixed, we +If the point \\( P\_2 = (X\_2 : Y\_2 : Z\_2 : T\_2) \\) is fixed, we can cache the multiplication of the curve constants by computing $$ \begin{aligned} -(S\_2' &&,&& S\_3' &&,&& Z\_2' &&,&& T\_2' ) +(S\_2\' &&,&& S\_3\' &&,&& Z\_2\' &&,&& T\_2\' ) &\gets (d\_2 \cdot (Y\_2 - X\_2)&&,&& d\_2 \cdot (Y\_1 + X\_1)&&,&& 2d\_2 \cdot Z\_2 &&,&& 2d\_1 \cdot T\_2). \end{aligned} $$ -This costs \\( 1\mathbf D\\); with \\( (S\_2', S\_3', Z\_2', T\_2')\\) +This costs \\( 1\mathbf D\\); with \\( (S\_2\', S\_3\', Z\_2\', T\_2\')\\) in hand, the addition formulas above become $$ \begin{aligned} @@ -164,7 +164,7 @@ $$ \\\\ (S\_8 &&,&& S\_9 &&,&& S\_{10} &&,&& S\_{11} ) &\gets -(S\_0 \cdot S\_2' &&,&& S\_1 \cdot S\_3'&&,&& Z\_1 \cdot Z\_2' &&,&& T\_1 \cdot T\_2') +(S\_0 \cdot S\_2\' &&,&& S\_1 \cdot S\_3\'&&,&& Z\_1 \cdot Z\_2\' &&,&& T\_1 \cdot T\_2\') \\\\ (S\_{12} &&,&& S\_{13} &&,&& S\_{14} &&,&& S\_{15}) &\gets @@ -207,7 +207,7 @@ $$ (S\_8 \cdot S\_9 &&,&& S\_5 \cdot S\_6 &&,&& S\_8 \cdot S\_6 &&,&& S\_5 \cdot S\_9) \end{aligned} $$ -to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = [2]P\_1 \\). +to obtain \\( P\_3 = (X\_3 : Y\_3 : Z\_3 : T\_3) = \[2\]P\_1 \\). The intermediate step between the squaring and multiplication requires a long chain of additions. For the IFMA-based implementation, this is not a problem; for the AVX2-based implementation, it is, but with some care and finesse, it's possible to arrange the computation without requiring an intermediate reduction. @@ -327,7 +327,7 @@ There are several directions for future improvement: [sandy2x]: https://eprint.iacr.org/2015/943.pdf [avx2trac]: https://trac.torproject.org/projects/tor/ticket/8897#comment:28 [hwcd08]: https://www.iacr.org/archive/asiacrypt2008/53500329/53500329.pdf -[curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html +[curve_models]: https://docs.rs/curve25519-dalek/latest/curve25519-dalek/backend/serial/curve_models/index.html [bbjlp08]: https://eprint.iacr.org/2008/013 [cmo98]: https://link.springer.com/content/pdf/10.1007%2F3-540-49649-1_6.pdf [intel]: https://software.intel.com/sites/default/files/managed/9e/bc/64-ia-32-architectures-optimization-manual.pdf diff --git a/curve25519-dalek/src/backend/mod.rs b/curve25519-dalek/src/backend/mod.rs new file mode 100644 index 000000000..9ad1dd3de --- /dev/null +++ b/curve25519-dalek/src/backend/mod.rs @@ -0,0 +1,251 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! **INTERNALS:** Pluggable implementations for different architectures. +//! +//! The backend code is split into two parts: a serial backend, +//! and a vector backend. +//! +//! The [`serial`] backend contains 32- and 64-bit implementations of +//! field arithmetic and scalar arithmetic, as well as implementations +//! of point operations using the mixed-model strategy (passing +//! between different curve models depending on the operation). +//! +//! The [`vector`] backend contains implementations of vectorized +//! field arithmetic, used to implement point operations using a novel +//! implementation strategy derived from parallel formulas of Hisil, +//! Wong, Carter, and Dawson. +//! +//! Because the two strategies give rise to different curve models, +//! it's not possible to reuse exactly the same scalar multiplication +//! code (or to write it generically), so both serial and vector +//! backends contain matching implementations of scalar multiplication +//! algorithms. These are intended to be selected by a `#[cfg]`-based +//! type alias. +//! +//! The [`vector`] backend is selected by the `simd_backend` cargo +//! feature; it uses the [`serial`] backend for non-vectorized operations. + +use crate::EdwardsPoint; +use crate::Scalar; + +pub mod serial; + +#[cfg(curve25519_dalek_backend = "simd")] +pub mod vector; + +#[derive(Copy, Clone)] +enum BackendKind { + #[cfg(curve25519_dalek_backend = "simd")] + Avx2, + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + Avx512, + Serial, +} + +#[inline] +fn get_selected_backend() -> BackendKind { + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + { + cpufeatures::new!(cpuid_avx512, "avx512ifma", "avx512vl"); + let token_avx512: cpuid_avx512::InitToken = cpuid_avx512::init(); + if token_avx512.get() { + return BackendKind::Avx512; + } + } + + #[cfg(curve25519_dalek_backend = "simd")] + { + cpufeatures::new!(cpuid_avx2, "avx2"); + let token_avx2: cpuid_avx2::InitToken = cpuid_avx2::init(); + if token_avx2.get() { + return BackendKind::Avx2; + } + } + + BackendKind::Serial +} + +#[allow(missing_docs)] +#[cfg(feature = "alloc")] +pub fn pippenger_optional_multiscalar_mul(scalars: I, points: J) -> Option +where + I: IntoIterator, + I::Item: core::borrow::Borrow, + J: IntoIterator>, +{ + use crate::traits::VartimeMultiscalarMul; + + match get_selected_backend() { + #[cfg(curve25519_dalek_backend = "simd")] + BackendKind::Avx2 => + vector::scalar_mul::pippenger::spec_avx2::Pippenger::optional_multiscalar_mul::(scalars, points), + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + BackendKind::Avx512 => + vector::scalar_mul::pippenger::spec_avx512ifma_avx512vl::Pippenger::optional_multiscalar_mul::(scalars, points), + BackendKind::Serial => + serial::scalar_mul::pippenger::Pippenger::optional_multiscalar_mul::(scalars, points), + } +} + +#[cfg(feature = "alloc")] +pub(crate) enum VartimePrecomputedStraus { + #[cfg(curve25519_dalek_backend = "simd")] + Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus), + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + Avx512ifma( + vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus, + ), + Scalar(serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus), +} + +#[cfg(feature = "alloc")] +impl VartimePrecomputedStraus { + pub fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: core::borrow::Borrow, + { + use crate::traits::VartimePrecomputedMultiscalarMul; + + match get_selected_backend() { + #[cfg(curve25519_dalek_backend = "simd")] + BackendKind::Avx2 => + VartimePrecomputedStraus::Avx2(vector::scalar_mul::precomputed_straus::spec_avx2::VartimePrecomputedStraus::new(static_points)), + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + BackendKind::Avx512 => + VartimePrecomputedStraus::Avx512ifma(vector::scalar_mul::precomputed_straus::spec_avx512ifma_avx512vl::VartimePrecomputedStraus::new(static_points)), + BackendKind::Serial => + VartimePrecomputedStraus::Scalar(serial::scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) + } + } + + pub fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: core::borrow::Borrow, + J: IntoIterator, + J::Item: core::borrow::Borrow, + K: IntoIterator>, + { + use crate::traits::VartimePrecomputedMultiscalarMul; + + match self { + #[cfg(curve25519_dalek_backend = "simd")] + VartimePrecomputedStraus::Avx2(inner) => inner.optional_mixed_multiscalar_mul( + static_scalars, + dynamic_scalars, + dynamic_points, + ), + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + VartimePrecomputedStraus::Avx512ifma(inner) => inner.optional_mixed_multiscalar_mul( + static_scalars, + dynamic_scalars, + dynamic_points, + ), + VartimePrecomputedStraus::Scalar(inner) => inner.optional_mixed_multiscalar_mul( + static_scalars, + dynamic_scalars, + dynamic_points, + ), + } + } +} + +#[allow(missing_docs)] +#[cfg(feature = "alloc")] +pub fn straus_multiscalar_mul(scalars: I, points: J) -> EdwardsPoint +where + I: IntoIterator, + I::Item: core::borrow::Borrow, + J: IntoIterator, + J::Item: core::borrow::Borrow, +{ + use crate::traits::MultiscalarMul; + + match get_selected_backend() { + #[cfg(curve25519_dalek_backend = "simd")] + BackendKind::Avx2 => { + vector::scalar_mul::straus::spec_avx2::Straus::multiscalar_mul::(scalars, points) + } + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + BackendKind::Avx512 => { + vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::multiscalar_mul::( + scalars, points, + ) + } + BackendKind::Serial => { + serial::scalar_mul::straus::Straus::multiscalar_mul::(scalars, points) + } + } +} + +#[allow(missing_docs)] +#[cfg(feature = "alloc")] +pub fn straus_optional_multiscalar_mul(scalars: I, points: J) -> Option +where + I: IntoIterator, + I::Item: core::borrow::Borrow, + J: IntoIterator>, +{ + use crate::traits::VartimeMultiscalarMul; + + match get_selected_backend() { + #[cfg(curve25519_dalek_backend = "simd")] + BackendKind::Avx2 => { + vector::scalar_mul::straus::spec_avx2::Straus::optional_multiscalar_mul::( + scalars, points, + ) + } + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + BackendKind::Avx512 => { + vector::scalar_mul::straus::spec_avx512ifma_avx512vl::Straus::optional_multiscalar_mul::< + I, + J, + >(scalars, points) + } + BackendKind::Serial => { + serial::scalar_mul::straus::Straus::optional_multiscalar_mul::(scalars, points) + } + } +} + +/// Perform constant-time, variable-base scalar multiplication. +pub fn variable_base_mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + match get_selected_backend() { + #[cfg(curve25519_dalek_backend = "simd")] + BackendKind::Avx2 => vector::scalar_mul::variable_base::spec_avx2::mul(point, scalar), + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + BackendKind::Avx512 => { + vector::scalar_mul::variable_base::spec_avx512ifma_avx512vl::mul(point, scalar) + } + BackendKind::Serial => serial::scalar_mul::variable_base::mul(point, scalar), + } +} + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +#[allow(non_snake_case)] +pub fn vartime_double_base_mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + match get_selected_backend() { + #[cfg(curve25519_dalek_backend = "simd")] + BackendKind::Avx2 => vector::scalar_mul::vartime_double_base::spec_avx2::mul(a, A, b), + #[cfg(all(curve25519_dalek_backend = "simd", nightly))] + BackendKind::Avx512 => { + vector::scalar_mul::vartime_double_base::spec_avx512ifma_avx512vl::mul(a, A, b) + } + BackendKind::Serial => serial::scalar_mul::vartime_double_base::mul(a, A, b), + } +} diff --git a/src/backend/serial/curve_models/mod.rs b/curve25519-dalek/src/backend/serial/curve_models/mod.rs similarity index 82% rename from src/backend/serial/curve_models/mod.rs rename to curve25519-dalek/src/backend/serial/curve_models/mod.rs index 9d10d9221..1343d3706 100644 --- a/src/backend/serial/curve_models/mod.rs +++ b/curve25519-dalek/src/backend/serial/curve_models/mod.rs @@ -129,13 +129,14 @@ use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; -use constants; +use crate::constants; -use edwards::EdwardsPoint; -use field::FieldElement; -use traits::ValidityCheck; +use crate::edwards::EdwardsPoint; +use crate::field::FieldElement; +use crate::traits::ValidityCheck; // ------------------------------------------------------------------------ // Internal point representations @@ -148,6 +149,7 @@ use traits::ValidityCheck; /// /// More details on the relationships between the different curve models /// can be found in the module-level documentation. +#[allow(missing_docs)] #[derive(Copy, Clone)] pub struct ProjectivePoint { pub X: FieldElement, @@ -180,11 +182,12 @@ pub struct CompletedPoint { #[derive(Copy, Clone, Eq, PartialEq)] #[allow(missing_docs)] pub struct AffineNielsPoint { - pub y_plus_x: FieldElement, + pub y_plus_x: FieldElement, pub y_minus_x: FieldElement, - pub xy2d: FieldElement, + pub xy2d: FieldElement, } +#[cfg(feature = "zeroize")] impl Zeroize for AffineNielsPoint { fn zeroize(&mut self) { self.y_plus_x.zeroize(); @@ -199,13 +202,15 @@ impl Zeroize for AffineNielsPoint { /// More details on the relationships between the different curve models /// can be found in the module-level documentation. #[derive(Copy, Clone)] +#[allow(missing_docs)] pub struct ProjectiveNielsPoint { - pub Y_plus_X: FieldElement, + pub Y_plus_X: FieldElement, pub Y_minus_X: FieldElement, - pub Z: FieldElement, - pub T2d: FieldElement, + pub Z: FieldElement, + pub T2d: FieldElement, } +#[cfg(feature = "zeroize")] impl Zeroize for ProjectiveNielsPoint { fn zeroize(&mut self) { self.Y_plus_X.zeroize(); @@ -219,25 +224,25 @@ impl Zeroize for ProjectiveNielsPoint { // Constructors // ------------------------------------------------------------------------ -use traits::Identity; +use crate::traits::Identity; impl Identity for ProjectivePoint { fn identity() -> ProjectivePoint { ProjectivePoint { - X: FieldElement::zero(), - Y: FieldElement::one(), - Z: FieldElement::one(), + X: FieldElement::ZERO, + Y: FieldElement::ONE, + Z: FieldElement::ONE, } } } impl Identity for ProjectiveNielsPoint { fn identity() -> ProjectiveNielsPoint { - ProjectiveNielsPoint{ - Y_plus_X: FieldElement::one(), - Y_minus_X: FieldElement::one(), - Z: FieldElement::one(), - T2d: FieldElement::zero(), + ProjectiveNielsPoint { + Y_plus_X: FieldElement::ONE, + Y_minus_X: FieldElement::ONE, + Z: FieldElement::ONE, + T2d: FieldElement::ZERO, } } } @@ -250,10 +255,10 @@ impl Default for ProjectiveNielsPoint { impl Identity for AffineNielsPoint { fn identity() -> AffineNielsPoint { - AffineNielsPoint{ - y_plus_x: FieldElement::one(), - y_minus_x: FieldElement::one(), - xy2d: FieldElement::zero(), + AffineNielsPoint { + y_plus_x: FieldElement::ONE, + y_minus_x: FieldElement::ONE, + xy2d: FieldElement::ZERO, } } } @@ -330,7 +335,7 @@ impl ProjectivePoint { /// \\( \mathbb P\^3 \\) model. /// /// This costs \\(3 \mathrm M + 1 \mathrm S\\). - pub fn to_extended(&self) -> EdwardsPoint { + pub fn as_extended(&self) -> EdwardsPoint { EdwardsPoint { X: &self.X * &self.Z, Y: &self.Y * &self.Z, @@ -345,7 +350,7 @@ impl CompletedPoint { /// \\) model to the \\( \mathbb P\^2 \\) model. /// /// This costs \\(3 \mathrm M \\). - pub fn to_projective(&self) -> ProjectivePoint { + pub fn as_projective(&self) -> ProjectivePoint { ProjectivePoint { X: &self.X * &self.T, Y: &self.Y * &self.Z, @@ -357,7 +362,7 @@ impl CompletedPoint { /// \\) model to the \\( \mathbb P\^3 \\) model. /// /// This costs \\(4 \mathrm M \\). - pub fn to_extended(&self) -> EdwardsPoint { + pub fn as_extended(&self) -> EdwardsPoint { EdwardsPoint { X: &self.X * &self.T, Y: &self.Y * &self.Z, @@ -373,20 +378,21 @@ impl CompletedPoint { impl ProjectivePoint { /// Double this point: return self + self - pub fn double(&self) -> CompletedPoint { // Double() - let XX = self.X.square(); - let YY = self.Y.square(); - let ZZ2 = self.Z.square2(); - let X_plus_Y = &self.X + &self.Y; + pub fn double(&self) -> CompletedPoint { + // Double() + let XX = self.X.square(); + let YY = self.Y.square(); + let ZZ2 = self.Z.square2(); + let X_plus_Y = &self.X + &self.Y; let X_plus_Y_sq = X_plus_Y.square(); - let YY_plus_XX = &YY + &XX; + let YY_plus_XX = &YY + &XX; let YY_minus_XX = &YY - &XX; - CompletedPoint{ + CompletedPoint { X: &X_plus_Y_sq - &YY_plus_XX, Y: YY_plus_XX, Z: YY_minus_XX, - T: &ZZ2 - &YY_minus_XX + T: &ZZ2 - &YY_minus_XX, } } } @@ -406,19 +412,19 @@ impl<'a, 'b> Add<&'b ProjectiveNielsPoint> for &'a EdwardsPoint { type Output = CompletedPoint; fn add(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { - let Y_plus_X = &self.Y + &self.X; + let Y_plus_X = &self.Y + &self.X; let Y_minus_X = &self.Y - &self.X; - let PP = &Y_plus_X * &other.Y_plus_X; + let PP = &Y_plus_X * &other.Y_plus_X; let MM = &Y_minus_X * &other.Y_minus_X; let TT2d = &self.T * &other.T2d; - let ZZ = &self.Z * &other.Z; - let ZZ2 = &ZZ + &ZZ; + let ZZ = &self.Z * &other.Z; + let ZZ2 = &ZZ + &ZZ; - CompletedPoint{ + CompletedPoint { X: &PP - &MM, Y: &PP + &MM, Z: &ZZ2 + &TT2d, - T: &ZZ2 - &TT2d + T: &ZZ2 - &TT2d, } } } @@ -428,19 +434,19 @@ impl<'a, 'b> Sub<&'b ProjectiveNielsPoint> for &'a EdwardsPoint { type Output = CompletedPoint; fn sub(self, other: &'b ProjectiveNielsPoint) -> CompletedPoint { - let Y_plus_X = &self.Y + &self.X; + let Y_plus_X = &self.Y + &self.X; let Y_minus_X = &self.Y - &self.X; let PM = &Y_plus_X * &other.Y_minus_X; - let MP = &Y_minus_X * &other.Y_plus_X; + let MP = &Y_minus_X * &other.Y_plus_X; let TT2d = &self.T * &other.T2d; - let ZZ = &self.Z * &other.Z; - let ZZ2 = &ZZ + &ZZ; + let ZZ = &self.Z * &other.Z; + let ZZ2 = &ZZ + &ZZ; - CompletedPoint{ + CompletedPoint { X: &PM - &MP, Y: &PM + &MP, Z: &ZZ2 - &TT2d, - T: &ZZ2 + &TT2d + T: &ZZ2 + &TT2d, } } } @@ -450,18 +456,18 @@ impl<'a, 'b> Add<&'b AffineNielsPoint> for &'a EdwardsPoint { type Output = CompletedPoint; fn add(self, other: &'b AffineNielsPoint) -> CompletedPoint { - let Y_plus_X = &self.Y + &self.X; + let Y_plus_X = &self.Y + &self.X; let Y_minus_X = &self.Y - &self.X; - let PP = &Y_plus_X * &other.y_plus_x; - let MM = &Y_minus_X * &other.y_minus_x; - let Txy2d = &self.T * &other.xy2d; - let Z2 = &self.Z + &self.Z; + let PP = &Y_plus_X * &other.y_plus_x; + let MM = &Y_minus_X * &other.y_minus_x; + let Txy2d = &self.T * &other.xy2d; + let Z2 = &self.Z + &self.Z; - CompletedPoint{ + CompletedPoint { X: &PP - &MM, Y: &PP + &MM, Z: &Z2 + &Txy2d, - T: &Z2 - &Txy2d + T: &Z2 - &Txy2d, } } } @@ -471,18 +477,18 @@ impl<'a, 'b> Sub<&'b AffineNielsPoint> for &'a EdwardsPoint { type Output = CompletedPoint; fn sub(self, other: &'b AffineNielsPoint) -> CompletedPoint { - let Y_plus_X = &self.Y + &self.X; + let Y_plus_X = &self.Y + &self.X; let Y_minus_X = &self.Y - &self.X; - let PM = &Y_plus_X * &other.y_minus_x; - let MP = &Y_minus_X * &other.y_plus_x; - let Txy2d = &self.T * &other.xy2d; - let Z2 = &self.Z + &self.Z; + let PM = &Y_plus_X * &other.y_minus_x; + let MP = &Y_minus_X * &other.y_plus_x; + let Txy2d = &self.T * &other.xy2d; + let Z2 = &self.Z + &self.Z; - CompletedPoint{ + CompletedPoint { X: &PM - &MP, Y: &PM + &MP, Z: &Z2 - &Txy2d, - T: &Z2 + &Txy2d + T: &Z2 + &Txy2d, } } } @@ -495,11 +501,11 @@ impl<'a> Neg for &'a ProjectiveNielsPoint { type Output = ProjectiveNielsPoint; fn neg(self) -> ProjectiveNielsPoint { - ProjectiveNielsPoint{ - Y_plus_X: self.Y_minus_X, - Y_minus_X: self.Y_plus_X, - Z: self.Z, - T2d: -(&self.T2d), + ProjectiveNielsPoint { + Y_plus_X: self.Y_minus_X, + Y_minus_X: self.Y_plus_X, + Z: self.Z, + T2d: -(&self.T2d), } } } @@ -508,10 +514,10 @@ impl<'a> Neg for &'a AffineNielsPoint { type Output = AffineNielsPoint; fn neg(self) -> AffineNielsPoint { - AffineNielsPoint{ - y_plus_x: self.y_minus_x, - y_minus_x: self.y_plus_x, - xy2d: -(&self.xy2d) + AffineNielsPoint { + y_plus_x: self.y_minus_x, + y_minus_x: self.y_plus_x, + xy2d: -(&self.xy2d), } } } @@ -521,31 +527,38 @@ impl<'a> Neg for &'a AffineNielsPoint { // ------------------------------------------------------------------------ impl Debug for ProjectivePoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}", - &self.X, &self.Y, &self.Z) + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "ProjectivePoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?}\n}}", + &self.X, &self.Y, &self.Z + ) } } impl Debug for CompletedPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", - &self.X, &self.Y, &self.Z, &self.T) + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "CompletedPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", + &self.X, &self.Y, &self.Z, &self.T + ) } } impl Debug for AffineNielsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}", - &self.y_plus_x, &self.y_minus_x, &self.xy2d) + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "AffineNielsPoint{{\n\ty_plus_x: {:?},\n\ty_minus_x: {:?},\n\txy2d: {:?}\n}}", + &self.y_plus_x, &self.y_minus_x, &self.xy2d + ) } } impl Debug for ProjectiveNielsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "ProjectiveNielsPoint{{\n\tY_plus_X: {:?},\n\tY_minus_X: {:?},\n\tZ: {:?},\n\tT2d: {:?}\n}}", &self.Y_plus_X, &self.Y_minus_X, &self.Z, &self.T2d) } } - - diff --git a/src/backend/serial/fiat_u32/field.rs b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs similarity index 60% rename from src/backend/serial/fiat_u32/field.rs rename to curve25519-dalek/src/backend/serial/fiat_u32/field.rs index 2864c955e..97695c383 100644 --- a/src/backend/serial/fiat_u32/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u32/field.rs @@ -27,6 +27,7 @@ use core::ops::{Sub, SubAssign}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use fiat_crypto::curve25519_32::*; @@ -54,72 +55,78 @@ use fiat_crypto::curve25519_32::*; /// The backend-specific type `FieldElement2625` should not be used /// outside of the `curve25519_dalek::field` module. #[derive(Copy, Clone)] -pub struct FieldElement2625(pub(crate) [u32; 10]); +pub struct FieldElement2625(pub(crate) fiat_25519_tight_field_element); impl Debug for FieldElement2625 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "FieldElement2625({:?})", &self.0[..]) + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "FieldElement2625({:?})", &(self.0).0[..]) } } +#[cfg(feature = "zeroize")] impl Zeroize for FieldElement2625 { fn zeroize(&mut self) { - self.0.zeroize(); + (self.0).0.zeroize(); } } impl<'b> AddAssign<&'b FieldElement2625> for FieldElement2625 { - fn add_assign(&mut self, _rhs: &'b FieldElement2625) { - let input = self.0; - fiat_25519_add(&mut self.0, &input, &_rhs.0); - let input = self.0; - fiat_25519_carry(&mut self.0, &input); + fn add_assign(&mut self, rhs: &'b FieldElement2625) { + let mut result_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_add(&mut result_loose, &self.0, &rhs.0); + fiat_25519_carry(&mut self.0, &result_loose); } } impl<'a, 'b> Add<&'b FieldElement2625> for &'a FieldElement2625 { type Output = FieldElement2625; - fn add(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { - let mut output = *self; - fiat_25519_add(&mut output.0, &self.0, &_rhs.0); - let input = output.0; - fiat_25519_carry(&mut output.0, &input); + fn add(self, rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut result_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_add(&mut result_loose, &self.0, &rhs.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry(&mut output.0, &result_loose); output } } impl<'b> SubAssign<&'b FieldElement2625> for FieldElement2625 { - fn sub_assign(&mut self, _rhs: &'b FieldElement2625) { - let input = self.0; - fiat_25519_sub(&mut self.0, &input, &_rhs.0); - let input = self.0; - fiat_25519_carry(&mut self.0, &input); + fn sub_assign(&mut self, rhs: &'b FieldElement2625) { + let mut result_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_sub(&mut result_loose, &self.0, &rhs.0); + fiat_25519_carry(&mut self.0, &result_loose); } } impl<'a, 'b> Sub<&'b FieldElement2625> for &'a FieldElement2625 { type Output = FieldElement2625; - fn sub(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { - let mut output = *self; - fiat_25519_sub(&mut output.0, &self.0, &_rhs.0); - let input = output.0; - fiat_25519_carry(&mut output.0, &input); + fn sub(self, rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut result_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_sub(&mut result_loose, &self.0, &rhs.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry(&mut output.0, &result_loose); output } } impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 { - fn mul_assign(&mut self, _rhs: &'b FieldElement2625) { - let input = self.0; - fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0); + fn mul_assign(&mut self, rhs: &'b FieldElement2625) { + let mut self_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut rhs_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut rhs_loose, &rhs.0); + fiat_25519_carry_mul(&mut self.0, &self_loose, &rhs_loose); } } impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { type Output = FieldElement2625; - fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { - let mut output = *self; - fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0); + fn mul(self, rhs: &'b FieldElement2625) -> FieldElement2625 { + let mut self_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut rhs_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut rhs_loose, &rhs.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry_mul(&mut output.0, &self_loose, &rhs_loose); output } } @@ -127,10 +134,10 @@ impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { impl<'a> Neg for &'a FieldElement2625 { type Output = FieldElement2625; fn neg(self) -> FieldElement2625 { - let mut output = *self; - fiat_25519_opp(&mut output.0, &self.0); - let input = output.0; - fiat_25519_carry(&mut output.0, &input); + let mut output_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_opp(&mut output_loose, &self.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry(&mut output.0, &output_loose); output } } @@ -141,8 +148,13 @@ impl ConditionallySelectable for FieldElement2625 { b: &FieldElement2625, choice: Choice, ) -> FieldElement2625 { - let mut output = [0u32; 10]; - fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0); + let mut output = fiat_25519_tight_field_element([0u32; 10]); + fiat_25519_selectznz( + &mut output.0, + choice.unwrap_u8() as fiat_25519_u1, + &(a.0).0, + &(b.0).0, + ); FieldElement2625(output) } @@ -159,7 +171,7 @@ impl ConditionallySelectable for FieldElement2625 { fiat_25519_cmovznz_u32(&mut output[7], choicebit, self.0[7], other.0[7]); fiat_25519_cmovznz_u32(&mut output[8], choicebit, self.0[8], other.0[8]); fiat_25519_cmovznz_u32(&mut output[9], choicebit, self.0[9], other.0[9]); - *self = FieldElement2625(output); + *self = FieldElement2625::from_limbs(output); } fn conditional_swap(a: &mut FieldElement2625, b: &mut FieldElement2625, choice: Choice) { @@ -177,30 +189,26 @@ impl ConditionallySelectable for FieldElement2625 { } impl FieldElement2625 { + pub(crate) const fn from_limbs(limbs: [u32; 10]) -> FieldElement2625 { + FieldElement2625(fiat_25519_tight_field_element(limbs)) + } + + /// The scalar \\( 0 \\). + pub const ZERO: FieldElement2625 = FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// The scalar \\( 1 \\). + pub const ONE: FieldElement2625 = FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// The scalar \\( -1 \\). + pub const MINUS_ONE: FieldElement2625 = FieldElement2625::from_limbs([ + 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, + 0x3ffffff, 0x1ffffff, + ]); + /// Invert the sign of this field element pub fn negate(&mut self) { let neg = self.neg(); self.0 = neg.0; } - /// Construct zero. - pub fn zero() -> FieldElement2625 { - FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - } - - /// Construct one. - pub fn one() -> FieldElement2625 { - FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - } - - /// Construct -1. - pub fn minus_one() -> FieldElement2625 { - FieldElement2625([ - 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, - 0x3ffffff, 0x1ffffff, - ]) - } - /// Given `k > 0`, return `self^(2^k)`. pub fn pow2k(&self, k: u32) -> FieldElement2625 { debug_assert!(k > 0); @@ -226,35 +234,38 @@ impl FieldElement2625 { let mut temp = [0u8; 32]; temp.copy_from_slice(data); temp[31] &= 127u8; - let mut output = [0u32; 10]; + let mut output = fiat_25519_tight_field_element([0u32; 10]); fiat_25519_from_bytes(&mut output, &temp); FieldElement2625(output) } /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { + pub fn as_bytes(&self) -> [u8; 32] { let mut bytes = [0u8; 32]; fiat_25519_to_bytes(&mut bytes, &self.0); - return bytes; + bytes } /// Compute `self^2`. pub fn square(&self) -> FieldElement2625 { - let mut output = *self; - fiat_25519_carry_square(&mut output.0, &self.0); + let mut self_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry_square(&mut output.0, &self_loose); output } /// Compute `2*self^2`. pub fn square2(&self) -> FieldElement2625 { - let mut output = *self; - let mut temp = *self; - // Void vs return type, measure cost of copying self - fiat_25519_carry_square(&mut temp.0, &self.0); - fiat_25519_add(&mut output.0, &temp.0, &temp.0); - let input = output.0; - fiat_25519_carry(&mut output.0, &input); + let mut self_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut square = fiat_25519_tight_field_element([0; 10]); + fiat_25519_carry_square(&mut square, &self_loose); + let mut output_loose = fiat_25519_loose_field_element([0; 10]); + fiat_25519_add(&mut output_loose, &square, &square); + let mut output = FieldElement2625::ZERO; + fiat_25519_carry(&mut output.0, &output_loose); output } } diff --git a/src/backend/serial/fiat_u32/mod.rs b/curve25519-dalek/src/backend/serial/fiat_u32/mod.rs similarity index 100% rename from src/backend/serial/fiat_u32/mod.rs rename to curve25519-dalek/src/backend/serial/fiat_u32/mod.rs diff --git a/src/backend/serial/fiat_u64/field.rs b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs similarity index 52% rename from src/backend/serial/fiat_u64/field.rs rename to curve25519-dalek/src/backend/serial/fiat_u64/field.rs index 7e381b6c4..2a022e23e 100644 --- a/src/backend/serial/fiat_u64/field.rs +++ b/curve25519-dalek/src/backend/serial/fiat_u64/field.rs @@ -23,6 +23,7 @@ use core::ops::{Sub, SubAssign}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; use fiat_crypto::curve25519_64::*; @@ -43,72 +44,78 @@ use fiat_crypto::curve25519_64::*; /// The backend-specific type `FieldElement51` should not be used /// outside of the `curve25519_dalek::field` module. #[derive(Copy, Clone)] -pub struct FieldElement51(pub(crate) [u64; 5]); +pub struct FieldElement51(pub(crate) fiat_25519_tight_field_element); impl Debug for FieldElement51 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "FieldElement51({:?})", &self.0[..]) + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "FieldElement51({:?})", &(self.0).0[..]) } } +#[cfg(feature = "zeroize")] impl Zeroize for FieldElement51 { fn zeroize(&mut self) { - self.0.zeroize(); + (self.0).0.zeroize(); } } impl<'b> AddAssign<&'b FieldElement51> for FieldElement51 { - fn add_assign(&mut self, _rhs: &'b FieldElement51) { - let input = self.0; - fiat_25519_add(&mut self.0, &input, &_rhs.0); - let input = self.0; - fiat_25519_carry(&mut self.0, &input); + fn add_assign(&mut self, rhs: &'b FieldElement51) { + let mut result_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_add(&mut result_loose, &self.0, &rhs.0); + fiat_25519_carry(&mut self.0, &result_loose); } } impl<'a, 'b> Add<&'b FieldElement51> for &'a FieldElement51 { type Output = FieldElement51; - fn add(self, _rhs: &'b FieldElement51) -> FieldElement51 { - let mut output = *self; - fiat_25519_add(&mut output.0, &self.0, &_rhs.0); - let input = output.0; - fiat_25519_carry(&mut output.0, &input); + fn add(self, rhs: &'b FieldElement51) -> FieldElement51 { + let mut result_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_add(&mut result_loose, &self.0, &rhs.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry(&mut output.0, &result_loose); output } } impl<'b> SubAssign<&'b FieldElement51> for FieldElement51 { - fn sub_assign(&mut self, _rhs: &'b FieldElement51) { - let input = self.0; - fiat_25519_sub(&mut self.0, &input, &_rhs.0); - let input = self.0; - fiat_25519_carry(&mut self.0, &input); + fn sub_assign(&mut self, rhs: &'b FieldElement51) { + let mut result_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_sub(&mut result_loose, &self.0, &rhs.0); + fiat_25519_carry(&mut self.0, &result_loose); } } impl<'a, 'b> Sub<&'b FieldElement51> for &'a FieldElement51 { type Output = FieldElement51; - fn sub(self, _rhs: &'b FieldElement51) -> FieldElement51 { - let mut output = *self; - fiat_25519_sub(&mut output.0, &self.0, &_rhs.0); - let input = output.0; - fiat_25519_carry(&mut output.0, &input); + fn sub(self, rhs: &'b FieldElement51) -> FieldElement51 { + let mut result_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_sub(&mut result_loose, &self.0, &rhs.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry(&mut output.0, &result_loose); output } } impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 { - fn mul_assign(&mut self, _rhs: &'b FieldElement51) { - let input = self.0; - fiat_25519_carry_mul(&mut self.0, &input, &_rhs.0); + fn mul_assign(&mut self, rhs: &'b FieldElement51) { + let mut self_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut rhs_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut rhs_loose, &rhs.0); + fiat_25519_carry_mul(&mut self.0, &self_loose, &rhs_loose); } } impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { type Output = FieldElement51; - fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 { - let mut output = *self; - fiat_25519_carry_mul(&mut output.0, &self.0, &_rhs.0); + fn mul(self, rhs: &'b FieldElement51) -> FieldElement51 { + let mut self_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut rhs_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut rhs_loose, &rhs.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry_mul(&mut output.0, &self_loose, &rhs_loose); output } } @@ -116,10 +123,10 @@ impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { impl<'a> Neg for &'a FieldElement51 { type Output = FieldElement51; fn neg(self) -> FieldElement51 { - let mut output = *self; - fiat_25519_opp(&mut output.0, &self.0); - let input = output.0; - fiat_25519_carry(&mut output.0, &input); + let mut output_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_opp(&mut output_loose, &self.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry(&mut output.0, &output_loose); output } } @@ -130,8 +137,13 @@ impl ConditionallySelectable for FieldElement51 { b: &FieldElement51, choice: Choice, ) -> FieldElement51 { - let mut output = [0u64; 5]; - fiat_25519_selectznz(&mut output, choice.unwrap_u8() as fiat_25519_u1, &a.0, &b.0); + let mut output = fiat_25519_tight_field_element([0u64; 5]); + fiat_25519_selectznz( + &mut output.0, + choice.unwrap_u8() as fiat_25519_u1, + &(a.0).0, + &(b.0).0, + ); FieldElement51(output) } @@ -143,47 +155,44 @@ impl ConditionallySelectable for FieldElement51 { u64::conditional_swap(&mut a.0[4], &mut b.0[4], choice); } - fn conditional_assign(&mut self, _rhs: &FieldElement51, choice: Choice) { + fn conditional_assign(&mut self, rhs: &FieldElement51, choice: Choice) { let mut output = [0u64; 5]; let choicebit = choice.unwrap_u8() as fiat_25519_u1; - fiat_25519_cmovznz_u64(&mut output[0], choicebit, self.0[0], _rhs.0[0]); - fiat_25519_cmovznz_u64(&mut output[1], choicebit, self.0[1], _rhs.0[1]); - fiat_25519_cmovznz_u64(&mut output[2], choicebit, self.0[2], _rhs.0[2]); - fiat_25519_cmovznz_u64(&mut output[3], choicebit, self.0[3], _rhs.0[3]); - fiat_25519_cmovznz_u64(&mut output[4], choicebit, self.0[4], _rhs.0[4]); - *self = FieldElement51(output); + fiat_25519_cmovznz_u64(&mut output[0], choicebit, self.0[0], rhs.0[0]); + fiat_25519_cmovznz_u64(&mut output[1], choicebit, self.0[1], rhs.0[1]); + fiat_25519_cmovznz_u64(&mut output[2], choicebit, self.0[2], rhs.0[2]); + fiat_25519_cmovznz_u64(&mut output[3], choicebit, self.0[3], rhs.0[3]); + fiat_25519_cmovznz_u64(&mut output[4], choicebit, self.0[4], rhs.0[4]); + *self = FieldElement51::from_limbs(output); } } impl FieldElement51 { - /// Construct zero. - pub fn zero() -> FieldElement51 { - FieldElement51([0, 0, 0, 0, 0]) - } - - /// Construct one. - pub fn one() -> FieldElement51 { - FieldElement51([1, 0, 0, 0, 0]) + pub(crate) const fn from_limbs(limbs: [u64; 5]) -> FieldElement51 { + FieldElement51(fiat_25519_tight_field_element(limbs)) } - /// Construct -1. - pub fn minus_one() -> FieldElement51 { - FieldElement51([ - 2251799813685228, - 2251799813685247, - 2251799813685247, - 2251799813685247, - 2251799813685247, - ]) - } + /// The scalar \\( 0 \\). + pub const ZERO: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0, 0]); + /// The scalar \\( 1 \\). + pub const ONE: FieldElement51 = FieldElement51::from_limbs([1, 0, 0, 0, 0]); + /// The scalar \\( -1 \\). + pub const MINUS_ONE: FieldElement51 = FieldElement51::from_limbs([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, + ]); /// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon). #[inline(always)] #[allow(dead_code)] // Need this to not complain about reduce not being used - fn reduce(mut limbs: [u64; 5]) -> FieldElement51 { - let input = limbs; - fiat_25519_carry(&mut limbs, &input); - FieldElement51(limbs) + fn reduce(limbs: [u64; 5]) -> FieldElement51 { + let input = fiat_25519_loose_field_element(limbs); + let mut output = fiat_25519_tight_field_element([0; 5]); + fiat_25519_carry(&mut output, &input); + FieldElement51(output) } /// Load a `FieldElement51` from the low 255 bits of a 256-bit @@ -202,24 +211,25 @@ impl FieldElement51 { let mut temp = [0u8; 32]; temp.copy_from_slice(bytes); temp[31] &= 127u8; - let mut output = [0u64; 5]; + let mut output = fiat_25519_tight_field_element([0u64; 5]); fiat_25519_from_bytes(&mut output, &temp); FieldElement51(output) } /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { + pub fn as_bytes(&self) -> [u8; 32] { let mut bytes = [0u8; 32]; fiat_25519_to_bytes(&mut bytes, &self.0); - return bytes; + bytes } /// Given `k > 0`, return `self^(2^k)`. pub fn pow2k(&self, mut k: u32) -> FieldElement51 { let mut output = *self; loop { - let input = output.0; + let mut input = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut input, &output.0); fiat_25519_carry_square(&mut output.0, &input); k -= 1; if k == 0 { @@ -230,20 +240,23 @@ impl FieldElement51 { /// Returns the square of this field element. pub fn square(&self) -> FieldElement51 { - let mut output = *self; - fiat_25519_carry_square(&mut output.0, &self.0); + let mut self_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut output = FieldElement51::ZERO; + fiat_25519_carry_square(&mut output.0, &self_loose); output } /// Returns 2 times the square of this field element. pub fn square2(&self) -> FieldElement51 { - let mut output = *self; - let mut temp = *self; - // Void vs return type, measure cost of copying self - fiat_25519_carry_square(&mut temp.0, &self.0); - fiat_25519_add(&mut output.0, &temp.0, &temp.0); - let input = output.0; - fiat_25519_carry(&mut output.0, &input); + let mut self_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_relax(&mut self_loose, &self.0); + let mut square = fiat_25519_tight_field_element([0; 5]); + fiat_25519_carry_square(&mut square, &self_loose); + let mut output_loose = fiat_25519_loose_field_element([0; 5]); + fiat_25519_add(&mut output_loose, &square, &square); + let mut output = FieldElement51::ZERO; + fiat_25519_carry(&mut output.0, &output_loose); output } } diff --git a/src/backend/serial/fiat_u64/mod.rs b/curve25519-dalek/src/backend/serial/fiat_u64/mod.rs similarity index 100% rename from src/backend/serial/fiat_u64/mod.rs rename to curve25519-dalek/src/backend/serial/fiat_u64/mod.rs diff --git a/curve25519-dalek/src/backend/serial/mod.rs b/curve25519-dalek/src/backend/serial/mod.rs new file mode 100644 index 000000000..c1814d1dd --- /dev/null +++ b/curve25519-dalek/src/backend/serial/mod.rs @@ -0,0 +1,53 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Serial implementations of field, scalar, point arithmetic. +//! +//! When the vector backend is disabled, the crate uses the mixed-model strategy +//! for implementing point operations and scalar multiplication; see the +//! [`curve_models`] and [`scalar_mul`] documentation for more information. +//! +//! When the vector backend is enabled, the field and scalar +//! implementations are still used for non-vectorized operations. + +use cfg_if::cfg_if; + +cfg_if! { + if #[cfg(curve25519_dalek_backend = "u32e_backend")] { + #[doc(hidden)] + pub mod u32e; + } + else if #[cfg(curve25519_dalek_backend = "fiat")] { + + #[cfg(curve25519_dalek_bits = "32")] + #[doc(hidden)] + pub mod fiat_u32; + + #[cfg(curve25519_dalek_bits = "64")] + #[doc(hidden)] + pub mod fiat_u64; + + } else { + + #[cfg(curve25519_dalek_bits = "32")] + #[doc(hidden)] + pub mod u32; + + #[cfg(curve25519_dalek_bits = "64")] + #[doc(hidden)] + pub mod u64; + + } +} + +pub mod curve_models; + +pub mod scalar_mul; diff --git a/src/backend/serial/scalar_mul/mod.rs b/curve25519-dalek/src/backend/serial/scalar_mul/mod.rs similarity index 94% rename from src/backend/serial/scalar_mul/mod.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/mod.rs index 8bdad1fe0..7747decc3 100644 --- a/src/backend/serial/scalar_mul/mod.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/mod.rs @@ -17,8 +17,10 @@ //! scalar multiplication implementations, since it only uses one //! curve model. +#[allow(missing_docs)] pub mod variable_base; +#[allow(missing_docs)] pub mod vartime_double_base; #[cfg(feature = "alloc")] diff --git a/src/backend/serial/scalar_mul/pippenger.rs b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs similarity index 86% rename from src/backend/serial/scalar_mul/pippenger.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs index 575291d68..f60d9b953 100644 --- a/src/backend/serial/scalar_mul/pippenger.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/pippenger.rs @@ -11,14 +11,14 @@ #![allow(non_snake_case)] -use core::borrow::Borrow; +use alloc::vec::Vec; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::VartimeMultiscalarMul; +use core::borrow::Borrow; +use core::cmp::Ordering; -#[allow(unused_imports)] -use prelude::*; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::VartimeMultiscalarMul; /// Implements a version of Pippenger's algorithm. /// @@ -61,7 +61,6 @@ use prelude::*; /// This algorithm is adapted from section 4 of . pub struct Pippenger; -#[cfg(any(feature = "alloc", feature = "std"))] impl VartimeMultiscalarMul for Pippenger { type Point = EdwardsPoint; @@ -71,7 +70,7 @@ impl VartimeMultiscalarMul for Pippenger { I::Item: Borrow, J: IntoIterator>, { - use traits::Identity; + use crate::traits::Identity; let mut scalars = scalars.into_iter(); let size = scalars.by_ref().size_hint().0; @@ -93,12 +92,11 @@ impl VartimeMultiscalarMul for Pippenger { // Collect optimized scalars and points in buffers for repeated access // (scanning the whole set per digit position). - let scalars = scalars - .map(|s| s.borrow().to_radix_2w(w)); + let scalars = scalars.map(|s| s.borrow().as_radix_2w(w)); let points = points .into_iter() - .map(|p| p.map(|P| P.to_projective_niels())); + .map(|p| p.map(|P| P.as_projective_niels())); let scalars_points = scalars .zip(points) @@ -113,8 +111,8 @@ impl VartimeMultiscalarMul for Pippenger { let mut columns = (0..digits_count).rev().map(|digit_index| { // Clear the buckets when processing another digit. - for i in 0..buckets_count { - buckets[i] = EdwardsPoint::identity(); + for bucket in &mut buckets { + *bucket = EdwardsPoint::identity(); } // Iterate over pairs of (point, scalar) @@ -124,12 +122,16 @@ impl VartimeMultiscalarMul for Pippenger { for (digits, pt) in scalars_points.iter() { // Widen digit so that we don't run into edge cases when w=8. let digit = digits[digit_index] as i16; - if digit > 0 { - let b = (digit - 1) as usize; - buckets[b] = (&buckets[b] + pt).to_extended(); - } else if digit < 0 { - let b = (-digit - 1) as usize; - buckets[b] = (&buckets[b] - pt).to_extended(); + match digit.cmp(&0) { + Ordering::Greater => { + let b = (digit - 1) as usize; + buckets[b] = (&buckets[b] + pt).as_extended(); + } + Ordering::Less => { + let b = (-digit - 1) as usize; + buckets[b] = (&buckets[b] - pt).as_extended(); + } + Ordering::Equal => {} } } @@ -152,21 +154,16 @@ impl VartimeMultiscalarMul for Pippenger { }); // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. - // `unwrap()` always succeeds because we know we have more than zero digits. - let hi_column = columns.next().unwrap(); + let hi_column = columns.next().expect("should have more than zero digits"); - Some( - columns - .fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p), - ) + Some(columns.fold(hi_column, |total, p| total.mul_by_pow_2(w as u32) + p)) } } #[cfg(test)] mod test { use super::*; - use constants; - use scalar::Scalar; + use crate::constants; #[test] fn test_vartime_pippenger() { @@ -196,7 +193,7 @@ mod test { assert_eq!(subject.compress(), control.compress()); - n = n / 2; + n /= 2; } } } diff --git a/src/backend/serial/scalar_mul/precomputed_straus.rs b/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs similarity index 67% rename from src/backend/serial/scalar_mul/precomputed_straus.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs index 97f5e860b..711649e21 100644 --- a/src/backend/serial/scalar_mul/precomputed_straus.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/precomputed_straus.rs @@ -11,20 +11,21 @@ #![allow(non_snake_case)] +use alloc::vec::Vec; + use core::borrow::Borrow; +use core::cmp::Ordering; -use backend::serial::curve_models::{ +use crate::backend::serial::curve_models::{ AffineNielsPoint, CompletedPoint, ProjectiveNielsPoint, ProjectivePoint, }; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::Identity; -use traits::VartimePrecomputedMultiscalarMul; -use window::{NafLookupTable5, NafLookupTable8}; - -#[allow(unused_imports)] -use prelude::*; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; +use crate::traits::VartimePrecomputedMultiscalarMul; +use crate::window::{NafLookupTable5, NafLookupTable8}; +#[allow(missing_docs)] pub struct VartimePrecomputedStraus { static_lookup_tables: Vec>, } @@ -86,25 +87,34 @@ impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { for i in 0..dp { let t_ij = dynamic_nafs[i][j]; - if t_ij > 0 { - R = &R.to_extended() + &dynamic_lookup_tables[i].select(t_ij as usize); - } else if t_ij < 0 { - R = &R.to_extended() - &dynamic_lookup_tables[i].select(-t_ij as usize); + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R.as_extended() + &dynamic_lookup_tables[i].select(t_ij as usize) + } + Ordering::Less => { + R = &R.as_extended() - &dynamic_lookup_tables[i].select(-t_ij as usize) + } + Ordering::Equal => {} } } + #[allow(clippy::needless_range_loop)] for i in 0..sp { let t_ij = static_nafs[i][j]; - if t_ij > 0 { - R = &R.to_extended() + &self.static_lookup_tables[i].select(t_ij as usize); - } else if t_ij < 0 { - R = &R.to_extended() - &self.static_lookup_tables[i].select(-t_ij as usize); + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R.as_extended() + &self.static_lookup_tables[i].select(t_ij as usize) + } + Ordering::Less => { + R = &R.as_extended() - &self.static_lookup_tables[i].select(-t_ij as usize) + } + Ordering::Equal => {} } } - S = R.to_projective(); + S = R.as_projective(); } - Some(S.to_extended()) + Some(S.as_extended()) } } diff --git a/src/backend/serial/scalar_mul/straus.rs b/curve25519-dalek/src/backend/serial/scalar_mul/straus.rs similarity index 83% rename from src/backend/serial/scalar_mul/straus.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/straus.rs index a361df52d..9c95b4fc6 100644 --- a/src/backend/serial/scalar_mul/straus.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/straus.rs @@ -13,15 +13,15 @@ #![allow(non_snake_case)] -use core::borrow::Borrow; +use alloc::vec::Vec; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::MultiscalarMul; -use traits::VartimeMultiscalarMul; +use core::borrow::Borrow; +use core::cmp::Ordering; -#[allow(unused_imports)] -use prelude::*; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::MultiscalarMul; +use crate::traits::VartimeMultiscalarMul; /// Perform multiscalar multiplication by the interleaved window /// method, also known as Straus' method (since it was apparently @@ -107,11 +107,9 @@ impl MultiscalarMul for Straus { J: IntoIterator, J::Item: Borrow, { - use zeroize::Zeroizing; - - use backend::serial::curve_models::ProjectiveNielsPoint; - use window::LookupTable; - use traits::Identity; + use crate::backend::serial::curve_models::ProjectiveNielsPoint; + use crate::traits::Identity; + use crate::window::LookupTable; let lookup_tables: Vec<_> = points .into_iter() @@ -121,11 +119,11 @@ impl MultiscalarMul for Straus { // This puts the scalar digits into a heap-allocated Vec. // To ensure that these are erased, pass ownership of the Vec into a // Zeroizing wrapper. - let scalar_digits_vec: Vec<_> = scalars + #[cfg_attr(not(feature = "zeroize"), allow(unused_mut))] + let mut scalar_digits: Vec<_> = scalars .into_iter() - .map(|s| s.borrow().to_radix_16()) + .map(|s| s.borrow().as_radix_16()) .collect(); - let scalar_digits = Zeroizing::new(scalar_digits_vec); let mut Q = EdwardsPoint::identity(); for j in (0..64).rev() { @@ -135,10 +133,13 @@ impl MultiscalarMul for Straus { // R_i = s_{i,j} * P_i let R_i = lookup_table_i.select(s_i[j]); // Q = Q + R_i - Q = (&Q + &R_i).to_extended(); + Q = (&Q + &R_i).as_extended(); } } + #[cfg(feature = "zeroize")] + zeroize::Zeroize::zeroize(&mut scalar_digits); + Q } } @@ -161,9 +162,11 @@ impl VartimeMultiscalarMul for Straus { I::Item: Borrow, J: IntoIterator>, { - use backend::serial::curve_models::{CompletedPoint, ProjectiveNielsPoint, ProjectivePoint}; - use window::NafLookupTable5; - use traits::Identity; + use crate::backend::serial::curve_models::{ + CompletedPoint, ProjectiveNielsPoint, ProjectivePoint, + }; + use crate::traits::Identity; + use crate::window::NafLookupTable5; let nafs: Vec<_> = scalars .into_iter() @@ -181,16 +184,18 @@ impl VartimeMultiscalarMul for Straus { let mut t: CompletedPoint = r.double(); for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { - if naf[i] > 0 { - t = &t.to_extended() + &lookup_table.select(naf[i] as usize); - } else if naf[i] < 0 { - t = &t.to_extended() - &lookup_table.select(-naf[i] as usize); + match naf[i].cmp(&0) { + Ordering::Greater => { + t = &t.as_extended() + &lookup_table.select(naf[i] as usize) + } + Ordering::Less => t = &t.as_extended() - &lookup_table.select(-naf[i] as usize), + Ordering::Equal => {} } } - r = t.to_projective(); + r = t.as_projective(); } - Some(r.to_extended()) + Some(r.as_extended()) } } diff --git a/src/backend/serial/scalar_mul/variable_base.rs b/curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs similarity index 66% rename from src/backend/serial/scalar_mul/variable_base.rs rename to curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs index a4ff2ed53..1de84bc4d 100644 --- a/src/backend/serial/scalar_mul/variable_base.rs +++ b/curve25519-dalek/src/backend/serial/scalar_mul/variable_base.rs @@ -1,12 +1,13 @@ #![allow(non_snake_case)] -use traits::Identity; -use scalar::Scalar; -use edwards::EdwardsPoint; -use backend::serial::curve_models::ProjectiveNielsPoint; -use window::LookupTable; +use crate::backend::serial::curve_models::ProjectiveNielsPoint; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; +use crate::window::LookupTable; /// Perform constant-time, variable-base scalar multiplication. +#[rustfmt::skip] // keep alignment of explanatory comments pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] let lookup_table = LookupTable::::from(point); @@ -15,7 +16,8 @@ pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { // s = s_0 + s_1*16^1 + ... + s_63*16^63, // // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. - let scalar_digits = scalar.to_radix_16(); + // This decomposition requires s < 2^255, which is guaranteed by Scalar invariant #1. + let scalar_digits = scalar.as_radix_16(); // Compute s*P as // // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) @@ -30,17 +32,17 @@ pub(crate) fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { let mut tmp1 = &tmp3 + &lookup_table.select(scalar_digits[63]); // Now tmp1 = s_63*P in P1xP1 coords for i in (0..63).rev() { - tmp2 = tmp1.to_projective(); // tmp2 = (prev) in P2 coords + tmp2 = tmp1.as_projective(); // tmp2 = (prev) in P2 coords tmp1 = tmp2.double(); // tmp1 = 2*(prev) in P1xP1 coords - tmp2 = tmp1.to_projective(); // tmp2 = 2*(prev) in P2 coords + tmp2 = tmp1.as_projective(); // tmp2 = 2*(prev) in P2 coords tmp1 = tmp2.double(); // tmp1 = 4*(prev) in P1xP1 coords - tmp2 = tmp1.to_projective(); // tmp2 = 4*(prev) in P2 coords + tmp2 = tmp1.as_projective(); // tmp2 = 4*(prev) in P2 coords tmp1 = tmp2.double(); // tmp1 = 8*(prev) in P1xP1 coords - tmp2 = tmp1.to_projective(); // tmp2 = 8*(prev) in P2 coords + tmp2 = tmp1.as_projective(); // tmp2 = 8*(prev) in P2 coords tmp1 = tmp2.double(); // tmp1 = 16*(prev) in P1xP1 coords - tmp3 = tmp1.to_extended(); // tmp3 = 16*(prev) in P3 coords + tmp3 = tmp1.as_extended(); // tmp3 = 16*(prev) in P3 coords tmp1 = &tmp3 + &lookup_table.select(scalar_digits[i]); // Now tmp1 = s_i*P + 16*(prev) in P1xP1 coords } - tmp1.to_extended() + tmp1.as_extended() } diff --git a/curve25519-dalek/src/backend/serial/scalar_mul/vartime_double_base.rs b/curve25519-dalek/src/backend/serial/scalar_mul/vartime_double_base.rs new file mode 100644 index 000000000..cdb31a124 --- /dev/null +++ b/curve25519-dalek/src/backend/serial/scalar_mul/vartime_double_base.rs @@ -0,0 +1,72 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence +#![allow(non_snake_case)] + +use core::cmp::Ordering; + +use crate::backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; +use crate::constants; +use crate::edwards::EdwardsPoint; +use crate::scalar::Scalar; +use crate::traits::Identity; +use crate::window::NafLookupTable5; + +/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. +pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + let a_naf = a.non_adjacent_form(5); + + #[cfg(feature = "precomputed-tables")] + let b_naf = b.non_adjacent_form(8); + #[cfg(not(feature = "precomputed-tables"))] + let b_naf = b.non_adjacent_form(5); + + // Find starting index + let mut i: usize = 255; + for j in (0..256).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let table_A = NafLookupTable5::::from(A); + #[cfg(feature = "precomputed-tables")] + let table_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT; + #[cfg(not(feature = "precomputed-tables"))] + let table_B = + &NafLookupTable5::::from(&constants::ED25519_BASEPOINT_POINT); + + let mut r = ProjectivePoint::identity(); + loop { + let mut t = r.double(); + + match a_naf[i].cmp(&0) { + Ordering::Greater => t = &t.as_extended() + &table_A.select(a_naf[i] as usize), + Ordering::Less => t = &t.as_extended() - &table_A.select(-a_naf[i] as usize), + Ordering::Equal => {} + } + + match b_naf[i].cmp(&0) { + Ordering::Greater => t = &t.as_extended() + &table_B.select(b_naf[i] as usize), + Ordering::Less => t = &t.as_extended() - &table_B.select(-b_naf[i] as usize), + Ordering::Equal => {} + } + + r = t.as_projective(); + + if i == 0 { + break; + } + i -= 1; + } + + r.as_extended() +} diff --git a/curve25519-dalek/src/backend/serial/u32/constants.rs b/curve25519-dalek/src/backend/serial/u32/constants.rs new file mode 100644 index 000000000..c4fc35025 --- /dev/null +++ b/curve25519-dalek/src/backend/serial/u32/constants.rs @@ -0,0 +1,4803 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! This module contains various constants (such as curve parameters +//! and useful field elements like `sqrt(-1)`), as well as +//! lookup tables of pre-computed points. + +use super::field::FieldElement2625; +use super::scalar::Scalar29; +use crate::edwards::EdwardsPoint; + +#[cfg(feature = "precomputed-tables")] +use crate::{ + backend::serial::curve_models::AffineNielsPoint, + edwards::EdwardsBasepointTable, + window::{LookupTable, NafLookupTable8}, +}; + +/// The value of minus one, equal to `-&FieldElement::ONE` +pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625::from_limbs([ + 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, + 33554431, +]); + +/// Edwards `d` value, equal to `-121665/121666 mod p`. +pub(crate) const EDWARDS_D: FieldElement2625 = FieldElement2625::from_limbs([ + 56195235, 13857412, 51736253, 6949390, 114729, 24766616, 60832955, 30306712, 48412415, 21499315, +]); + +/// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. +pub(crate) const EDWARDS_D2: FieldElement2625 = FieldElement2625::from_limbs([ + 45281625, 27714825, 36363642, 13898781, 229458, 15978800, 54557047, 27058993, 29715967, 9444199, +]); + +/// One minus edwards `d` value squared, equal to `(1 - (-121665/121666) mod p) pow 2` +pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement2625 = FieldElement2625::from_limbs([ + 6275446, 16937061, 44170319, 29780721, 11667076, 7397348, 39186143, 1766194, 42675006, 672202, +]); + +/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` +pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement2625 = FieldElement2625::from_limbs([ + 15551776, 22456977, 53683765, 23429360, 55212328, 10178283, 40474537, 4729243, 61826754, + 23438029, +]); + +/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const SQRT_AD_MINUS_ONE: FieldElement2625 = FieldElement2625::from_limbs([ + 24849947, 33400850, 43495378, 6347714, 46036536, 32887293, 41837720, 18186727, 66238516, + 14525638, +]); + +/// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625::from_limbs([ + 6111466, 4156064, 39310137, 12243467, 41204824, 120896, 20826367, 26493656, 6093567, 31568420, +]); + +/// Precomputed value of one of the square roots of -1 (mod p) +pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625::from_limbs([ + 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, 31548777, 326685, 11406482, +]); + +/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) +/// The u32e backend uses hardware acceleration for this. +#[cfg(not(curve25519_dalek_backend = "u32e_backend"))] +pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = + FieldElement2625::from_limbs([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + +/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation +/// for Curve25519 in its Montgomery form. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A: FieldElement2625 = + FieldElement2625::from_limbs([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + +/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A_NEG: FieldElement2625 = FieldElement2625::from_limbs([ + 66622183, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, + 33554431, +]); + +/// `L` is the order of base point, i.e. 2^252 + +/// 27742317777372353535851937790883648493 +pub(crate) const L: Scalar29 = Scalar29([ + 0x1cf5d3ed, 0x009318d2, 0x1de73596, 0x1df3bd45, 0x0000014d, 0x00000000, 0x00000000, 0x00000000, + 0x00100000, +]); + +/// `L` * `LFACTOR` = -1 (mod 2^29) +pub(crate) const LFACTOR: u32 = 0x12547e1b; + +/// `R` = R % L where R = 2^261 +pub(crate) const R: Scalar29 = Scalar29([ + 0x114df9ed, 0x1a617303, 0x0f7c098c, 0x16793167, 0x1ffd656e, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x000fffff, +]); + +/// `RR` = (R^2) % L where R = 2^261 +pub(crate) const RR: Scalar29 = Scalar29([ + 0x0b5f9d12, 0x1e141b17, 0x158d7f3d, 0x143f3757, 0x1972d781, 0x042feb7c, 0x1ceec73d, 0x1e184d1e, + 0x0005046d, +]); + +/// The Ed25519 basepoint, as an `EdwardsPoint`. +/// +/// This is called `_POINT` to distinguish it from +/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { + X: FieldElement2625::from_limbs([ + 52811034, 25909283, 16144682, 17082669, 27570973, 30858332, 40966398, 8378388, 20764389, + 8758491, + ]), + Y: FieldElement2625::from_limbs([ + 40265304, 26843545, 13421772, 20132659, 26843545, 6710886, 53687091, 13421772, 40265318, + 26843545, + ]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ + 28827043, 27438313, 39759291, 244362, 8635006, 11264893, 19351346, 13413597, 16611511, + 27139452, + ]), +}; + +/// The 8-torsion subgroup \\(\mathcal E \[8\]\\). +/// +/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of +/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\) +/// generating \\(\mathcal E\[8\]\\). +/// +/// Thus \\(\mathcal E\[4\]\\) is the points indexed by `0,2,4,6`, and +/// \\(\mathcal E\[2\]\\) is the points indexed by `0,4`. +/// The Ed25519 basepoint has y = 4/5. This is called `_POINT` to +/// distinguish it from `_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; + +/// Inner item used to hide limb constants from cargo doc output. +#[doc(hidden)] +pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ + EdwardsPoint { + X: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Y: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625::from_limbs([ + 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, + 8345318, + ]), + Y: FieldElement2625::from_limbs([ + 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, + 31985330, + ]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ + 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, + 3541542, 28543251, + ]), + }, + EdwardsPoint { + X: FieldElement2625::from_limbs([ + 32595773, 7943725, 57730914, 30054016, 54719391, 272472, 25146209, 2005654, 66782178, + 22147949, + ]), + Y: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625::from_limbs([ + 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, + 8345318, + ]), + Y: FieldElement2625::from_limbs([ + 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, + 47743011, 1569101, + ]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ + 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, + 5011180, + ]), + }, + EdwardsPoint { + X: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Y: FieldElement2625::from_limbs([ + 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, + 67108863, 33554431, + ]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625::from_limbs([ + 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, + 33528939, 25209113, + ]), + Y: FieldElement2625::from_limbs([ + 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, + 47743011, 1569101, + ]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ + 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, + 3541542, 28543251, + ]), + }, + EdwardsPoint { + X: FieldElement2625::from_limbs([ + 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, 31548777, 326685, + 11406482, + ]), + Y: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement2625::from_limbs([ + 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, + 33528939, 25209113, + ]), + Y: FieldElement2625::from_limbs([ + 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, + 31985330, + ]), + Z: FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), + T: FieldElement2625::from_limbs([ + 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, + 5011180, + ]), + }, +]; + +/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). +#[cfg(feature = "precomputed-tables")] +pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable = + &ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; + +/// Inner constant, used to avoid filling the docs with precomputed points. +#[doc(hidden)] +#[cfg(feature = "precomputed-tables")] +static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, + 61029707, 35602036, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, + 19500929, 18085054, + ]), + xy2d: FieldElement2625::from_limbs([ + 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, + 42594502, 29115885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54292951, 54132516, 45527619, 11784319, 41753206, 30803714, 55390960, 29739860, + 66750418, 23343128, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 45405608, 6903824, 27185491, 6451973, 37531140, 24000426, 51492312, 11189267, + 40279186, 28235350, + ]), + xy2d: FieldElement2625::from_limbs([ + 26966623, 11152617, 32442495, 15396054, 14353839, 20802097, 63980037, 24013313, + 51636816, 29387734, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, + 28944398, 32004408, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, + 7689661, 11199574, + ]), + xy2d: FieldElement2625::from_limbs([ + 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, + 49359771, 23634074, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 50071967, 13921891, 78054670, 27521000, 27105051, 17470053, 105291517, 15006021, + 70393432, 27277891, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 23599295, 25248385, 55915199, 25867015, 13236773, 10506355, 7464579, 9656445, + 13059162, 10374397, + ]), + xy2d: FieldElement2625::from_limbs([ + 7798537, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, 29715387, + 66467155, 33453106, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, + 118779423, 44373810, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, + 54440373, 5581305, + ]), + xy2d: FieldElement2625::from_limbs([ + 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, + 43430843, 17738489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 51736881, 20691677, 32573249, 4720197, 107781206, 39429941, 115029100, 18329611, + 124398787, 21468653, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 58559652, 109982, 15149363, 2178705, 22900618, 4543417, 3044240, 17864545, 1762327, + 14866737, + ]), + xy2d: FieldElement2625::from_limbs([ + 48909169, 17603008, 56635573, 1707277, 49922944, 3916100, 38872452, 3959420, + 27914454, 4383652, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, + 43156424, 18378665, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, + 30598449, 7715701, + ]), + xy2d: FieldElement2625::from_limbs([ + 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, + 29794553, 32145132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 14499452, 64379265, 33917749, 62854211, 95603724, 14271266, 97399599, 10876453, + 33954766, 35936157, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 59913433, 30899068, 52378708, 462250, 39384538, 3941371, 60872247, 3696004, + 34808032, 15351954, + ]), + xy2d: FieldElement2625::from_limbs([ + 27431194, 8222322, 16448760, 29646437, 48401861, 11938354, 34147463, 30583916, + 29551812, 10109425, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 53451805, 20399000, 102933977, 45331528, 88556249, 40073815, 64730579, 31926875, + 77201646, 28790260, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 27939166, 14210322, 4677035, 16277044, 44144402, 21156292, 34600109, 12005537, + 49298737, 12803509, + ]), + xy2d: FieldElement2625::from_limbs([ + 17228999, 17892808, 65875336, 300139, 65883994, 21839654, 30364212, 24516238, + 18016356, 4397660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 56150002, 25864224, 4776340, 18600194, 27850027, 17952220, 40489757, 14544524, + 49631360, 34537070, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 29253598, 15796703, 64244882, 23645547, 10057022, 3163536, 7332899, 29434304, + 46061167, 9934962, + ]), + xy2d: FieldElement2625::from_limbs([ + 5793284, 16271923, 42977250, 23438027, 29188559, 1206517, 52360934, 4559894, + 36984942, 22656481, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 39464893, 55615857, 83391519, 22517938, 28414020, 52096600, 24191032, 38096129, + 53770554, 39054999, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 12650548, 32057319, 9052870, 11355358, 49428827, 25154267, 49678271, 12264342, + 10874051, 13524335, + ]), + xy2d: FieldElement2625::from_limbs([ + 25556948, 30508442, 714650, 2510400, 23394682, 23139102, 33119037, 5080568, + 44580805, 5376627, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 108129445, 29543378, 50095164, 30016803, 60382070, 35475328, 44787558, 57661420, + 71644630, 35123438, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 64853442, 14606629, 45416424, 25514613, 28430648, 8775819, 36614302, 3044289, + 31848280, 12543772, + ]), + xy2d: FieldElement2625::from_limbs([ + 45080285, 2943892, 35251351, 6777305, 13784462, 29262229, 39731668, 31491700, + 7718481, 14474653, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 69494160, 36008644, 44477543, 33601034, 62670928, 51428448, 67765827, 26317766, + 91425031, 28300864, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 13741529, 10911568, 33875447, 24950694, 46931033, 32521134, 33040650, 20129900, + 46379407, 8321685, + ]), + xy2d: FieldElement2625::from_limbs([ + 21060490, 31341688, 15712756, 29218333, 1639039, 10656336, 23845965, 21679594, + 57124405, 608371, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 53436113, 18466845, 56219170, 25997372, 61071954, 11305546, 68232832, 60328286, + 94338261, 33578318, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 43864724, 33260226, 55364135, 14712570, 37643165, 31524814, 12797023, 27114124, + 65475458, 16678953, + ]), + xy2d: FieldElement2625::from_limbs([ + 37608244, 4770661, 51054477, 14001337, 7830047, 9564805, 65600720, 28759386, + 49939598, 4904952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 91168402, 48171434, 86146020, 18514523, 86874956, 18648002, 72278074, 16191879, + 69237100, 29227598, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 50127693, 4124965, 58568254, 22900634, 30336521, 19449185, 37302527, 916032, + 60226322, 30567899, + ]), + xy2d: FieldElement2625::from_limbs([ + 44477957, 12419371, 59974635, 26081060, 50629959, 16739174, 285431, 2763829, + 15736322, 4143876, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 69488197, 11839344, 62998462, 27565766, 78383161, 34349388, 67321664, 18959768, + 23527083, 17096164, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 33431108, 22423954, 49269897, 17927531, 8909498, 8376530, 34483524, 4087880, + 51919953, 19138217, + ]), + xy2d: FieldElement2625::from_limbs([ + 1767664, 7197987, 53903638, 31531796, 54017513, 448825, 5799055, 4357868, 62334673, + 17231393, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 6721947, 47388255, 43585475, 32003117, 93463156, 21691110, 90474010, 29604699, + 74499753, 36314231, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 4409022, 2052381, 23373853, 10530217, 7676779, 20668478, 21302352, 29290375, + 1244379, 20634787, + ]), + xy2d: FieldElement2625::from_limbs([ + 62687625, 7169618, 4982368, 30596842, 30256824, 30776892, 14086412, 9208236, + 15886429, 16489664, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 69104920, 43930080, 81455230, 46865633, 60234728, 17116020, 120524529, 33952799, + 36502408, 32841498, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 41801399, 9795879, 64331450, 14878808, 33577029, 14780362, 13348553, 12076947, + 36272402, 5113181, + ]), + xy2d: FieldElement2625::from_limbs([ + 49338080, 11797795, 31950843, 13929123, 41220562, 12288343, 36767763, 26218045, + 13847710, 5387222, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 48526682, 30138214, 84933706, 64767897, 89853205, 56666252, 75871923, 37172217, + 47508201, 43925422, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 20246567, 19185054, 22358228, 33010720, 18507282, 23140436, 14554436, 24808340, + 32232923, 16763880, + ]), + xy2d: FieldElement2625::from_limbs([ + 9648486, 10094563, 26416693, 14745928, 36734546, 27081810, 11094160, 15689506, + 3140038, 17044340, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 50948773, 39027126, 31895587, 38299426, 75932378, 43920116, 39884063, 43003044, + 38334409, 33920726, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 19153450, 11523972, 56012374, 27051289, 42461232, 5420646, 28344573, 8041113, + 719605, 11671788, + ]), + xy2d: FieldElement2625::from_limbs([ + 8678006, 2694440, 60300850, 2517371, 4964326, 11152271, 51675948, 18287915, + 27000812, 23358879, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 119059805, 40688742, 75748150, 30739554, 59873175, 43976173, 67672928, 38890528, + 73859840, 19033405, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 11836410, 29574944, 26297893, 16080799, 23455045, 15735944, 1695823, 24735310, + 8169719, 16220347, + ]), + xy2d: FieldElement2625::from_limbs([ + 48993007, 8653646, 17578566, 27461813, 59083086, 17541668, 55964556, 30926767, + 61118155, 19388398, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 43800347, 22586119, 82322091, 23473217, 36255258, 22504427, 27884328, 36401716, + 69764724, 35292826, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 39571412, 19301410, 41772562, 25551651, 57738101, 8129820, 21651608, 30315096, + 48021414, 22549153, + ]), + xy2d: FieldElement2625::from_limbs([ + 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, + 10478196, 8544890, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 32173083, 50979553, 24896205, 37475929, 22579055, 63698010, 19270447, 45771905, + 84897880, 63712868, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 36555903, 31326030, 51530034, 23407230, 13243888, 517024, 15479401, 29701199, + 30460519, 1052596, + ]), + xy2d: FieldElement2625::from_limbs([ + 55493970, 13323617, 32618793, 8175907, 51878691, 12596686, 27491595, 28942073, + 3179267, 24075541, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 99055914, 52742212, 62468279, 18214510, 51982886, 27514722, 52352086, 17142691, + 19072639, 24043372, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 11685058, 11822410, 3158003, 19601838, 33402193, 29389366, 5977895, 28339415, + 473098, 5040608, + ]), + xy2d: FieldElement2625::from_limbs([ + 46817982, 8198641, 39698732, 11602122, 1290375, 30754672, 28326861, 1721092, + 47550222, 30422825, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 74990396, 10687936, 74687587, 7738377, 48157852, 31000479, 88929649, 8076148, + 39240368, 11538388, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 47173198, 3899860, 18283497, 26752864, 51380203, 22305220, 8754524, 7446702, + 61432810, 5797015, + ]), + xy2d: FieldElement2625::from_limbs([ + 55813245, 29760862, 51326753, 25589858, 12708868, 25098233, 2014098, 24503858, + 64739691, 27677090, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 111745333, 55540121, 106535706, 34700805, 86065554, 50194990, 68301593, 29840232, + 82232482, 44365936, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 14352079, 30134717, 48166819, 10822654, 32750596, 4699007, 67038501, 15776355, + 38222085, 21579878, + ]), + xy2d: FieldElement2625::from_limbs([ + 38867681, 25481956, 62129901, 28239114, 29416930, 1847569, 46454691, 17069576, + 4714546, 23953777, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 15200313, 41923004, 86787964, 15970073, 35236190, 35513882, 24611598, 29010600, + 55362987, 45894651, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 12876937, 23074376, 33134380, 6590940, 60801088, 14872439, 9613953, 8241152, + 15370987, 9608631, + ]), + xy2d: FieldElement2625::from_limbs([ + 62965568, 21540023, 8446280, 33162829, 4407737, 13629032, 59383996, 15866073, + 38898243, 24740332, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 26660609, 51431209, 75502596, 33912478, 59707572, 34547419, 43204630, 34413128, + 87680086, 41974987, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 14620696, 13067227, 51661590, 8264466, 14106269, 15080814, 33531827, 12516406, + 45534429, 21077682, + ]), + xy2d: FieldElement2625::from_limbs([ + 236881, 10476226, 57258, 18877408, 6472997, 2466984, 17258519, 7256740, 8791136, + 15069930, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 68385255, 24182513, 90058498, 17231624, 43615824, 61406677, 81820737, 38428660, + 36445723, 31223040, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 5855666, 4990204, 53397016, 7294283, 59304582, 1924646, 65685689, 25642053, + 34039526, 9234252, + ]), + xy2d: FieldElement2625::from_limbs([ + 20590503, 24535444, 31529743, 26201766, 64402029, 10650547, 31559055, 21944845, + 18979185, 13396066, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 24474268, 38522535, 22267081, 37961786, 91172745, 25229251, 48291976, 13594781, + 33514650, 40576390, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 55541958, 26988926, 45743778, 15928891, 40950559, 4315420, 41160136, 29637754, + 45628383, 12868081, + ]), + xy2d: FieldElement2625::from_limbs([ + 38473832, 13504660, 19988037, 31421671, 21078224, 6443208, 45662757, 2244499, + 54653067, 25465048, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 36513317, 13793478, 61256044, 33873567, 41385691, 60844964, 100195408, 8957936, + 51875216, 39094952, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 55478669, 22050529, 58989363, 25911358, 2620055, 1022908, 43398120, 31985447, + 50980335, 18591624, + ]), + xy2d: FieldElement2625::from_limbs([ + 23152952, 775386, 27395463, 14006635, 57407746, 4649511, 1689819, 892185, 55595587, + 18348483, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 76878974, 43141169, 93604957, 37878551, 68665374, 30004407, 94562682, 38317558, + 47929249, 39421565, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 34343820, 1927589, 31726409, 28801137, 23962433, 17534932, 27846558, 5931263, + 37359161, 17445976, + ]), + xy2d: FieldElement2625::from_limbs([ + 27461885, 30576896, 22380809, 1815854, 44075111, 30522493, 7283489, 18406359, + 47582163, 7734628, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 59098581, 57518046, 55988459, 39750469, 29344157, 20123547, 74694158, 30377805, + 85658360, 48856500, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 34450527, 27383209, 59436070, 22502750, 6258877, 13504381, 10458790, 27135971, + 58236621, 8424745, + ]), + xy2d: FieldElement2625::from_limbs([ + 24687186, 8613276, 36441818, 30320886, 1863891, 31723888, 19206233, 7134917, + 55824382, 32725512, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 11334880, 24336410, 75134156, 46261950, 84632755, 23078360, 77352601, 18868970, + 62042829, 50053268, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 8911542, 6887158, 57524604, 26595841, 11145640, 24010752, 17303924, 19430194, + 6536640, 10543906, + ]), + xy2d: FieldElement2625::from_limbs([ + 38162480, 15479762, 49642029, 568875, 65611181, 11223453, 64439674, 16928857, + 39873154, 8876770, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 41365946, 54541999, 118567760, 32707823, 101191041, 32758142, 33627041, 15824473, + 66504438, 24514614, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10330056, 70051, 7957388, 24551765, 9764901, 15609756, 27698697, 28664395, 1657393, + 3084098, + ]), + xy2d: FieldElement2625::from_limbs([ + 10477963, 26084172, 12119565, 20303627, 29016246, 28188843, 31280318, 14396151, + 36875289, 15272408, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54820536, 36723894, 28813182, 16658753, 92225296, 27923965, 109043770, 54472724, + 42094105, 35504935, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 40928506, 9489186, 11053416, 18808271, 36055143, 5825629, 58724558, 24786899, + 15341278, 8373727, + ]), + xy2d: FieldElement2625::from_limbs([ + 28685821, 7759505, 52730348, 21551571, 35137043, 4079241, 298136, 23321830, + 64230656, 15190419, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 34175950, 47360767, 52771378, 51314432, 110213106, 10940926, 75778582, 36296824, + 108184414, 60233859, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 65528476, 21825014, 41129205, 22109408, 49696989, 22641577, 9291593, 17306653, + 54954121, 6048604, + ]), + xy2d: FieldElement2625::from_limbs([ + 36803549, 14843443, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, + 11213262, 9168384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 40828313, 44562278, 19408959, 32613674, 115624762, 29225850, 62020803, 22449281, + 20470156, 50710163, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 43972811, 9282191, 14855179, 18164354, 59746048, 19145871, 44324911, 14461607, + 14042978, 5230683, + ]), + xy2d: FieldElement2625::from_limbs([ + 29969548, 30812838, 50396996, 25001989, 9175485, 31085458, 21556950, 3506042, + 61174973, 21104723, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 63964099, 42299092, 19704002, 38135710, 46678177, 6830682, 45824694, 42525944, + 38569674, 48880994, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 47644235, 10110287, 49846336, 30050539, 43608476, 1355668, 51585814, 15300987, + 46594746, 9168259, + ]), + xy2d: FieldElement2625::from_limbs([ + 61755510, 4488612, 43305616, 16314346, 7780487, 17915493, 38160505, 9601604, + 33087103, 24543045, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 47665675, 18041531, 46311396, 21109108, 104393280, 43783891, 39664534, 52108332, + 61111992, 49219103, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 23294591, 16921819, 44458082, 25083453, 27844203, 11461195, 13099750, 31094076, + 18151675, 13417686, + ]), + xy2d: FieldElement2625::from_limbs([ + 42385932, 29377914, 35958184, 5988918, 40250079, 6685064, 1661597, 21002991, + 15271675, 18101767, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 78541887, 20325766, 75348494, 28274914, 65123427, 32828713, 48410099, 35721975, + 60187562, 20114249, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 35672693, 15575145, 30436815, 12192228, 44645511, 9395378, 57191156, 24915434, + 12215109, 12028277, + ]), + xy2d: FieldElement2625::from_limbs([ + 14098381, 6555944, 23007258, 5757252, 51681032, 20603929, 30123439, 4617780, + 50208775, 32898803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 63082644, 51868028, 79002030, 47273095, 52299401, 35401816, 51288864, 43708440, + 91082124, 20869957, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 40577025, 29858441, 65199965, 2534300, 35238307, 17004076, 18341389, 22134481, + 32013173, 23450893, + ]), + xy2d: FieldElement2625::from_limbs([ + 41629544, 10876442, 55337778, 18929291, 54739296, 1838103, 21911214, 6354752, + 4425632, 32716610, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 56675456, 18941465, 89338721, 30463384, 53917697, 34331160, 116802352, 55088400, + 71833867, 47599401, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 19268631, 26250011, 1555348, 8692754, 45634805, 23643767, 6347389, 32142648, + 47586572, 17444675, + ]), + xy2d: FieldElement2625::from_limbs([ + 42244775, 12986007, 56209986, 27995847, 55796492, 33405905, 19541417, 8180106, + 9282262, 10282508, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 108012627, 37982977, 58447667, 20360168, 71207265, 52943606, 15522533, 8372215, + 72651459, 22851748, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56546323, 14895632, 26814552, 16880582, 49628109, 31065071, 64326972, 6993760, + 49014979, 10114654, + ]), + xy2d: FieldElement2625::from_limbs([ + 47001790, 32625013, 31422703, 10427861, 59998115, 6150668, 38017109, 22025285, + 25953724, 33448274, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 62874448, 59069571, 57989737, 36600431, 69210472, 54501569, 86498882, 39648727, + 63793584, 46385556, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 51110167, 7578151, 5310217, 14408357, 33560244, 33329692, 31575953, 6326196, + 7381791, 31132593, + ]), + xy2d: FieldElement2625::from_limbs([ + 46206085, 3296810, 24736065, 17226043, 18374253, 7318640, 6295303, 8082724, + 51746375, 12339663, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 27724736, 35845589, 73197064, 19369633, 68901590, 39412065, 80957277, 15768921, + 92200031, 14856293, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 48242193, 8331042, 24373479, 8541013, 66406866, 24284974, 12927299, 20858939, + 44926390, 24541532, + ]), + xy2d: FieldElement2625::from_limbs([ + 55685435, 28132841, 11632844, 3405020, 30536730, 21880393, 39848098, 13866389, + 30146206, 9142070, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 71032974, 18246915, 120400605, 23499470, 79400683, 32886065, 39406089, 9326383, + 58871006, 37725725, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 51186905, 16037936, 6713787, 16606682, 45496729, 2790943, 26396185, 3731949, + 345228, 28091483, + ]), + xy2d: FieldElement2625::from_limbs([ + 45781307, 13448258, 25284571, 1143661, 20614966, 24705045, 2031538, 21163201, + 50855680, 19972348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 98125037, 16832002, 93480255, 52657630, 62081513, 14854136, 17477601, 37397089, + 28012649, 50703444, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 62033029, 9368965, 58546785, 28953529, 51858910, 6970559, 57918991, 16292056, + 58241707, 3507939, + ]), + xy2d: FieldElement2625::from_limbs([ + 29439664, 3537914, 23333589, 6997794, 49553303, 22536363, 51899661, 18503164, + 57943934, 6580395, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54922984, 59429075, 83547131, 10826159, 58412047, 27318820, 84969307, 24280585, + 65013061, 42858998, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 20714545, 29217521, 29088194, 7406487, 11426967, 28458727, 14792666, 18945815, + 5289420, 33077305, + ]), + xy2d: FieldElement2625::from_limbs([ + 50443312, 22903641, 60948518, 20248671, 9192019, 31751970, 17271489, 12349094, + 26939669, 29802138, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54218947, 9373457, 98704712, 16374214, 21471720, 13221525, 39825369, 54760304, + 63410056, 33672318, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 22263325, 26994382, 3984569, 22379786, 51994855, 32987646, 28311252, 5358056, + 43789084, 541963, + ]), + xy2d: FieldElement2625::from_limbs([ + 16259200, 3261970, 2309254, 18019958, 50223152, 28972515, 24134069, 16848603, + 53771797, 20002236, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 76487005, 20414245, 111371745, 20809166, 95307144, 59864765, 64709178, 32837080, + 67799289, 48430675, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 24977353, 33240048, 58884894, 20089345, 28432342, 32378079, 54040059, 21257083, + 44727879, 6618998, + ]), + xy2d: FieldElement2625::from_limbs([ + 65570671, 11685645, 12944378, 13682314, 42719353, 19141238, 8044828, 19737104, + 32239828, 27901670, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 48505798, 38317421, 66182613, 42439735, 105805247, 30367115, 76890510, 23204372, + 32779358, 5095274, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 34100715, 28339925, 34843976, 29869215, 9460460, 24227009, 42507207, 14506723, + 21639561, 30924196, + ]), + xy2d: FieldElement2625::from_limbs([ + 50707921, 20442216, 25239337, 15531969, 3987758, 29055114, 65819361, 26690896, + 17874573, 558605, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 53508716, 10240080, 76280747, 16131052, 46239610, 43154131, 100608350, 38634582, + 69194755, 38674192, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 44903700, 31034903, 50727262, 414690, 42089314, 2170429, 30634760, 25190818, + 35108870, 27794547, + ]), + xy2d: FieldElement2625::from_limbs([ + 60263160, 15791201, 8550074, 32241778, 29928808, 21462176, 27534429, 26362287, + 44757485, 12961481, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 42616785, 57538092, 10368192, 11582341, 110820435, 31309143, 83642793, 8206995, + 104023076, 28394792, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 55987368, 30172197, 2307365, 6362031, 66973409, 8868176, 50273234, 7031274, + 7589640, 8945490, + ]), + xy2d: FieldElement2625::from_limbs([ + 34956097, 8917966, 6661220, 21876816, 65916803, 17761038, 7251488, 22372252, + 24099108, 19098262, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 72128384, 25646961, 71352990, 18840075, 107284455, 40007595, 47990681, 20265406, + 127985831, 56828126, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10853575, 10721687, 26480089, 5861829, 44113045, 1972174, 65242217, 22996533, + 63745412, 27113307, + ]), + xy2d: FieldElement2625::from_limbs([ + 50106456, 5906789, 221599, 26991285, 7828207, 20305514, 24362660, 31546264, + 53242455, 7421391, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 75248772, 27007934, 99366509, 27663885, 97484582, 1886180, 113042620, 48995682, + 95935221, 29431402, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 6267067, 9695052, 7709135, 16950835, 34239795, 31668296, 14795159, 25714308, + 13746020, 31812384, + ]), + xy2d: FieldElement2625::from_limbs([ + 28584883, 7787108, 60375922, 18503702, 22846040, 25983196, 63926927, 33190907, + 4771361, 25134474, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 92058101, 6376278, 39642383, 25379823, 48462709, 23623825, 100652432, 54967168, + 70678489, 44897024, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 26514970, 4740088, 27912651, 3697550, 19331575, 22082093, 6809885, 4608608, + 7325975, 18753361, + ]), + xy2d: FieldElement2625::from_limbs([ + 55490446, 19000001, 42787651, 7655127, 65739590, 5214311, 39708324, 10258389, + 49462170, 25367739, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 11431185, 49377439, 93679108, 47883555, 85138853, 38350513, 35662684, 49135095, + 76389221, 29580744, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 66948081, 23228174, 44253547, 29249434, 46247496, 19933429, 34297962, 22372809, + 51563772, 4387440, + ]), + xy2d: FieldElement2625::from_limbs([ + 46309467, 12194511, 3937617, 27748540, 39954043, 9340369, 42594872, 8548136, + 20617071, 26072431, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 66170039, 29623845, 58394552, 49679149, 91711988, 27329038, 53333511, 55233041, + 91454545, 10325459, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 47253587, 31985546, 44906155, 8714033, 14007766, 6928528, 16318175, 32543743, + 4766742, 3552007, + ]), + xy2d: FieldElement2625::from_limbs([ + 45357481, 16823515, 1351762, 32751011, 63099193, 3950934, 3217514, 14481909, + 10988822, 29559670, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 15564288, 19242862, 70210106, 39238579, 97555643, 25503075, 79785990, 27049088, + 58813011, 46850436, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 57666574, 6624295, 36809900, 21640754, 62437882, 31497052, 31521203, 9614054, + 37108040, 12074673, + ]), + xy2d: FieldElement2625::from_limbs([ + 4771172, 33419193, 14290748, 20464580, 27992297, 14998318, 65694928, 31997715, + 29832612, 17163397, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 7064865, 59567690, 115055764, 62041325, 48217593, 30641695, 92934105, 38847728, + 39986203, 46656021, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 64810282, 2439669, 59642254, 1719964, 39841323, 17225986, 32512468, 28236839, + 36752793, 29363474, + ]), + xy2d: FieldElement2625::from_limbs([ + 37102324, 10162315, 33928688, 3981722, 50626726, 20484387, 14413973, 9515896, + 19568978, 9628812, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 33053784, 33753789, 83003454, 35137490, 94489106, 28973996, 49269969, 61002024, + 60817076, 36992171, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 48129987, 3884492, 19469877, 12726490, 15913552, 13614290, 44147131, 70103, + 7463304, 4176122, + ]), + xy2d: FieldElement2625::from_limbs([ + 39984863, 10659916, 11482427, 17484051, 12771466, 26919315, 34389459, 28231680, + 24216881, 5944158, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 76002989, 41005405, 64444714, 57343111, 106137209, 21165315, 19345745, 48235228, + 78741856, 5847884, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 26942781, 31239115, 9129563, 28647825, 26024104, 11769399, 55590027, 6367193, + 57381634, 4782139, + ]), + xy2d: FieldElement2625::from_limbs([ + 19916442, 28726022, 44198159, 22140040, 25606323, 27581991, 33253852, 8220911, + 6358847, 31680575, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 67910273, 31472729, 16569427, 44619599, 29875703, 33651059, 75017251, 29073951, + 53570360, 34941586, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 19646058, 5720633, 55692158, 12814208, 11607948, 12749789, 14147075, 15156355, + 45242033, 11835259, + ]), + xy2d: FieldElement2625::from_limbs([ + 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, + 40548314, 5052482, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 64091413, 43612637, 69089700, 37518674, 22160965, 12322533, 60677741, 20936246, + 12228556, 26550755, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 32944382, 14922211, 44263970, 5188527, 21913450, 24834489, 4001464, 13238564, + 60994061, 8653814, + ]), + xy2d: FieldElement2625::from_limbs([ + 22865569, 28901697, 27603667, 21009037, 14348957, 8234005, 24808405, 5719875, + 28483275, 2841751, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 117796741, 32441125, 66781144, 21446575, 21886281, 51556090, 65220896, 33238773, + 87040921, 20815228, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 55452759, 10087520, 58243976, 28018288, 47830290, 30498519, 3999227, 13239134, + 62331395, 19644223, + ]), + xy2d: FieldElement2625::from_limbs([ + 1382174, 21859713, 17266789, 9194690, 53784508, 9720080, 20403944, 11284705, + 53095046, 3093229, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 83759766, 56070931, 66044684, 35125060, 58779117, 40907184, 66806439, 16271224, + 43059443, 26862581, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 45197768, 27626490, 62497547, 27994275, 35364760, 22769138, 24123613, 15193618, + 45456747, 16815042, + ]), + xy2d: FieldElement2625::from_limbs([ + 57172930, 29264984, 41829040, 4372841, 2087473, 10399484, 31870908, 14690798, + 17361620, 11864968, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 55801216, 39764803, 80315437, 39360751, 105200035, 19587230, 54777658, 26067830, + 41530403, 50868174, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 14668443, 21284197, 26039038, 15305210, 25515617, 4542480, 10453892, 6577524, + 9145645, 27110552, + ]), + xy2d: FieldElement2625::from_limbs([ + 5974855, 3053895, 57675815, 23169240, 35243739, 3225008, 59136222, 3936127, + 61456591, 30504127, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 97734231, 28825031, 41552902, 20761565, 46624288, 41249530, 17097187, 50805368, + 106217947, 35358062, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 63555773, 9865098, 61880298, 4272700, 61435032, 16864731, 14911343, 12196514, + 45703375, 7047411, + ]), + xy2d: FieldElement2625::from_limbs([ + 20093258, 9920966, 55970670, 28210574, 13161586, 12044805, 34252013, 4124600, + 34765036, 23296865, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 46320021, 14084653, 53577151, 41396578, 19119037, 19731827, 71861240, 24839791, + 45429205, 35842469, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 40289628, 30270716, 29965058, 3039786, 52635099, 2540456, 29457502, 14625692, + 42289247, 12570231, + ]), + xy2d: FieldElement2625::from_limbs([ + 66045306, 22002608, 16920317, 12494842, 1278292, 27685323, 45948920, 30055751, + 55134159, 4724942, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 85069815, 21778897, 62967895, 23851901, 58232301, 32143814, 54201480, 24894499, + 104641427, 35458286, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 23134274, 19275300, 56426866, 31942495, 20684484, 15770816, 54119114, 3190295, + 26955097, 14109738, + ]), + xy2d: FieldElement2625::from_limbs([ + 15308788, 5320727, 36995055, 19235554, 22902007, 7767164, 29425325, 22276870, + 31960941, 11934971, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 39713134, 41990227, 71218507, 12222638, 109589860, 14818667, 87747037, 38429459, + 77600255, 34934149, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 53949449, 9197840, 3875503, 24618324, 65725151, 27674630, 33518458, 16176658, + 21432314, 12180697, + ]), + xy2d: FieldElement2625::from_limbs([ + 55321537, 11500837, 13787581, 19721842, 44678184, 10140204, 1465425, 12689540, + 56807545, 19681548, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 72522936, 18168390, 46101199, 43198001, 79943833, 34740580, 64485947, 32212200, + 26128230, 39587344, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 40771450, 19788269, 32496024, 19900513, 17847800, 20885276, 3604024, 8316894, + 41233830, 23117073, + ]), + xy2d: FieldElement2625::from_limbs([ + 3296484, 6223048, 24680646, 21307972, 44056843, 5903204, 58246567, 28915267, + 12376616, 3188849, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 29190450, 18895386, 27549112, 32370916, 70628929, 22857130, 32049514, 26245319, + 50999629, 57256556, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 52364359, 24245275, 735817, 32955454, 46701176, 28496527, 25246077, 17758763, + 18640740, 32593455, + ]), + xy2d: FieldElement2625::from_limbs([ + 60180029, 17123636, 10361373, 5642961, 4910474, 12345252, 35470478, 33060001, + 10530746, 1053335, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 104951742, 52922057, 120679510, 54991489, 47651803, 56453479, 102755357, 30605445, + 24018830, 48581076, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 44516310, 30409154, 64819587, 5953842, 53668675, 9425630, 25310643, 13003497, + 64794073, 18408815, + ]), + xy2d: FieldElement2625::from_limbs([ + 39688860, 32951110, 59064879, 31885314, 41016598, 13987818, 39811242, 187898, + 43942445, 31022696, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 45364447, 19743956, 68953703, 38575859, 123783328, 17642957, 76825530, 49821353, + 62038646, 34280530, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 29370903, 27500434, 7334070, 18212173, 9385286, 2247707, 53446902, 28714970, + 30007387, 17731091, + ]), + xy2d: FieldElement2625::from_limbs([ + 66172485, 16086690, 23751945, 33011114, 65941325, 28365395, 9137108, 730663, + 9835848, 4555336, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 43732410, 34964877, 44855110, 54209249, 97976497, 49381408, 17693929, 34099128, + 55123565, 45977077, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 31117226, 21338698, 53606025, 6561946, 57231997, 20796761, 61990178, 29457725, + 29120152, 13924425, + ]), + xy2d: FieldElement2625::from_limbs([ + 49707966, 19321222, 19675798, 30819676, 56101901, 27695611, 57724924, 22236731, + 7240930, 33317044, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 35747087, 22207651, 119210280, 27698212, 111764387, 54956091, 68331198, 37943914, + 70402500, 51557120, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 50424044, 19110186, 11038543, 11054958, 53307689, 30215898, 42789283, 7733546, + 12796905, 27218610, + ]), + xy2d: FieldElement2625::from_limbs([ + 58349431, 22736595, 41689999, 10783768, 36493307, 23807620, 38855524, 3647835, + 3222231, 22393970, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 85714958, 35247531, 108769341, 51938590, 71221215, 43599452, 23603892, 31506198, + 59558087, 36039416, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 9255298, 30423235, 54952701, 32550175, 13098012, 24339566, 16377219, 31451620, + 47306788, 30519729, + ]), + xy2d: FieldElement2625::from_limbs([ + 44379556, 7496159, 61366665, 11329248, 19991973, 30206930, 35390715, 9936965, + 37011176, 22935634, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 88987435, 28553134, 71447199, 47198328, 64071998, 13160959, 86817760, 5415496, + 59748361, 29445138, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 27736842, 10103576, 12500508, 8502413, 63695848, 23920873, 10436917, 32004156, + 43449720, 25422331, + ]), + xy2d: FieldElement2625::from_limbs([ + 19492550, 21450067, 37426887, 32701801, 63900692, 12403436, 30066266, 8367329, + 13243957, 8709688, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 79123950, 36355692, 95306994, 10151020, 91926984, 28811298, 55914672, 27908697, + 72259831, 40828617, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 2831347, 21062286, 1478974, 6122054, 23825128, 20820846, 31097298, 6083058, + 31021603, 23760822, + ]), + xy2d: FieldElement2625::from_limbs([ + 64578913, 31324785, 445612, 10720828, 53259337, 22048494, 43601132, 16354464, + 15067285, 19406725, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 74949787, 47592304, 100852864, 49488446, 66380650, 29911725, 88512851, 34612017, + 47729401, 21151211, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 915865, 17085158, 15608284, 24765302, 42751837, 6060029, 49737545, 8410996, + 59888403, 16527024, + ]), + xy2d: FieldElement2625::from_limbs([ + 32922597, 32997445, 20336073, 17369864, 10903704, 28169945, 16957573, 52992, + 23834301, 6588044, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 32752011, 44787382, 70490858, 24839565, 22652987, 22810329, 17159698, 50243539, + 46794283, 32248439, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 62419196, 9166775, 41398568, 22707125, 11576751, 12733943, 7924251, 30802151, + 1976122, 26305405, + ]), + xy2d: FieldElement2625::from_limbs([ + 21251203, 16309901, 64125849, 26771309, 30810596, 12967303, 156041, 30183180, + 12331344, 25317235, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 75760459, 29077399, 118132091, 28557436, 80111370, 36505236, 96163290, 28447461, + 77116999, 28886530, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 31486061, 15114593, 52847614, 12951353, 14369431, 26166587, 16347320, 19892343, + 8684154, 23021480, + ]), + xy2d: FieldElement2625::from_limbs([ + 19443825, 11385320, 24468943, 23895364, 43189605, 2187568, 40845657, 27467510, + 31316347, 14219878, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 38514355, 1193784, 99354083, 11392484, 31092169, 49277233, 94254877, 40546840, + 29126554, 42761822, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 32382916, 1110093, 18477781, 11028262, 39697101, 26006320, 62128346, 10843781, + 59151264, 19118701, + ]), + xy2d: FieldElement2625::from_limbs([ + 2814918, 7836403, 27519878, 25686276, 46214848, 22000742, 45614304, 8550129, + 28346258, 1994730, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 47530546, 41639976, 53108344, 29605809, 69894701, 17323124, 47591912, 40729325, + 22628101, 41669612, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 36703732, 955510, 55975026, 18476362, 34661776, 20276352, 41457285, 3317159, + 57165847, 930271, + ]), + xy2d: FieldElement2625::from_limbs([ + 51805164, 26720662, 28856489, 1357446, 23421993, 1057177, 24091212, 32165462, + 44343487, 22903716, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 44357614, 28250434, 54201256, 54339997, 51297351, 25757378, 52269845, 50554643, + 65241844, 41953401, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 35139535, 2106402, 62372504, 1362500, 12813763, 16200670, 22981545, 27263159, + 18009407, 17781660, + ]), + xy2d: FieldElement2625::from_limbs([ + 49887941, 24009210, 39324209, 14166834, 29815394, 7444469, 29551787, 29827013, + 19288548, 1325865, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 82209002, 51273111, 110293748, 32549332, 107767535, 49063838, 79485593, 30075285, + 100274970, 25511681, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 20909212, 13023121, 57899112, 16251777, 61330449, 25459517, 12412150, 10018715, + 2213263, 19676059, + ]), + xy2d: FieldElement2625::from_limbs([ + 32529814, 22479743, 30361438, 16864679, 57972923, 1513225, 22922121, 6382134, + 61341936, 8371347, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77032307, 44825931, 79725657, 37099153, 104219359, 31832804, 12891686, 25361300, + 40665920, 44040575, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 44511638, 26541766, 8587002, 25296571, 4084308, 20584370, 361725, 2610596, + 43187334, 22099236, + ]), + xy2d: FieldElement2625::from_limbs([ + 5408392, 32417741, 62139741, 10561667, 24145918, 14240566, 31319731, 29318891, + 19985174, 30118346, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 53114388, 50171252, 81658109, 36895530, 99264821, 13648975, 49531796, 8849296, + 67173894, 41925115, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 58787919, 21504805, 31204562, 5839400, 46481576, 32497154, 47665921, 6922163, + 12743482, 23753914, + ]), + xy2d: FieldElement2625::from_limbs([ + 64747493, 12678784, 28815050, 4759974, 43215817, 4884716, 23783145, 11038569, + 18800704, 255233, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 61839168, 31780545, 13957885, 41545147, 23132994, 34283205, 80502710, 42621388, + 86367551, 52355070, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 64172210, 22726896, 56676774, 14516792, 63468078, 4372540, 35173943, 2209389, + 65584811, 2055793, + ]), + xy2d: FieldElement2625::from_limbs([ + 580882, 16705327, 5468415, 30871414, 36182444, 18858431, 59905517, 24560042, + 37087844, 7394434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 90947654, 35377159, 118479284, 48797157, 75426955, 29821327, 45436683, 30062226, + 62287122, 48354352, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 13345610, 9759151, 3371034, 17416641, 16353038, 8577942, 31129804, 13496856, + 58052846, 7402517, + ]), + xy2d: FieldElement2625::from_limbs([ + 2286874, 29118501, 47066405, 31546095, 53412636, 5038121, 11006906, 17794080, + 8205060, 1607563, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 81522931, 25552299, 70440693, 63900646, 89358013, 27960243, 85473524, 30647473, + 30019586, 24525154, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 39420813, 1585952, 56333811, 931068, 37988643, 22552112, 52698034, 12029092, + 9944378, 8024, + ]), + xy2d: FieldElement2625::from_limbs([ + 4368715, 29844802, 29874199, 18531449, 46878477, 22143727, 50994269, 32555346, + 58966475, 5640029, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77408455, 13746482, 11661824, 16234854, 74739102, 5998373, 76918751, 16859867, + 82328661, 19226648, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 27425505, 27835351, 3055005, 10660664, 23458024, 595578, 51710259, 32381236, + 48766680, 9742716, + ]), + xy2d: FieldElement2625::from_limbs([ + 6744077, 2427284, 26042789, 2720740, 66260958, 1118973, 32324614, 7406442, + 12420155, 1994844, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 81121366, 62084143, 115833273, 23975961, 107732385, 29617991, 121184249, 22644627, + 91428792, 27108098, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 16412671, 29047065, 10772640, 15929391, 50040076, 28895810, 10555944, 23070383, + 37006495, 28815383, + ]), + xy2d: FieldElement2625::from_limbs([ + 22397363, 25786748, 57815702, 20761563, 17166286, 23799296, 39775798, 6199365, + 21880021, 21303672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 62825538, 5368522, 35991846, 41717820, 103894664, 36763558, 83666014, 42445160, + 75949308, 38512191, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 51661137, 709326, 60189418, 22684253, 37330941, 6522331, 45388683, 12130071, + 52312361, 5005756, + ]), + xy2d: FieldElement2625::from_limbs([ + 64994094, 19246303, 23019041, 15765735, 41839181, 6002751, 10183197, 20315106, + 50713577, 31378319, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 115191953, 35186435, 80575154, 59113763, 110577275, 16573535, 35094956, 30497327, + 22208661, 35554900, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 3065054, 32141671, 41510189, 33192999, 49425798, 27851016, 58944651, 11248526, + 63417650, 26140247, + ]), + xy2d: FieldElement2625::from_limbs([ + 10379208, 27508878, 8877318, 1473647, 37817580, 21046851, 16690914, 2553332, + 63976176, 16400288, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 82825513, 34808697, 115745037, 41000704, 58659945, 6344163, 45011593, 26268851, + 26894936, 42686498, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 24158868, 12938817, 11085297, 25376834, 39045385, 29097348, 36532400, 64451, + 60291780, 30861549, + ]), + xy2d: FieldElement2625::from_limbs([ + 13488534, 7794716, 22236231, 5989356, 25426474, 20976224, 2350709, 30135921, + 62420857, 2364225, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 83443897, 9132433, 92749446, 40233319, 68834491, 42072368, 55301839, 21856974, + 15445874, 25756331, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 29004188, 25687351, 28661401, 32914020, 54314860, 25611345, 31863254, 29418892, + 66830813, 17795152, + ]), + xy2d: FieldElement2625::from_limbs([ + 60986784, 18687766, 38493958, 14569918, 56250865, 29962602, 10343411, 26578142, + 37280576, 22738620, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 94190495, 37018415, 14099041, 29036828, 68725166, 27348827, 96651499, 15372178, + 84402661, 34515140, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 20263915, 11434237, 61343429, 11236809, 13505955, 22697330, 50997518, 6493121, + 47724353, 7639713, + ]), + xy2d: FieldElement2625::from_limbs([ + 64278047, 18715199, 25403037, 25339236, 58791851, 17380732, 18006286, 17510682, + 29994676, 17746311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 76878673, 38757082, 110060329, 19923038, 106166724, 21992806, 42495722, 53248081, + 35924287, 34263895, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 12286395, 13076066, 45333675, 32377809, 42105665, 4057651, 35090736, 24663557, + 16102006, 13205847, + ]), + xy2d: FieldElement2625::from_limbs([ + 13733362, 5599946, 10557076, 3195751, 61550873, 8536969, 41568694, 8525971, + 10151379, 10394400, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 71133505, 17416880, 89545125, 12276533, 58009849, 64422764, 86807091, 11743038, + 100915394, 42488844, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 51229064, 29029191, 58528116, 30620370, 14634844, 32856154, 57659786, 3137093, + 55571978, 11721157, + ]), + xy2d: FieldElement2625::from_limbs([ + 17555920, 28540494, 8268605, 2331751, 44370049, 9761012, 9319229, 8835153, + 57903375, 32274386, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 66647436, 25724417, 87722981, 16688287, 59594098, 28747312, 89409167, 34059860, + 73217325, 27371016, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 62038564, 12367916, 36445330, 3234472, 32617080, 25131790, 29880582, 20071101, + 40210373, 25686972, + ]), + xy2d: FieldElement2625::from_limbs([ + 35133562, 5726538, 26934134, 10237677, 63935147, 32949378, 24199303, 3795095, + 7592688, 18562353, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 21594413, 18590204, 84575271, 63031641, 32537082, 36294330, 73516586, 12018832, + 38852812, 37852843, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 46458361, 21592935, 39872588, 570497, 3767144, 31836892, 13891941, 31985238, + 13717173, 10805743, + ]), + xy2d: FieldElement2625::from_limbs([ + 52432215, 17910135, 15287173, 11927123, 24177847, 25378864, 66312432, 14860608, + 40169934, 27690595, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 80071405, 38866230, 57048095, 45212711, 85964149, 25600230, 80395126, 54300159, + 62727806, 9882021, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 18512060, 11319350, 46985740, 15090308, 18818594, 5271736, 44380960, 3666878, + 43141434, 30255002, + ]), + xy2d: FieldElement2625::from_limbs([ + 60319844, 30408388, 16192428, 13241070, 15898607, 19348318, 57023983, 26893321, + 64705764, 5276064, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 97278672, 28236783, 93415069, 55358004, 94923826, 40623698, 74261714, 37239413, + 68558087, 13082860, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10342807, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, + 46092426, 25352431, + ]), + xy2d: FieldElement2625::from_limbs([ + 33958735, 3261607, 22745853, 7948688, 19370557, 18376767, 40936887, 6482813, + 56808784, 22494330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 32869439, 61700319, 25609741, 49233102, 56421094, 51637792, 26112419, 36075440, + 44444575, 40459246, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 29506904, 4457497, 3377935, 23757988, 36598817, 12935079, 1561737, 3841096, + 38105225, 26896789, + ]), + xy2d: FieldElement2625::from_limbs([ + 10340844, 26924055, 48452231, 31276001, 12621150, 20215377, 30878496, 21730062, + 41524312, 5181965, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 25940096, 20896407, 17324187, 56801490, 58437394, 15029093, 91505116, 17103509, + 64786011, 21165857, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 45343161, 9916822, 65808455, 4079497, 66080518, 11909558, 1782390, 12641087, + 20603771, 26992690, + ]), + xy2d: FieldElement2625::from_limbs([ + 48226577, 21881051, 24849421, 11501709, 13161720, 28785558, 1925522, 11914390, + 4662781, 7820689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 79349895, 33128449, 75241554, 42948365, 32846759, 31954812, 29749455, 45727356, + 83245615, 48818451, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56758909, 18873868, 58896884, 2330219, 49446315, 19008651, 10658212, 6671822, + 19012087, 3772772, + ]), + xy2d: FieldElement2625::from_limbs([ + 3753511, 30133366, 10617073, 2028709, 14841030, 26832768, 28718731, 17791548, + 20527770, 12988982, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 52286341, 27757162, 63400876, 12689772, 66209881, 22639565, 110034681, 56543919, + 70408527, 54683910, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 50331161, 18301130, 57466446, 4978982, 3308785, 8755439, 6943197, 6461331, + 41525717, 8991217, + ]), + xy2d: FieldElement2625::from_limbs([ + 49882601, 1816361, 65435576, 27467992, 31783887, 25378441, 34160718, 7417949, + 36866577, 1507264, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 29692644, 40384323, 56610063, 37889327, 88054838, 21647935, 38221255, 41763822, + 14606361, 22907359, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 63627275, 8707080, 32188102, 5672294, 22096700, 1711240, 34088169, 9761486, + 4170404, 31469107, + ]), + xy2d: FieldElement2625::from_limbs([ + 55521375, 14855944, 62981086, 32022574, 40459774, 15084045, 22186522, 16002000, + 52832027, 25153633, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 62297389, 47315460, 35404986, 31070512, 63796392, 41423478, 59995291, 23934339, + 80349708, 44520301, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 59366301, 25297669, 52340529, 19898171, 43876480, 12387165, 4498947, 14147411, + 29514390, 4302863, + ]), + xy2d: FieldElement2625::from_limbs([ + 53695440, 21146572, 20757301, 19752600, 14785142, 8976368, 62047588, 31410058, + 17846987, 19582505, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 64864393, 32799703, 62511833, 32488122, 60861691, 35009730, 112569999, 24339641, + 61886162, 46204698, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 57202067, 17484121, 21134159, 12198166, 40044289, 708125, 387813, 13770293, + 47974538, 10958662, + ]), + xy2d: FieldElement2625::from_limbs([ + 22470984, 12369526, 23446014, 28113323, 45588061, 23855708, 55336367, 21979976, + 42025033, 4271861, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 109048144, 57055220, 47199530, 48916026, 61124505, 35713623, 67184238, 62830334, + 101691505, 42024103, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 15854951, 4148314, 58214974, 7259001, 11666551, 13824734, 36577666, 2697371, + 24154791, 24093489, + ]), + xy2d: FieldElement2625::from_limbs([ + 15446137, 17747788, 29759746, 14019369, 30811221, 23944241, 35526855, 12840103, + 24913809, 9815020, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 62399559, 27940162, 35267365, 21265538, 52665326, 44353845, 125114051, 46993199, + 85843991, 43020669, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 11933045, 9281483, 5081055, 28370608, 64480701, 28648802, 59381042, 22658328, + 44380208, 16199063, + ]), + xy2d: FieldElement2625::from_limbs([ + 14576810, 379472, 40322331, 25237195, 37682355, 22741457, 67006097, 1876698, + 30801119, 2164795, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 15995067, 36754305, 13672554, 13712240, 47730029, 62461217, 121136116, 51612593, + 53616055, 34822483, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56818250, 29895392, 63822271, 10948817, 23037027, 3794475, 63638526, 20954210, + 50053494, 3565903, + ]), + xy2d: FieldElement2625::from_limbs([ + 29210069, 24135095, 61189071, 28601646, 10834810, 20226706, 50596761, 22733718, + 39946641, 19523900, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 121055819, 49063018, 83772567, 25398281, 38758921, 42573554, 37925442, 29785008, + 69352974, 19552452, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 61955989, 29753495, 57802388, 27482848, 16243068, 14684434, 41435776, 17373631, + 13491505, 4641841, + ]), + xy2d: FieldElement2625::from_limbs([ + 10813398, 643330, 47920349, 32825515, 30292061, 16954354, 27548446, 25833190, + 14476988, 20787001, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77400943, 9984944, 73590300, 41834336, 59857349, 40587174, 27282936, 31910173, + 106304917, 12651322, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 35923332, 32741048, 22271203, 11835308, 10201545, 15351028, 17099662, 3988035, + 21721536, 30405492, + ]), + xy2d: FieldElement2625::from_limbs([ + 10202177, 27008593, 35735631, 23979793, 34958221, 25434748, 54202543, 3852693, + 13216206, 14842320, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 51293205, 22953365, 60569911, 26295436, 60124204, 26972653, 35608016, 47320255, + 106783330, 43454614, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 14465486, 19721101, 34974879, 18815558, 39665676, 12990491, 33046193, 15796406, + 60056998, 25514317, + ]), + xy2d: FieldElement2625::from_limbs([ + 30924398, 25274812, 6359015, 20738097, 16508376, 9071735, 41620263, 15413634, + 9524356, 26535554, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 12274182, 20378885, 99736504, 65323537, 73845487, 13267304, 72346523, 28444948, + 82772379, 37590215, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 64157555, 8903984, 17349946, 601635, 50676049, 28941875, 53376124, 17665097, + 44850385, 4659090, + ]), + xy2d: FieldElement2625::from_limbs([ + 50192582, 28601458, 36715152, 18395610, 20774811, 15897498, 5736189, 15026997, + 64930608, 20098846, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 58249865, 31335375, 28571665, 56953346, 66634395, 23448733, 63307367, 33832526, + 23440561, 33264224, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10226222, 27625730, 15139955, 120818, 52241171, 5218602, 32937275, 11551483, + 50536904, 26111567, + ]), + xy2d: FieldElement2625::from_limbs([ + 17932739, 21117156, 43069306, 10749059, 11316803, 7535897, 22503767, 5561594, + 63462240, 3898660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 74858752, 32584864, 50769132, 33537967, 42090752, 15122142, 65535333, 40706961, + 88940025, 34799664, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 26958440, 18896406, 4314585, 8346991, 61431100, 11960071, 34519569, 32934396, + 36706772, 16838219, + ]), + xy2d: FieldElement2625::from_limbs([ + 54942968, 9166946, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, + 44770839, 13987524, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 109867800, 7778773, 88224864, 49127028, 62275597, 28196653, 62807965, 28429792, + 59639082, 30696363, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 9681908, 26817309, 35157219, 13591837, 60225043, 386949, 31622781, 6439245, + 52527852, 4091396, + ]), + xy2d: FieldElement2625::from_limbs([ + 58682418, 1470726, 38999185, 31957441, 3978626, 28430809, 47486180, 12092162, + 29077877, 18812444, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 72378032, 26694705, 120987516, 25533715, 25932562, 35317984, 61502753, 28048550, + 47091016, 2357888, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 32264008, 18146780, 61721128, 32394338, 65017541, 29607531, 23104803, 20684524, + 5727337, 189038, + ]), + xy2d: FieldElement2625::from_limbs([ + 14609104, 24599962, 61108297, 16931650, 52531476, 25810533, 40363694, 10942114, + 41219933, 18669734, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 87622345, 39112362, 51504250, 41383962, 93522806, 31535027, 45729895, 41026212, + 13913676, 28416557, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 41534488, 11967825, 29233242, 12948236, 60354399, 4713226, 58167894, 14059179, + 12878652, 8511905, + ]), + xy2d: FieldElement2625::from_limbs([ + 41452044, 3393630, 64153449, 26478905, 64858154, 9366907, 36885446, 6812973, + 5568676, 30426776, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 78738868, 12144453, 69225203, 47160468, 94487748, 49231348, 49700110, 20050058, + 119822531, 8070816, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 27117677, 23547054, 35826092, 27984343, 1127281, 12772488, 37262958, 10483305, + 55556115, 32525717, + ]), + xy2d: FieldElement2625::from_limbs([ + 10637467, 27866368, 5674780, 1072708, 40765276, 26572129, 65424888, 9177852, + 39615702, 15431202, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 87633990, 44446997, 121475255, 12779441, 104724694, 16150073, 105977209, 14943140, + 52052074, 25618500, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 37084402, 5626925, 66557297, 23573344, 753597, 11981191, 25244767, 30314666, + 63752313, 9594023, + ]), + xy2d: FieldElement2625::from_limbs([ + 43356201, 2636869, 61944954, 23450613, 585133, 7877383, 11345683, 27062142, + 13352334, 22577348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 65177046, 28146973, 70413512, 54223994, 84124668, 62231772, 104433876, 25801948, + 53893326, 33235227, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 20239939, 6607058, 6203985, 3483793, 48721888, 32775202, 46385121, 15077869, + 44358105, 14523816, + ]), + xy2d: FieldElement2625::from_limbs([ + 27406023, 27512775, 27423595, 29057038, 4996213, 10002360, 38266833, 29008937, + 36936121, 28748764, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 78483087, 12660714, 17861383, 21013599, 78044431, 34653658, 53222787, 24462691, + 106490683, 44912934, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 54378055, 10311866, 1510375, 10778093, 64989409, 24408729, 32676002, 11149336, + 40985213, 4985767, + ]), + xy2d: FieldElement2625::from_limbs([ + 48012542, 341146, 60911379, 33315398, 15756972, 24757770, 66125820, 13794113, + 47694557, 17933176, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 73598907, 45494717, 25495922, 59382504, 75777235, 24803115, 70476466, 40524436, + 65417798, 58104073, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 1656478, 13457317, 15370807, 6364910, 13605745, 8362338, 47934242, 28078708, + 50312267, 28522993, + ]), + xy2d: FieldElement2625::from_limbs([ + 44835530, 20030007, 67044178, 29220208, 48503227, 22632463, 46537798, 26546453, + 67009010, 23317098, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 84856310, 43593691, 86477162, 29503840, 46478228, 51067577, 99101545, 17696455, + 104957364, 28042459, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 31932008, 28568291, 47496481, 16366579, 22023614, 88450, 11371999, 29810185, + 4882241, 22927527, + ]), + xy2d: FieldElement2625::from_limbs([ + 29796488, 37186, 19818052, 10115756, 55279832, 3352735, 18551198, 3272828, + 61917932, 29392022, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 12501267, 4044383, 58495907, 53716478, 101787674, 38691029, 47878485, 30024734, + 330069, 29895023, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 6384877, 2899513, 17807477, 7663917, 64749976, 12363164, 25366522, 24980540, + 66837568, 12071498, + ]), + xy2d: FieldElement2625::from_limbs([ + 58743349, 29511910, 25133447, 29037077, 60897836, 2265926, 34339246, 1936674, + 61949167, 3829362, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 28425947, 27718999, 66531773, 28857233, 120000172, 40425360, 75030413, 26986644, + 26333139, 47822096, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56041645, 11871230, 27385719, 22994888, 62522949, 22365119, 10004785, 24844944, + 45347639, 8930323, + ]), + xy2d: FieldElement2625::from_limbs([ + 45911060, 17158396, 25654215, 31829035, 12282011, 11008919, 1541940, 4757911, + 40617363, 17145491, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 80646107, 25794941, 113612887, 44516357, 61186043, 20336366, 53952279, 39771685, + 118274028, 47369420, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 49686272, 15157789, 18705543, 29619, 24409717, 33293956, 27361680, 9257833, + 65152338, 31777517, + ]), + xy2d: FieldElement2625::from_limbs([ + 42063564, 23362465, 15366584, 15166509, 54003778, 8423555, 37937324, 12361134, + 48422886, 4578289, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 91688613, 3711569, 68451186, 22374305, 107212592, 47679386, 44564334, 14074918, + 21964432, 41789689, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 60580251, 31142934, 9442965, 27628844, 12025639, 32067012, 64127349, 31885225, + 13006805, 2355433, + ]), + xy2d: FieldElement2625::from_limbs([ + 50803946, 19949172, 60476436, 28412082, 16974358, 22643349, 27202043, 1719366, + 1141648, 20758196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54244901, 53888877, 58790596, 56090772, 60298717, 28710537, 13475065, 30420460, + 32674894, 47269477, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 11423316, 28086373, 32344215, 8962751, 24989809, 9241752, 53843611, 16086211, + 38367983, 17912338, + ]), + xy2d: FieldElement2625::from_limbs([ + 65699196, 12530727, 60740138, 10847386, 19531186, 19422272, 55399715, 7791793, + 39862921, 4383346, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 38137947, 38825878, 65842854, 23817442, 121762491, 50287029, 62246456, 62202414, + 27193555, 39799623, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 51914908, 5362277, 65324971, 2695833, 4960227, 12840725, 23061898, 3260492, + 22510453, 8577507, + ]), + xy2d: FieldElement2625::from_limbs([ + 54476394, 11257345, 34415870, 13548176, 66387860, 10879010, 31168030, 13952092, + 37537372, 29918525, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 70986166, 23981692, 99525555, 38959755, 56104456, 19897796, 70868632, 45489751, + 72720723, 41718449, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 50833043, 14667796, 15906460, 12155291, 44997715, 24514713, 32003001, 24722143, + 5773084, 25132323, + ]), + xy2d: FieldElement2625::from_limbs([ + 43320746, 25300131, 1950874, 8937633, 18686727, 16459170, 66203139, 12376319, + 31632953, 190926, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 109624102, 17415545, 58684872, 13378745, 81271271, 6901327, 58820115, 38062995, + 41767308, 29926903, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 8884438, 27670423, 6023973, 10104341, 60227295, 28612898, 18722940, 18768427, + 65436375, 827624, + ]), + xy2d: FieldElement2625::from_limbs([ + 34388281, 17265135, 34605316, 7101209, 13354605, 2659080, 65308289, 19446395, + 42230385, 1541285, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 70010192, 32436744, 70989239, 57049475, 116596786, 29941649, 45306746, 29986950, + 87565708, 31669398, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 27019610, 12299467, 53450576, 31951197, 54247203, 28692960, 47568713, 28538373, + 29439640, 15138866, + ]), + xy2d: FieldElement2625::from_limbs([ + 21536104, 26928012, 34661045, 22864223, 44700786, 5175813, 61688824, 17193268, + 7779327, 109896, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 97388589, 48203181, 59063992, 39979989, 80748484, 32810922, 28698389, 45734550, + 23177718, 33000357, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 26572828, 3405927, 35407164, 12890904, 47843196, 5335865, 60615096, 2378491, + 4439158, 20275085, + ]), + xy2d: FieldElement2625::from_limbs([ + 44392139, 3489069, 57883598, 33221678, 18875721, 32414337, 14819433, 20822905, + 49391106, 28092994, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 62052362, 50120982, 83062524, 37322183, 56672364, 49181491, 66287909, 35731656, + 75658945, 18440266, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 48635543, 16596774, 66727204, 15663610, 22860960, 15585581, 39264755, 29971692, + 43848403, 25125843, + ]), + xy2d: FieldElement2625::from_limbs([ + 34628313, 15707274, 58902952, 27902350, 29464557, 2713815, 44383727, 15860481, + 45206294, 1494192, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 47546754, 53021470, 41524990, 24254879, 80236705, 34314140, 21923481, 16529112, + 75851568, 46521448, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 38643965, 1553204, 32536856, 23080703, 42417258, 33148257, 58194238, 30620535, + 37205105, 15553882, + ]), + xy2d: FieldElement2625::from_limbs([ + 21877890, 3230008, 9881174, 10539357, 62311749, 2841331, 11543572, 14513274, + 19375923, 20906471, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 75941133, 52613378, 80362373, 38692006, 72146734, 37633208, 24880817, 60886148, + 69971515, 9455042, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 29306751, 5123106, 20245049, 19404543, 9592565, 8447059, 65031740, 30564351, + 15511448, 4789663, + ]), + xy2d: FieldElement2625::from_limbs([ + 46429108, 7004546, 8824831, 24119455, 63063159, 29803695, 61354101, 108892, + 23513200, 16652362, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 100961536, 37699212, 62632834, 26975308, 77878902, 26398889, 60458447, 54172563, + 115898528, 43767290, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 2756062, 8598110, 7383731, 26694540, 22312758, 32449420, 21179800, 2600940, + 57120566, 21047965, + ]), + xy2d: FieldElement2625::from_limbs([ + 42463153, 13317461, 36659605, 17900503, 21365573, 22684775, 11344423, 864440, + 64609187, 16844368, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 107784906, 6148327, 49924452, 19080277, 85891792, 33278434, 44547329, 33765731, + 69828620, 38495428, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 65784982, 3911312, 60160120, 14759764, 37081714, 7851206, 21690126, 8518463, + 26699843, 5276295, + ]), + xy2d: FieldElement2625::from_limbs([ + 53958991, 27125364, 9396248, 365013, 24703301, 23065493, 1321585, 149635, 51656090, + 7159368, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77096625, 30149672, 84616825, 43059961, 76840398, 31388917, 89464872, 41866607, + 89586081, 25151046, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 18155857, 17049442, 19744715, 9006923, 15154154, 23015456, 24256459, 28689437, + 44560690, 9334108, + ]), + xy2d: FieldElement2625::from_limbs([ + 2986088, 28642539, 10776627, 30080588, 10620589, 26471229, 45695018, 14253544, + 44521715, 536905, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 71486582, 41670267, 91675941, 15495313, 78733938, 46619030, 74499414, 44144056, + 77946923, 51688439, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 47766460, 867879, 9277171, 30335973, 52677291, 31567988, 19295825, 17757482, + 6378259, 699185, + ]), + xy2d: FieldElement2625::from_limbs([ + 7895007, 4057113, 60027092, 20476675, 49222032, 33231305, 66392824, 15693154, + 62063800, 20180469, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 59371282, 27685029, 119651408, 26147511, 78494517, 46756047, 31730677, 22591592, + 63190227, 23885106, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10188286, 17783598, 59772502, 13427542, 22223443, 14896287, 30743455, 7116568, + 45322357, 5427592, + ]), + xy2d: FieldElement2625::from_limbs([ + 696102, 13206899, 27047647, 22922350, 15285304, 23701253, 10798489, 28975712, + 19236242, 12477404, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 55879406, 44798227, 50054593, 25513566, 66320635, 58940896, 63211193, 44734935, + 43939347, 41288075, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 17800790, 19518253, 40108434, 21787760, 23887826, 3149671, 23466177, 23016261, + 10322026, 15313801, + ]), + xy2d: FieldElement2625::from_limbs([ + 26246234, 11968874, 32263343, 28085704, 6830754, 20231401, 51314159, 33452449, + 42659621, 10890803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 35743198, 43825794, 54448238, 27287163, 83799070, 54046319, 119235514, 50039361, + 92289660, 28219547, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 66522290, 10376443, 34522450, 22268075, 19801892, 10997610, 2276632, 9482883, + 316878, 13820577, + ]), + xy2d: FieldElement2625::from_limbs([ + 57226037, 29044064, 64993357, 16457135, 56008783, 11674995, 30756178, 26039378, + 30696929, 29841583, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 100097781, 23951019, 12499365, 41465219, 56491606, 21622917, 59766047, 57123466, + 34759345, 7392472, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 58253184, 15927860, 9866406, 29905021, 64711949, 16898650, 36699387, 24419436, + 25112946, 30627788, + ]), + xy2d: FieldElement2625::from_limbs([ + 64604801, 33117465, 25621773, 27875660, 15085041, 28074555, 42223985, 20028237, + 5537437, 19640113, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 55883261, 2320284, 57524584, 10149186, 100773065, 5808646, 119341477, 31824763, + 98343453, 39645030, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 57475529, 116425, 26083934, 2897444, 60744427, 30866345, 609720, 15878753, + 60138459, 24519663, + ]), + xy2d: FieldElement2625::from_limbs([ + 39351007, 247743, 51914090, 24551880, 23288160, 23542496, 43239268, 6503645, + 20650474, 1804084, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 106627923, 49010854, 76081380, 42024039, 82749485, 37994278, 70230858, 56779150, + 94951478, 33352103, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 51801891, 2839643, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, + 55733782, 12714368, + ]), + xy2d: FieldElement2625::from_limbs([ + 20807691, 26283607, 29286140, 11421711, 39232341, 19686201, 45881388, 1035545, + 47375635, 12796919, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 79185725, 52807577, 58323861, 21705509, 42096072, 49955115, 49517368, 20654993, + 70589528, 51926048, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 34747315, 5457596, 28548107, 7833186, 7303070, 21600887, 42745799, 17632556, + 33734809, 2771024, + ]), + xy2d: FieldElement2625::from_limbs([ + 45719598, 421931, 26597266, 6860826, 22486084, 26817260, 49971378, 29344205, + 42556581, 15673396, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 46924223, 35892647, 19788684, 57487908, 63107597, 24813538, 46837679, 38287685, + 70836007, 20619983, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 6120100, 814863, 55314462, 32931715, 6812204, 17806661, 2019593, 7975683, 31123697, + 22595451, + ]), + xy2d: FieldElement2625::from_limbs([ + 30069250, 22119100, 30434653, 2958439, 18399564, 32578143, 12296868, 9204260, + 50676426, 9648164, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 32705413, 32003455, 97814521, 41005496, 55303257, 43186244, 70414129, 38803035, + 108209395, 22176929, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 17219846, 2375039, 35537917, 27978816, 47649184, 9219902, 294711, 15298639, + 2662509, 17257359, + ]), + xy2d: FieldElement2625::from_limbs([ + 65935918, 25995736, 62742093, 29266687, 45762450, 25120105, 32087528, 32331655, + 32247247, 19164571, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 14312609, 34775988, 17395389, 58408721, 62163121, 58424228, 106019982, 23916613, + 51081240, 20175586, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 65680039, 23875441, 57873182, 6549686, 59725795, 33085767, 23046501, 9803137, + 17597934, 2346211, + ]), + xy2d: FieldElement2625::from_limbs([ + 18510781, 15337574, 26171504, 981392, 44867312, 7827555, 43617730, 22231079, + 3059832, 21771562, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77250443, 39637338, 84938156, 31606788, 76938955, 13613135, 41552228, 28009845, + 33606651, 37146527, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 33114149, 17665080, 40583177, 20211034, 33076704, 8716171, 1151462, 1521897, + 66126199, 26716628, + ]), + xy2d: FieldElement2625::from_limbs([ + 34169699, 29298616, 23947180, 33230254, 34035889, 21248794, 50471177, 3891703, + 26353178, 693168, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 97483084, 35150011, 117333688, 46741361, 71709207, 33961335, 76694157, 33153763, + 31375463, 47924397, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 52738210, 25781902, 1510300, 6434173, 48324075, 27291703, 32732229, 20445593, + 17901440, 16011505, + ]), + xy2d: FieldElement2625::from_limbs([ + 18171223, 21619806, 54608461, 15197121, 56070717, 18324396, 47936623, 17508055, + 8764034, 12309598, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 73084753, 28311243, 47649501, 23872684, 55567586, 14015781, 110551971, 34782749, + 17544095, 22960650, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 5811932, 31839139, 3442886, 31285122, 48741515, 25194890, 49064820, 18144304, + 61543482, 12348899, + ]), + xy2d: FieldElement2625::from_limbs([ + 35709185, 11407554, 25755363, 6891399, 63851926, 14872273, 42259511, 8141294, + 56476330, 32968952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 121542424, 34248456, 62032718, 46854775, 81124121, 19103037, 124519055, 22225380, + 30944592, 1130208, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 8247747, 26843490, 40546482, 25845122, 52706924, 18905521, 4652151, 2488540, + 23550156, 33283200, + ]), + xy2d: FieldElement2625::from_limbs([ + 17294297, 29765994, 7026747, 15626851, 22990044, 113481, 2267737, 27646286, + 66700045, 33416712, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 83199930, 17300505, 85708115, 40895109, 69246500, 32332774, 63744702, 48105367, + 70369388, 26388160, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 62198760, 20221544, 18550886, 10864893, 50649539, 26262835, 44079994, 20349526, + 54360141, 2701325, + ]), + xy2d: FieldElement2625::from_limbs([ + 58534169, 16099414, 4629974, 17213908, 46322650, 27548999, 57090500, 9276970, + 11329923, 1862132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 14763057, 17650824, 103299457, 3689865, 70620756, 43867957, 45157775, 45773662, + 58070900, 32614131, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 8894987, 30108338, 6150752, 3013931, 301220, 15693451, 35127648, 30644714, + 51670695, 11595569, + ]), + xy2d: FieldElement2625::from_limbs([ + 15214943, 3537601, 40870142, 19495559, 4418656, 18323671, 13947275, 10730794, + 53619402, 29190761, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 64570539, 41237224, 99867876, 33817540, 104232996, 25598978, 111885603, 23365795, + 68085971, 34254425, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 54642373, 4195083, 57897332, 550903, 51543527, 12917919, 19118110, 33114591, + 36574330, 19216518, + ]), + xy2d: FieldElement2625::from_limbs([ + 31788442, 19046775, 4799988, 7372237, 8808585, 18806489, 9408236, 23502657, + 12493931, 28145115, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 41428258, 5260743, 47873055, 27269961, 63412921, 16566086, 94327144, 36161552, + 29375954, 6024730, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 842132, 30759739, 62345482, 24831616, 26332017, 21148791, 11831879, 6985184, + 57168503, 2854095, + ]), + xy2d: FieldElement2625::from_limbs([ + 62261602, 25585100, 2516241, 27706719, 9695690, 26333246, 16512644, 960770, + 12121869, 16648078, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 51890193, 48221527, 53772634, 35568148, 97707150, 33090294, 35603941, 25672367, + 20237805, 36392843, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 47820798, 4453151, 15298546, 17376044, 22115042, 17581828, 12544293, 20083975, + 1068880, 21054527, + ]), + xy2d: FieldElement2625::from_limbs([ + 57549981, 17035596, 33238497, 13506958, 30505848, 32439836, 58621956, 30924378, + 12521377, 4845654, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 106019188, 44298538, 64150483, 43754095, 74868174, 54020263, 70518210, 32681031, + 127735421, 20668560, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 43547042, 6230155, 46726851, 10655313, 43068279, 21933259, 10477733, 32314216, + 63995636, 13974497, + ]), + xy2d: FieldElement2625::from_limbs([ + 12966261, 15550616, 35069916, 31939085, 21025979, 32924988, 5642324, 7188737, + 18895762, 12629579, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 14741860, 18607545, 89286071, 21833194, 68388604, 41613031, 11758139, 34343875, + 32195180, 37450109, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10758205, 15755439, 62598914, 9243697, 62229442, 6879878, 64904289, 29988312, + 58126794, 4429646, + ]), + xy2d: FieldElement2625::from_limbs([ + 64654951, 15725972, 46672522, 23143759, 61304955, 22514211, 59972993, 21911536, + 18047435, 18272689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 41935825, 55801698, 29759954, 45331216, 111955344, 51288407, 78101976, 54258026, + 49488161, 57700395, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 21987233, 700364, 42603816, 14972007, 59334599, 27836036, 32155025, 2581431, + 37149879, 8773374, + ]), + xy2d: FieldElement2625::from_limbs([ + 41540495, 454462, 53896929, 16126714, 25240068, 8594567, 20656846, 12017935, + 59234475, 19634276, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 73137027, 39817509, 103205921, 55807152, 66289943, 36016203, 102376553, 61640820, + 65387074, 30777706, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 54829870, 16624276, 987579, 27631834, 32908202, 1248608, 7719845, 29387734, + 28408819, 6816612, + ]), + xy2d: FieldElement2625::from_limbs([ + 56750770, 25316602, 19549650, 21385210, 22082622, 16147817, 20613181, 13982702, + 56769294, 5067942, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 36602859, 29732664, 79183544, 13582411, 47230892, 35998382, 47389577, 12746131, + 72440074, 57002919, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 30528792, 3601899, 65151774, 4619784, 39747042, 18118043, 24180792, 20984038, + 27679907, 31905504, + ]), + xy2d: FieldElement2625::from_limbs([ + 9402385, 19597367, 32834042, 10838634, 40528714, 20317236, 26653273, 24868867, + 22611443, 20839026, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 89299435, 34672460, 22736440, 48684895, 103757035, 27563109, 86298488, 62459921, + 71963721, 40176570, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 58798126, 30600981, 58846284, 30166382, 56707132, 33282502, 13424425, 29987205, + 26404408, 13001963, + ]), + xy2d: FieldElement2625::from_limbs([ + 35867026, 18138731, 64114613, 8939345, 11562230, 20713762, 41044498, 21932711, + 51703708, 11020692, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 68974887, 59159374, 59210213, 23253421, 12483314, 47031979, 70284499, 21130268, + 28761761, 34961166, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 66660290, 31776765, 13018550, 3194501, 57528444, 22392694, 24760584, 29207344, + 25577410, 20175752, + ]), + xy2d: FieldElement2625::from_limbs([ + 42818486, 4759344, 66418211, 31701615, 2066746, 10693769, 37513074, 9884935, + 57739938, 4745409, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 57967561, 39604145, 47577802, 29213020, 102956929, 43498706, 51646855, 55797011, + 78040786, 21622500, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 50547351, 14112679, 59096219, 4817317, 59068400, 22139825, 44255434, 10856640, + 46638094, 13434653, + ]), + xy2d: FieldElement2625::from_limbs([ + 22759470, 23480998, 50342599, 31683009, 13637441, 23386341, 1765143, 20900106, + 28445306, 28189722, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 29875044, 46048045, 69904399, 63322533, 68819482, 48735613, 56913146, 24765756, + 9074233, 34721612, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 40903181, 11014232, 57266213, 30918946, 40200743, 7532293, 48391976, 24018933, + 3843902, 9367684, + ]), + xy2d: FieldElement2625::from_limbs([ + 56139269, 27150720, 9591133, 9582310, 11349256, 108879, 16235123, 8601684, + 66969667, 4242894, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 89201818, 53917740, 65066069, 21585919, 99295616, 55591475, 60534521, 36025091, + 106800361, 16625499, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56051142, 3042015, 13770083, 24296510, 584235, 33009577, 59338006, 2602724, + 39757248, 14247412, + ]), + xy2d: FieldElement2625::from_limbs([ + 6314156, 23289540, 34336361, 15957556, 56951134, 168749, 58490057, 14290060, + 27108877, 32373552, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 58522248, 26383465, 80350645, 44514587, 34117848, 19759835, 100656839, 22495542, + 107069276, 34536304, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 22833421, 9293594, 34459416, 19935764, 57971897, 14756818, 44180005, 19583651, + 56629059, 17356469, + ]), + xy2d: FieldElement2625::from_limbs([ + 59340277, 3326785, 38997067, 10783823, 19178761, 14905060, 22680049, 13906969, + 51175174, 3797898, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 88830182, 29341685, 54902740, 42864613, 63226624, 19901321, 90849087, 30845199, + 87600846, 59066711, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 9209251, 18419377, 53852306, 27386633, 66377847, 15289672, 25947805, 15286587, + 30997318, 26851369, + ]), + xy2d: FieldElement2625::from_limbs([ + 7392013, 16618386, 23946583, 25514540, 53843699, 32020573, 52911418, 31232855, + 17649997, 33304352, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 57807757, 52915036, 97718388, 30504888, 41933794, 32270679, 51867297, 24028707, + 64875610, 41216577, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 49550191, 1763593, 33994528, 15908609, 37067994, 21380136, 7335079, 25082233, + 63934189, 3440182, + ]), + xy2d: FieldElement2625::from_limbs([ + 47219164, 27577423, 42997570, 23865561, 10799742, 16982475, 40449, 29122597, + 4862399, 1133, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 34252636, 25680474, 61686474, 48415381, 50789832, 41510573, 74366924, 33866292, + 36513872, 26175010, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 63335436, 31988495, 28985339, 7499440, 24445838, 9325937, 29727763, 16527196, + 18278453, 15405622, + ]), + xy2d: FieldElement2625::from_limbs([ + 62726958, 8508651, 47210498, 29880007, 61124410, 15149969, 53795266, 843522, + 45233802, 13626196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 69390312, 20067376, 56193445, 30944521, 68988221, 49718638, 56324981, 37508223, + 80449702, 15928662, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 31727126, 26374577, 48671360, 25270779, 2875792, 17164102, 41838969, 26539605, + 43656557, 5964752, + ]), + xy2d: FieldElement2625::from_limbs([ + 4100401, 27594980, 49929526, 6017713, 48403027, 12227140, 40424029, 11344143, + 2538215, 25983677, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 57675240, 6123112, 78268667, 31397823, 97125143, 48520672, 46633880, 35039852, + 66479607, 17595569, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 40304287, 4260918, 11851389, 9658551, 35091757, 16367491, 46903439, 20363143, + 11659921, 22439314, + ]), + xy2d: FieldElement2625::from_limbs([ + 26180377, 10015009, 36264640, 24973138, 5418196, 9480663, 2231568, 23384352, + 33100371, 32248261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 82229958, 28352560, 56718958, 48982252, 39598926, 17561924, 88779810, 38041106, + 61177053, 19088051, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 16166467, 24070699, 56004733, 6023907, 35182066, 32189508, 2340059, 17299464, + 56373093, 23514607, + ]), + xy2d: FieldElement2625::from_limbs([ + 28042865, 29997343, 54982337, 12259705, 63391366, 26608532, 6766452, 24864833, + 18036435, 5803270, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 66291264, 40318343, 78912424, 35140016, 78067310, 30883266, 23855390, 4598332, + 60949433, 19436993, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 36077558, 19298237, 17332028, 31170912, 31312681, 27587249, 696308, 50292, + 47013125, 11763583, + ]), + xy2d: FieldElement2625::from_limbs([ + 66514282, 31040148, 34874710, 12643979, 12650761, 14811489, 665117, 20940800, + 47335652, 22840869, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 97573435, 55845991, 62981386, 20819953, 86944190, 60003250, 109821551, 35630203, + 50088706, 34546902, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 18357166, 26559999, 7766381, 16342475, 37783946, 411173, 14578841, 8080033, + 55534529, 22952821, + ]), + xy2d: FieldElement2625::from_limbs([ + 19598397, 10334610, 12555054, 2555664, 18821899, 23214652, 21873262, 16014234, + 26224780, 16452269, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 36884920, 5145195, 73053412, 49940397, 71085598, 35564328, 122839923, 25936244, + 46575034, 37253081, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 14187449, 3448569, 56472628, 22743496, 44444983, 30120835, 7268409, 22663988, + 27394300, 12015369, + ]), + xy2d: FieldElement2625::from_limbs([ + 19695742, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, 32241655, + 53849736, 30151970, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 97968948, 12735207, 65220619, 28854697, 50133957, 35811371, 126051714, 45852742, + 58558339, 23160969, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 61389038, 22309106, 65198214, 15569034, 26642876, 25966672, 61319509, 18435777, + 62132699, 12651792, + ]), + xy2d: FieldElement2625::from_limbs([ + 64260450, 9953420, 11531313, 28271553, 26895122, 20857343, 53990043, 17036529, + 9768697, 31021214, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 109498250, 35449081, 66821165, 28850346, 82457582, 25397901, 32767512, 46319882, + 72048958, 44232657, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 18860224, 15980149, 48121624, 31991861, 40875851, 22482575, 59264981, 13944023, + 42736516, 16582018, + ]), + xy2d: FieldElement2625::from_limbs([ + 51604604, 4970267, 37215820, 4175592, 46115652, 31354675, 55404809, 15444559, + 56105103, 7989036, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 98599278, 39122492, 64696060, 35736814, 34772016, 38086117, 35030594, 39754637, + 47422750, 52308692, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 49800177, 17674491, 35586086, 33551600, 34221481, 16375548, 8680158, 17182719, + 28550067, 26697300, + ]), + xy2d: FieldElement2625::from_limbs([ + 38981977, 27866340, 16837844, 31733974, 60258182, 12700015, 37068883, 4364037, + 1155602, 5988841, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 88999280, 20281524, 121593716, 12154347, 59276991, 48854927, 90257846, 29083950, + 91727270, 41837612, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 33972757, 23041680, 9975415, 6841041, 35549071, 16356535, 3070187, 26528504, + 1466168, 10740210, + ]), + xy2d: FieldElement2625::from_limbs([ + 65599446, 18066246, 53605478, 22898515, 32799043, 909394, 53169961, 27774712, + 34944214, 18227391, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 71069668, 19286628, 39082773, 51190812, 47704004, 46701299, 82676190, 34505938, + 63848542, 32980496, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 24740822, 5052253, 37014733, 8961360, 25877428, 6165135, 42740684, 14397371, + 59728495, 27410326, + ]), + xy2d: FieldElement2625::from_limbs([ + 38220480, 3510802, 39005586, 32395953, 55870735, 22922977, 51667400, 19101303, + 65483377, 27059617, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 67902144, 24323953, 75945165, 27318724, 39747955, 31184838, 100261706, 62223612, + 57202662, 32932579, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 5666214, 525582, 20782575, 25516013, 42570364, 14657739, 16099374, 1468826, + 60937436, 18367850, + ]), + xy2d: FieldElement2625::from_limbs([ + 62249590, 29775088, 64191105, 26806412, 7778749, 11688288, 36704511, 23683193, + 65549940, 23690785, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 10896313, 25834728, 67933138, 34027032, 114757419, 36564017, 25248957, 48337770, + 36527387, 17796587, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10566929, 12612572, 35164652, 11118702, 54475488, 12362878, 21752402, 8822496, + 24003793, 14264025, + ]), + xy2d: FieldElement2625::from_limbs([ + 27713843, 26198459, 56100623, 9227529, 27050101, 2504721, 23886875, 20436907, + 13958494, 27821979, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 110736080, 38421656, 39861735, 37454952, 29838368, 25342141, 102328328, 23512649, + 74449384, 51698795, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 4646495, 25543308, 44342840, 22021777, 23184552, 8566613, 31366726, 32173371, + 52042079, 23179239, + ]), + xy2d: FieldElement2625::from_limbs([ + 49838347, 12723031, 50115803, 14878793, 21619651, 27356856, 27584816, 3093888, + 58265170, 3849920, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 58043933, 35657603, 92670503, 51983125, 61869038, 43137389, 99585908, 24536476, + 72111157, 18004172, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 55051311, 22376525, 21115584, 20189277, 8808711, 21523724, 16489529, 13378448, + 41263148, 12741425, + ]), + xy2d: FieldElement2625::from_limbs([ + 61162478, 10645102, 36197278, 15390283, 63821882, 26435754, 24306471, 15852464, + 28834118, 25908360, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 49773097, 24447374, 109686448, 42989383, 58636779, 32971069, 54018092, 34010272, + 87570721, 39045736, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 13669229, 17458950, 54626889, 23351392, 52539093, 21661233, 42112877, 11293806, + 38520660, 24132599, + ]), + xy2d: FieldElement2625::from_limbs([ + 28497909, 6272777, 34085870, 14470569, 8906179, 32328802, 18504673, 19389266, + 29867744, 24758489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 50901822, 47071627, 39309233, 19856633, 24009063, 60734973, 60741262, 53933471, + 22853427, 29542421, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 24191359, 16712145, 53177067, 15217830, 14542237, 1646131, 18603514, 22516545, + 12876622, 31441985, + ]), + xy2d: FieldElement2625::from_limbs([ + 17902668, 4518229, 66697162, 30725184, 26878216, 5258055, 54248111, 608396, + 16031844, 3723494, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 105584936, 12763726, 46662418, 41131935, 33001347, 54091119, 17558840, 59235974, + 23896952, 29240187, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 47103464, 21542479, 31520463, 605201, 2543521, 5991821, 64163800, 7229063, + 57189218, 24727572, + ]), + xy2d: FieldElement2625::from_limbs([ + 28816026, 298879, 38943848, 17633493, 19000927, 31888542, 54428030, 30605106, + 49057085, 31471516, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 16000882, 33209536, 70601955, 55661665, 37604267, 20394642, 79686603, 49595699, + 47393623, 7847706, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, 34252933, 27035413, + 57088296, 3852847, + ]), + xy2d: FieldElement2625::from_limbs([ + 55678375, 15697595, 45987307, 29133784, 5386313, 15063598, 16514493, 17622322, + 29330898, 18478208, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 41609110, 29175637, 51885955, 26653220, 83724594, 35606215, 70412565, 33569921, + 106668931, 45868821, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 15683501, 27551389, 18109119, 23573784, 15337967, 27556609, 50391428, 15921865, + 16103996, 29823217, + ]), + xy2d: FieldElement2625::from_limbs([ + 43939021, 22773182, 13588191, 31925625, 63310306, 32479502, 47835256, 5402698, + 37293151, 23713330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 90299521, 35939014, 34394523, 37016585, 104314072, 32025298, 55842007, 8911516, + 109011869, 36294143, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 21374101, 30000182, 33584214, 9874410, 15377179, 11831242, 33578960, 6134906, + 4931255, 11987849, + ]), + xy2d: FieldElement2625::from_limbs([ + 67101132, 30575573, 50885377, 7277596, 105524, 33232381, 35628324, 13861387, + 37032554, 10117929, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 37607694, 22809559, 40945095, 13051538, 41483300, 38644074, 127892224, 40258509, + 79998882, 15728939, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 45136504, 21783052, 66157804, 29135591, 14704839, 2695116, 903376, 23126293, + 12885166, 8311031, + ]), + xy2d: FieldElement2625::from_limbs([ + 49592363, 5352193, 10384213, 19742774, 7506450, 13453191, 26423267, 4384730, + 1888765, 28119028, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 108400371, 64001550, 120723127, 30371924, 98005322, 19632702, 101966083, 20846561, + 47644429, 30214188, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 43500868, 30888657, 66582772, 4651135, 5765089, 4618330, 6092245, 14845197, + 17151279, 23700316, + ]), + xy2d: FieldElement2625::from_limbs([ + 42278406, 20820711, 51942885, 10367249, 37577956, 33289075, 22825804, 26467153, + 50242379, 16176524, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 43525570, 40119392, 87172552, 37352659, 129477549, 40913655, 69115045, 23191005, + 38362610, 56911354, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56482264, 29068029, 53788301, 28429114, 3432135, 27161203, 23632036, 31613822, + 32808309, 1099883, + ]), + xy2d: FieldElement2625::from_limbs([ + 15030958, 5768825, 39657628, 30667132, 60681485, 18193060, 51830967, 26745081, + 2051440, 18328567, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 63746522, 26315059, 74626753, 43379423, 90664713, 33849800, 72257261, 52954675, + 44422508, 50188091, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 4577067, 16802144, 13249840, 18250104, 19958762, 19017158, 18559669, 22794883, + 8402477, 23690159, + ]), + xy2d: FieldElement2625::from_limbs([ + 38702534, 32502850, 40318708, 32646733, 49896449, 22523642, 9453450, 18574360, + 17983009, 9967138, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 41346351, 40079153, 93694351, 43523701, 24709297, 34774792, 65430873, 7806336, + 84616260, 37205991, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56688388, 29436320, 14584638, 15971087, 51340543, 8861009, 26556809, 27979875, + 48555541, 22197296, + ]), + xy2d: FieldElement2625::from_limbs([ + 2839082, 14284142, 4029895, 3472686, 14402957, 12689363, 40466743, 8459446, + 61503401, 25932490, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 62269556, 30018987, 76853824, 2871047, 92222842, 36741449, 109106914, 32705364, + 84366947, 25576692, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 18164541, 22959256, 49953981, 32012014, 19237077, 23809137, 23357532, 18337424, + 26908269, 12150756, + ]), + xy2d: FieldElement2625::from_limbs([ + 36843994, 25906566, 5112248, 26517760, 65609056, 26580174, 43167, 28016731, + 34806789, 16215818, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 60209940, 43378825, 54804084, 29153342, 102820586, 27277595, 99683352, 46087336, + 59605791, 24879084, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 39765323, 17038963, 39957339, 22831480, 946345, 16291093, 254968, 7168080, + 21676107, 31611404, + ]), + xy2d: FieldElement2625::from_limbs([ + 21260942, 25129680, 50276977, 21633609, 43430902, 3968120, 63456915, 27338965, + 63552672, 25641356, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 16544735, 46804798, 50304435, 49100673, 62525860, 46311689, 64646555, 24874095, + 48201831, 23891632, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 64693606, 17976703, 18312302, 4964443, 51836334, 20900867, 26820650, 16690659, + 25459437, 28989823, + ]), + xy2d: FieldElement2625::from_limbs([ + 41964155, 11425019, 28423002, 22533875, 60963942, 17728207, 9142794, 31162830, + 60676445, 31909614, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 44004193, 39807907, 16964146, 29785560, 109103755, 54812425, 39651637, 50764205, + 73444554, 40804420, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 36775618, 13979674, 7503222, 21186118, 55152142, 28932738, 36836594, 2682241, + 25993170, 21075909, + ]), + xy2d: FieldElement2625::from_limbs([ + 4364628, 5930691, 32304656, 23509878, 59054082, 15091130, 22857016, 22955477, + 31820367, 15075278, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 98987979, 24635738, 84367624, 33645057, 126175891, 28636721, 91271651, 23903545, + 116247489, 46387475, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 19073683, 14851414, 42705695, 21694263, 7625277, 11091125, 47489674, 2074448, + 57694925, 14905376, + ]), + xy2d: FieldElement2625::from_limbs([ + 24483648, 21618865, 64589997, 22007013, 65555733, 15355505, 41826784, 9253128, + 27628530, 25998952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 84706452, 41895034, 86464480, 34106618, 26198469, 30377849, 71702187, 24396849, + 120106852, 48851446, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 510886, 14337390, 35323607, 16638631, 6328095, 2713355, 46891447, 21690211, + 8683220, 2921426, + ]), + xy2d: FieldElement2625::from_limbs([ + 18606791, 11874196, 27155355, 28272950, 43077121, 6265445, 41930624, 32275507, + 4674689, 13890525, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 13609605, 13069022, 106845367, 20498522, 91469449, 43147405, 82086020, 43389536, + 71498550, 33842827, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 9922506, 33035038, 13613106, 5883594, 48350519, 33120168, 54804801, 8317627, + 23388070, 16052080, + ]), + xy2d: FieldElement2625::from_limbs([ + 12719997, 11937594, 35138804, 28525742, 26900119, 8561328, 46953177, 21921452, + 52354592, 22741539, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 83070703, 47704840, 93825794, 32888599, 111423399, 47157999, 78938436, 41022275, + 38286735, 34483706, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 11038231, 21972036, 39798381, 26237869, 56610336, 17246600, 43629330, 24182562, + 45715720, 2465073, + ]), + xy2d: FieldElement2625::from_limbs([ + 20017144, 29231206, 27915241, 1529148, 12396362, 15675764, 13817261, 23896366, + 2463390, 28932292, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 50749967, 20890520, 122152544, 38550884, 65852441, 34628003, 76692421, 12851106, + 71112760, 46228148, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 65377275, 18398561, 63845933, 16143081, 19294135, 13385325, 14741514, 24450706, + 7903885, 2348101, + ]), + xy2d: FieldElement2625::from_limbs([ + 24536016, 17039225, 12715591, 29692277, 1511292, 10047386, 63266518, 26425272, + 38731325, 10048126, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54486638, 27349611, 97827688, 2591311, 56491836, 12192839, 85982162, 59811773, + 34811106, 15221631, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 40630742, 22450567, 11546243, 31701949, 9180879, 7656409, 45764914, 2095754, + 29769758, 6593415, + ]), + xy2d: FieldElement2625::from_limbs([ + 35114656, 30646970, 4176911, 3264766, 12538965, 32686321, 26312344, 27435754, + 30958053, 8292160, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 98538667, 53149747, 96282394, 15632447, 12174511, 64348770, 99917693, 37531617, + 93251999, 30405555, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 22648882, 1402143, 44308880, 13746058, 7936347, 365344, 58440231, 31879998, + 63350620, 31249806, + ]), + xy2d: FieldElement2625::from_limbs([ + 51616947, 8012312, 64594134, 20851969, 43143017, 23300402, 65496150, 32018862, + 50444388, 8194477, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 27338047, 26047012, 59694639, 10140404, 48082437, 26964542, 94386054, 42409807, + 95681149, 36559595, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 26287105, 4821776, 25476601, 29408529, 63344350, 17765447, 49100281, 1182478, + 41014043, 20474836, + ]), + xy2d: FieldElement2625::from_limbs([ + 59937691, 3178079, 23970071, 6201893, 49913287, 29065239, 45232588, 19571804, + 32208682, 32356184, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 50451143, 36372074, 56822501, 14811297, 73133531, 46903936, 39793359, 56611021, + 39436277, 22014573, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 15941010, 24148500, 45741813, 8062054, 31876073, 33315803, 51830470, 32110002, + 15397330, 29424239, + ]), + xy2d: FieldElement2625::from_limbs([ + 8934485, 20068965, 43822466, 20131190, 34662773, 14047985, 31170398, 32113411, + 39603297, 15087183, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 115860466, 31397939, 24524912, 16876564, 82629290, 27193655, 118715321, 11461894, + 83897392, 27685489, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 65161459, 16013772, 21750665, 3714552, 49707082, 17498998, 63338576, 23231111, + 31322513, 21938797, + ]), + xy2d: FieldElement2625::from_limbs([ + 21426636, 27904214, 53460576, 28206894, 38296674, 28633461, 48833472, 18933017, + 13040861, 21441484, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 78402740, 46032517, 107081326, 48638180, 104910306, 14748870, 14555558, 20137329, + 68722574, 38451366, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 41213962, 15323293, 58619073, 25496531, 25967125, 20128972, 2825959, 28657387, + 43137087, 22287016, + ]), + xy2d: FieldElement2625::from_limbs([ + 51184079, 28324551, 49665331, 6410663, 3622847, 10243618, 20615400, 12405433, + 43355834, 25118015, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 127126414, 46110638, 114026375, 9025185, 50036385, 4333800, 71487300, 35986461, + 23097948, 32988414, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 4565804, 17528778, 20084411, 25711615, 1724998, 189254, 24767264, 10103221, + 48596551, 2424777, + ]), + xy2d: FieldElement2625::from_limbs([ + 366633, 21577626, 8173089, 26664313, 30788633, 5745705, 59940186, 1344108, + 63466311, 12412658, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 110215918, 41244716, 82038279, 33386174, 102006892, 53695876, 91271559, 51782359, + 63967361, 44733816, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 18289503, 18829478, 8056944, 16430056, 45379140, 7842513, 61107423, 32067534, + 48424218, 22110928, + ]), + xy2d: FieldElement2625::from_limbs([ + 476239, 6601091, 60956074, 23831056, 17503544, 28690532, 27672958, 13403813, + 11052904, 5219329, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 87787372, 25178693, 34436965, 42403554, 129207969, 48129182, 98295834, 29580701, + 9014761, 58529808, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 53464795, 23204192, 51146355, 5075807, 65594203, 22019831, 34006363, 9160279, + 8473550, 30297594, + ]), + xy2d: FieldElement2625::from_limbs([ + 24900749, 14435722, 17209120, 18261891, 44516588, 9878982, 59419555, 17218610, + 42540382, 11788947, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 63990690, 22159237, 53306774, 48351872, 76761311, 26708527, 47071426, 43965164, + 42540393, 32095740, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 51449703, 16736705, 44641714, 10215877, 58011687, 7563910, 11871841, 21049238, + 48595538, 8464117, + ]), + xy2d: FieldElement2625::from_limbs([ + 43708233, 8348506, 52522913, 32692717, 63158658, 27181012, 14325288, 8628612, + 33313881, 25183915, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 46921853, 28586496, 89476219, 38825978, 66011746, 28765593, 109412060, 23317576, + 58168128, 61290594, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 60160060, 31759219, 34483180, 17533252, 32635413, 26180187, 15989196, 20716244, + 28358191, 29300528, + ]), + xy2d: FieldElement2625::from_limbs([ + 43547083, 30755372, 34757181, 31892468, 57961144, 10429266, 50471180, 4072015, + 61757200, 5596588, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 105981130, 30164382, 79421759, 39767609, 3117141, 49632997, 29266238, 36111653, + 68877164, 15373192, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 59865506, 30307471, 62515396, 26001078, 66980936, 32642186, 66017961, 29049440, + 42448372, 3442909, + ]), + xy2d: FieldElement2625::from_limbs([ + 36898293, 5124042, 14181784, 8197961, 18964734, 21615339, 22597930, 7176455, + 48523386, 13365929, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 59231455, 32054473, 75433536, 38244510, 73370723, 34444877, 24538106, 24984246, + 57419264, 30522764, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 25008885, 22782833, 62803832, 23916421, 16265035, 15721635, 683793, 21730648, + 15723478, 18390951, + ]), + xy2d: FieldElement2625::from_limbs([ + 57448220, 12374378, 40101865, 26528283, 59384749, 21239917, 11879681, 5400171, + 519526, 32318556, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 22258378, 50776631, 59239045, 14613015, 44588609, 30603508, 46754982, 40870398, + 16648396, 41160072, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 59027556, 25089834, 58885552, 9719709, 19259459, 18206220, 23994941, 28272877, + 57640015, 4763277, + ]), + xy2d: FieldElement2625::from_limbs([ + 45409620, 9220968, 51378240, 1084136, 41632757, 30702041, 31088446, 25789909, + 55752334, 728111, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 26047201, 55357393, 127317403, 50587064, 91200930, 9158118, 62835319, 20998873, + 104852291, 28056158, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 17510331, 33231575, 5854288, 8403524, 17133918, 30441820, 38997856, 12327944, + 10750447, 10014012, + ]), + xy2d: FieldElement2625::from_limbs([ + 56796096, 3936951, 9156313, 24656749, 16498691, 32559785, 39627812, 32887699, + 3424690, 7540221, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 97431206, 26590321, 78469868, 29411114, 74542167, 4989747, 127146306, 50791643, + 57864597, 48812477, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 13054543, 30774935, 19155473, 469045, 54626067, 4566041, 5631406, 2711395, 1062915, + 28418087, + ]), + xy2d: FieldElement2625::from_limbs([ + 47868616, 22299832, 37599834, 26054466, 61273100, 13005410, 61042375, 12194496, + 32960380, 1459310, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 86960860, 40582355, 90778216, 43574797, 75695366, 26896524, 67503060, 27452546, + 85746866, 55933926, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 31395515, 15098109, 26581030, 8030562, 50580950, 28547297, 9012485, 25970078, + 60465776, 28111795, + ]), + xy2d: FieldElement2625::from_limbs([ + 57916680, 31207054, 65111764, 4529533, 25766844, 607986, 67095642, 9677542, + 34813975, 27098423, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 64664330, 33404494, 96457765, 8186664, 68982624, 12489862, 103283149, 25714738, + 59256019, 58970434, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 51872508, 18120922, 7766469, 746860, 26346930, 23332670, 39775412, 10754587, + 57677388, 5203575, + ]), + xy2d: FieldElement2625::from_limbs([ + 31834314, 14135496, 66338857, 5159117, 20917671, 16786336, 59640890, 26216907, + 31809242, 7347066, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 57502122, 21680191, 87523322, 46588417, 80825387, 21862550, 86906833, 21343176, + 82301739, 31466941, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 54445282, 31372712, 1168161, 29749623, 26747876, 19416341, 10609329, 12694420, + 33473243, 20172328, + ]), + xy2d: FieldElement2625::from_limbs([ + 33184999, 11180355, 15832085, 22169002, 65475192, 225883, 15089336, 22530529, + 60973201, 14480052, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 98417562, 27934433, 98139703, 31657332, 82783410, 26971548, 72605071, 13685226, + 27595050, 42291707, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 46790012, 18404192, 10933842, 17376410, 8335351, 26008410, 36100512, 20943827, + 26498113, 66511, + ]), + xy2d: FieldElement2625::from_limbs([ + 22644435, 24792703, 50437087, 4884561, 64003250, 19995065, 30540765, 29267685, + 53781076, 26039336, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 106199862, 9834843, 85726071, 30873119, 63706907, 53801357, 75314402, 13585436, + 117090263, 48669869, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 23711543, 32881517, 31206560, 25191721, 6164646, 23844445, 33572981, 32128335, + 8236920, 16492939, + ]), + xy2d: FieldElement2625::from_limbs([ + 43198286, 20038905, 40809380, 29050590, 25005589, 25867162, 19574901, 10071562, + 6708380, 27332008, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 69210217, 28624377, 86811594, 35922006, 118790560, 34602105, 72409880, 42883131, + 29955600, 55430554, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 3096359, 9271816, 45488000, 18032587, 52260867, 25961494, 41216721, 20918836, + 57191288, 6216607, + ]), + xy2d: FieldElement2625::from_limbs([ + 34493015, 338662, 41913253, 2510421, 37895298, 19734218, 24822829, 27407865, + 40341383, 7525078, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 44042196, 53123240, 83242349, 25658253, 130828162, 34333218, 66198527, 30771936, + 47722230, 45548532, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 21691500, 19929806, 66467532, 19187410, 3285880, 30070836, 42044197, 9718257, + 59631427, 13381417, + ]), + xy2d: FieldElement2625::from_limbs([ + 18445390, 29352196, 14979845, 11622458, 65381754, 29971451, 23111647, 27179185, + 28535281, 15779576, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 30098034, 36644094, 124983340, 16662133, 45801924, 44862842, 53040409, 12021729, + 77064149, 17251075, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 9734894, 18977602, 59635230, 24415696, 2060391, 11313496, 48682835, 9924398, + 20194861, 13380996, + ]), + xy2d: FieldElement2625::from_limbs([ + 40730762, 25589224, 44941042, 15789296, 49053522, 27385639, 65123949, 15707770, + 26342023, 10146099, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 41091971, 33334488, 88448054, 33513043, 86854119, 30675731, 37471583, 35781471, + 21612325, 33008704, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 54031477, 1184227, 23562814, 27583990, 46757619, 27205717, 25764460, 12243797, + 46252298, 11649657, + ]), + xy2d: FieldElement2625::from_limbs([ + 57077370, 11262625, 27384172, 2271902, 26947504, 17556661, 39943, 6114064, + 33514190, 2333242, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 112784121, 54687041, 75228644, 40774344, 45278341, 58092729, 60429112, 54438225, + 91459440, 20104430, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 62992557, 22282898, 43222677, 4843614, 37020525, 690622, 35572776, 23147595, + 8317859, 12352766, + ]), + xy2d: FieldElement2625::from_limbs([ + 18200138, 19078521, 34021104, 30857812, 43406342, 24451920, 43556767, 31266881, + 20712162, 6719373, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 26656189, 39629685, 59250307, 35440503, 105873684, 37816756, 78226393, 29791221, + 26224234, 30256974, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 49939907, 18700334, 63713187, 17184554, 47154818, 14050419, 21728352, 9493610, + 18620611, 17125804, + ]), + xy2d: FieldElement2625::from_limbs([ + 53785524, 13325348, 11432106, 5964811, 18609221, 6062965, 61839393, 23828875, + 36407290, 17074774, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 43248307, 55875704, 94070219, 35195292, 34695751, 16816491, 79357372, 28313792, + 80844205, 35488493, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 25089769, 6742589, 17081145, 20148166, 21909292, 17486451, 51972569, 29789085, + 45830866, 5473615, + ]), + xy2d: FieldElement2625::from_limbs([ + 31883658, 25593331, 1083431, 21982029, 22828470, 13290673, 59983779, 12469655, + 29111212, 28103418, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 91353792, 52058456, 107954750, 36345970, 52111264, 50221109, 91476329, 39943270, + 56813276, 34006814, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 41468082, 30136590, 5217915, 16224624, 19987036, 29472163, 42872612, 27639183, + 15766061, 8407814, + ]), + xy2d: FieldElement2625::from_limbs([ + 46701865, 13990230, 15495425, 16395525, 5377168, 15166495, 58191841, 29165478, + 59040954, 2276717, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 30157899, 46478498, 116505677, 42800183, 87003891, 36922573, 43281276, 38650650, + 89849239, 26251014, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 2041139, 19298082, 7783686, 13876377, 41161879, 20201972, 24051123, 13742383, + 51471265, 13295221, + ]), + xy2d: FieldElement2625::from_limbs([ + 33338218, 25048699, 12532112, 7977527, 9106186, 31839181, 49388668, 28941459, + 62657506, 18884987, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 47063564, 39008528, 52762315, 40001577, 28862070, 35438083, 64639597, 29412551, + 74879432, 43175028, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 23208049, 7979712, 33071466, 8149229, 1758231, 22719437, 30945527, 31860109, + 33606523, 18786461, + ]), + xy2d: FieldElement2625::from_limbs([ + 1439939, 17283952, 66028874, 32760649, 4625401, 10647766, 62065063, 1220117, + 30494170, 22113633, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 62071265, 20526136, 64138304, 30492664, 82749837, 26852765, 40369837, 34480481, + 65424524, 20220784, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 13908495, 30005160, 30919927, 27280607, 45587000, 7989038, 9021034, 9078865, + 3353509, 4033511, + ]), + xy2d: FieldElement2625::from_limbs([ + 37445433, 18440821, 32259990, 33209950, 24295848, 20642309, 23161162, 8839127, + 27485041, 7356032, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 76769853, 34259874, 79088928, 28184277, 65480320, 14661172, 60762722, 36179446, + 95539899, 50337029, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 43269631, 25243016, 41163352, 7480957, 49427195, 25200248, 44562891, 14150564, + 15970762, 4099461, + ]), + xy2d: FieldElement2625::from_limbs([ + 29262576, 16756590, 26350592, 24760869, 8529670, 22346382, 13617292, 23617289, + 11465738, 8317062, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 41615764, 26591503, 99609063, 24135380, 44070139, 31252209, 82007500, 37402886, + 88078197, 28396915, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 46724414, 19206718, 48772458, 13884721, 34069410, 2842113, 45498038, 29904543, + 11177094, 14989547, + ]), + xy2d: FieldElement2625::from_limbs([ + 42612143, 21838415, 16959895, 2278463, 12066309, 10137771, 13515641, 2581286, + 38621356, 9930239, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 49357223, 31456605, 83653163, 54099563, 118302919, 18605349, 18345766, 53705111, + 83400343, 28240393, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 33879670, 2553287, 32678213, 9875984, 8534129, 6889387, 57432090, 6957616, 4368891, + 9788741, + ]), + xy2d: FieldElement2625::from_limbs([ + 16660737, 7281060, 56278106, 12911819, 20108584, 25452756, 45386327, 24941283, + 16250551, 22443329, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 47343357, 35944957, 117666696, 14161978, 69014150, 39969338, 71798447, 10604806, + 104027325, 4782745, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 65754325, 14736940, 59741422, 20261545, 7710541, 19398842, 57127292, 4383044, + 22546403, 437323, + ]), + xy2d: FieldElement2625::from_limbs([ + 31665558, 21373968, 50922033, 1491338, 48740239, 3294681, 27343084, 2786261, + 36475274, 19457415, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 52641566, 32870716, 33734756, 41002983, 19294359, 14334329, 47418233, 35909750, + 47824192, 27440058, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 15121312, 17758270, 6377019, 27523071, 56310752, 20596586, 18952176, 15496498, + 37728731, 11754227, + ]), + xy2d: FieldElement2625::from_limbs([ + 64471568, 20071356, 8488726, 19250536, 12728760, 31931939, 7141595, 11724556, + 22761615, 23420291, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 16918416, 11729663, 49025285, 36577418, 103201995, 53769203, 38367677, 21327038, + 32851221, 11717399, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 11166615, 7338049, 60386341, 4531519, 37640192, 26252376, 31474878, 3483633, + 65915689, 29523600, + ]), + xy2d: FieldElement2625::from_limbs([ + 66923210, 9921304, 31456609, 20017994, 55095045, 13348922, 33142652, 6546660, + 47123585, 29606055, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 101757113, 44821142, 55911756, 25655328, 31703693, 37410335, 58571732, 20721383, + 36336829, 18068118, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 49102387, 12709067, 3991746, 27075244, 45617340, 23004006, 35973516, 17504552, + 10928916, 3011958, + ]), + xy2d: FieldElement2625::from_limbs([ + 60151107, 17960094, 31696058, 334240, 29576716, 14796075, 36277808, 20749251, + 18008030, 10258577, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 44660220, 49210000, 74127342, 29144428, 36794597, 32352840, 65255398, 34921551, + 92236737, 6671742, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 29701166, 19180498, 56230743, 9279287, 67091296, 13127209, 21382910, 11042292, + 25838796, 4642684, + ]), + xy2d: FieldElement2625::from_limbs([ + 46678630, 14955536, 42982517, 8124618, 61739576, 27563961, 30468146, 19653792, + 18423288, 4177476, + ]), + }, + ]), +]); + +/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +#[cfg(feature = "precomputed-tables")] +#[allow(dead_code)] +pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = + NafLookupTable8([ + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, + 61029707, 35602036, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, + 19500929, 18085054, + ]), + xy2d: FieldElement2625::from_limbs([ + 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, + 42594502, 29115885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, + 28944398, 32004408, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, + 7689661, 11199574, + ]), + xy2d: FieldElement2625::from_limbs([ + 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, + 49359771, 23634074, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, + 118779423, 44373810, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, + 54440373, 5581305, + ]), + xy2d: FieldElement2625::from_limbs([ + 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, + 43430843, 17738489, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, + 43156424, 18378665, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, + 30598449, 7715701, + ]), + xy2d: FieldElement2625::from_limbs([ + 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, + 29794553, 32145132, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 44589852, 26862249, 14201701, 24808930, 43598457, 42399157, 85583074, 32192981, + 54046167, 47376308, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 60653668, 25714560, 3374701, 28813570, 40010246, 22982724, 31655027, 26342105, + 18853321, 19333481, + ]), + xy2d: FieldElement2625::from_limbs([ + 4566811, 20590564, 38133974, 21313742, 59506191, 30723862, 58594505, 23123294, + 2207752, 30344648, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 41954014, 62923042, 96790006, 41423232, 60254202, 24130566, 121780363, 32891430, + 103106264, 17421994, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 25576264, 30851218, 7349803, 21739588, 16472781, 9300885, 3844789, 15725684, + 171356, 6466918, + ]), + xy2d: FieldElement2625::from_limbs([ + 23103977, 13316479, 9739013, 17404951, 817874, 18515490, 8965338, 19466374, + 36393951, 16193876, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 100695917, 36735143, 64714733, 47558118, 50205389, 17283591, 84347261, 38283886, + 49034350, 9256799, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 41926547, 29380300, 32336397, 5036987, 45872047, 11360616, 22616405, 9761698, + 47281666, 630304, + ]), + xy2d: FieldElement2625::from_limbs([ + 53388152, 2639452, 42871404, 26147950, 9494426, 27780403, 60554312, 17593437, + 64659607, 19263131, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 63957664, 28508356, 76391577, 40420576, 102310665, 32691407, 48168288, 15033783, + 92213982, 25659555, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 42782475, 15950225, 35307649, 18961608, 55446126, 28463506, 1573891, 30928545, + 2198789, 17749813, + ]), + xy2d: FieldElement2625::from_limbs([ + 64009494, 10324966, 64867251, 7453182, 61661885, 30818928, 53296841, 17317989, + 34647629, 21263748, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 17735022, 27114469, 76149336, 40765111, 43325570, 26153544, 26948151, 45905235, + 38656900, 62179684, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 2154119, 14782993, 28737794, 11906199, 36205504, 26488101, 19338132, 16910143, + 50209922, 29794297, + ]), + xy2d: FieldElement2625::from_limbs([ + 29935700, 6336041, 20999566, 30405369, 13628497, 24612108, 61639745, 22359641, + 56973806, 18684690, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 29792811, 31379227, 113441390, 20675662, 58452680, 54138549, 42892249, 32958636, + 31674345, 24275271, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 7606599, 22131225, 17376912, 15235046, 32822971, 7512882, 30227203, 14344178, + 9952094, 8804749, + ]), + xy2d: FieldElement2625::from_limbs([ + 32575079, 3961822, 36404898, 17773250, 67073898, 1319543, 30641032, 7823672, + 63309858, 18878784, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77823924, 52933642, 26572931, 18690221, 109143683, 23989794, 79129572, 53326100, + 38888709, 55889506, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 37146997, 554126, 63326061, 20925660, 49205290, 8620615, 53375504, 25938867, + 8752612, 31225894, + ]), + xy2d: FieldElement2625::from_limbs([ + 4529887, 12416158, 60388162, 30157900, 15427957, 27628808, 61150927, 12724463, + 23658330, 23690055, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 102043267, 54823614, 45810225, 19657305, 54297192, 7413280, 66851983, 39718512, + 25005048, 18002658, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 5403481, 24654166, 61855580, 13522652, 14989680, 1879017, 43913069, 25724172, + 20315901, 421248, + ]), + xy2d: FieldElement2625::from_limbs([ + 34818947, 1705239, 25347020, 7938434, 51632025, 1720023, 54809726, 32655885, + 64907986, 5517607, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 88543525, 16557377, 80359887, 30047148, 91602876, 27723948, 62710290, 52707861, + 7715736, 61648232, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 14461032, 6393639, 22681353, 14533514, 52493587, 3544717, 57780998, 24657863, + 59891807, 31628125, + ]), + xy2d: FieldElement2625::from_limbs([ + 60864886, 31199953, 18524951, 11247802, 43517645, 21165456, 26204394, 27268421, + 63221077, 29979135, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 97491378, 10077555, 94805128, 42472719, 30231379, 17961119, 76201413, 41182329, + 41405214, 31798052, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 13670592, 720327, 7131696, 19360499, 66651570, 16947532, 3061924, 22871019, + 39814495, 20141336, + ]), + xy2d: FieldElement2625::from_limbs([ + 44847187, 28379568, 38472030, 23697331, 49441718, 3215393, 1669253, 30451034, + 62323912, 29368533, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 74923758, 35244493, 27222384, 30715870, 48444195, 28125622, 116052444, 32330148, + 92609232, 35372537, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 39340596, 15199968, 52787715, 18781603, 18787729, 5464578, 11652644, 8722118, + 57056621, 5153960, + ]), + xy2d: FieldElement2625::from_limbs([ + 5733861, 14534448, 59480402, 15892910, 30737296, 188529, 491756, 17646733, + 33071791, 15771063, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 85239571, 21331573, 119690709, 30172286, 44350959, 55826224, 68258766, 16209406, + 20222151, 32139086, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 52372801, 13847470, 52690845, 3802477, 48387139, 10595589, 13745896, 3112846, + 50361463, 2761905, + ]), + xy2d: FieldElement2625::from_limbs([ + 45982696, 12273933, 15897066, 704320, 31367969, 3120352, 11710867, 16405685, + 19410991, 10591627, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 82008850, 34439758, 89319886, 49124188, 34309215, 29866047, 80308709, 27738519, + 71739865, 46909287, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 36631997, 23300851, 59535242, 27474493, 59924914, 29067704, 17551261, 13583017, + 37580567, 31071178, + ]), + xy2d: FieldElement2625::from_limbs([ + 22641770, 21277083, 10843473, 1582748, 37504588, 634914, 15612385, 18139122, + 59415250, 22563863, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 76721854, 52814714, 41722368, 35285867, 53022548, 38255176, 93163883, 27627617, + 87963092, 33729456, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 61915349, 11733561, 59403492, 31381562, 29521830, 16845409, 54973419, 26057054, + 49464700, 796779, + ]), + xy2d: FieldElement2625::from_limbs([ + 3855018, 8248512, 12652406, 88331, 2948262, 971326, 15614761, 9441028, 29507685, + 8583792, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 76968870, 14808584, 76708906, 57649718, 23400175, 24077237, 63783137, 37471119, + 56750251, 30681804, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 33709664, 3740344, 52888604, 25059045, 46197996, 22678812, 45207164, 6431243, + 21300862, 27646257, + ]), + xy2d: FieldElement2625::from_limbs([ + 49811511, 9216232, 25043921, 18738174, 29145960, 3024227, 65580502, 530149, + 66809973, 22275500, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 23499366, 24936714, 38355445, 35908587, 82540167, 39280880, 46809413, 41143783, + 72530804, 49676198, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 45162189, 23851397, 9380591, 15192763, 36034862, 15525765, 5277811, 25040629, + 33286237, 31693326, + ]), + xy2d: FieldElement2625::from_limbs([ + 62424427, 13336013, 49368582, 1581264, 30884213, 15048226, 66823504, 4736577, + 53805192, 29608355, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 25190215, 26304748, 58928336, 42665707, 64280342, 38580230, 61299598, 20659504, + 30387592, 32519377, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 14480213, 17057820, 2286692, 32980967, 14693157, 22197912, 49247898, 9909859, + 236428, 16857435, + ]), + xy2d: FieldElement2625::from_limbs([ + 7877514, 29872867, 45886243, 25902853, 41998762, 6241604, 35694938, 15657879, + 56797932, 8609105, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54245189, 32562161, 57887697, 19509733, 45323534, 37472546, 27606727, 59528498, + 74398957, 44973176, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 28964163, 20950093, 44929966, 26145892, 34786807, 18058153, 18187179, 27016486, + 42438836, 14869174, + ]), + xy2d: FieldElement2625::from_limbs([ + 55703901, 1222455, 64329400, 24533246, 11330890, 9135834, 3589529, 19555234, + 53275553, 1207212, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 33323313, 35603165, 79328585, 6017848, 71286345, 23804207, 86644124, 44008367, + 55775078, 31816581, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 64814718, 27217688, 29891310, 4504619, 8548709, 21986323, 62140656, 12555980, + 34377058, 21436823, + ]), + xy2d: FieldElement2625::from_limbs([ + 49069441, 9880212, 33350825, 24576421, 24446077, 15616561, 19302117, 9370836, + 55172180, 28526191, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 95404934, 26757208, 123864063, 4572839, 69249194, 43584425, 53559055, 41742046, + 41167331, 24643278, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 35101859, 30958612, 66105296, 3168612, 22836264, 10055966, 22893634, 13045780, + 28576558, 30704591, + ]), + xy2d: FieldElement2625::from_limbs([ + 59987873, 21166324, 43296694, 15387892, 39447987, 19996270, 5059183, 19972934, + 30207804, 29631666, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 67444156, 16132892, 88330413, 37924284, 68147855, 57949418, 91481571, 24889160, + 62329722, 50712214, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56922508, 1347520, 23300731, 27393371, 42651667, 8512932, 27610931, 24436993, + 3998295, 3835244, + ]), + xy2d: FieldElement2625::from_limbs([ + 16327050, 22776956, 14746360, 22599650, 23700920, 11727222, 25900154, 21823218, + 34907363, 25105813, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 59807886, 12089757, 115624210, 41476837, 67589715, 26361580, 71355762, 44268661, + 67753061, 13128476, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 7174885, 26592113, 59892333, 6465478, 4145835, 17673606, 38764952, 22293290, + 1360980, 25805937, + ]), + xy2d: FieldElement2625::from_limbs([ + 40179568, 6331649, 42386021, 20205884, 15635073, 6103612, 56391180, 6789942, + 7597240, 24095312, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54776568, 36935932, 18757261, 41429535, 67215081, 34700142, 86560976, 61204154, + 26496794, 19612129, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 46701540, 24101444, 49515651, 25946994, 45338156, 9941093, 55509371, 31298943, + 1347425, 15381335, + ]), + xy2d: FieldElement2625::from_limbs([ + 53576449, 26135856, 17092785, 3684747, 57829121, 27109516, 2987881, 10987137, + 52269096, 15465522, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 80033010, 26264316, 72380996, 10039544, 94605936, 30615493, 60406855, 30400829, + 120765849, 45301372, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 35668062, 24246990, 47788280, 25128298, 37456967, 19518969, 43459670, 10724644, + 7294162, 4471290, + ]), + xy2d: FieldElement2625::from_limbs([ + 33813988, 3549109, 101112, 21464449, 4858392, 3029943, 59999440, 21424738, + 34313875, 1512799, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 29494960, 28240930, 51093230, 28823678, 92791151, 54796794, 77571888, 37795542, + 75765856, 10649531, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 63536751, 7572551, 62249759, 25202639, 32046232, 32318941, 29315141, 15424555, + 24706712, 28857648, + ]), + xy2d: FieldElement2625::from_limbs([ + 47618751, 5819839, 19528172, 20715950, 40655763, 20611047, 4960954, 6496879, + 2790858, 28045273, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 85174457, 55843901, 111946683, 31021158, 32797785, 48944265, 78338887, 31144772, + 82688001, 38470222, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 49664705, 3638040, 57888693, 19234931, 40104182, 28143840, 28667142, 18386877, + 18584835, 3592929, + ]), + xy2d: FieldElement2625::from_limbs([ + 12065039, 18867394, 6430594, 17107159, 1727094, 13096957, 61520237, 27056604, + 27026997, 13543966, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 68512926, 37577278, 94695528, 14209106, 95849194, 30038709, 51818051, 20241476, + 68980056, 42251074, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 17325298, 33376175, 65271265, 4931225, 31708266, 6292284, 23064744, 22072792, + 43945505, 9236924, + ]), + xy2d: FieldElement2625::from_limbs([ + 51955585, 20268063, 61151838, 26383348, 4766519, 20788033, 21173534, 27030753, + 9509140, 7790046, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 24124086, 38918775, 28620390, 10538620, 59433851, 19581010, 60862718, 43500219, + 77600721, 32213801, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 7062127, 13930079, 2259902, 6463144, 32137099, 24748848, 41557343, 29331342, + 47345194, 13022814, + ]), + xy2d: FieldElement2625::from_limbs([ + 18921826, 392002, 55817981, 6420686, 8000611, 22415972, 14722962, 26246290, + 20604450, 8079345, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 67710253, 26257798, 51499391, 46550521, 30228769, 53940987, 76234206, 43362242, + 77953697, 21034392, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 25817710, 8020883, 50134679, 21244805, 47057788, 8766556, 29308546, 22307963, + 49449920, 23874253, + ]), + xy2d: FieldElement2625::from_limbs([ + 11081015, 13522660, 12474691, 29260223, 48687631, 9341946, 16850694, 18637605, + 6199839, 14303642, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 64518173, 19894035, 117213833, 43031641, 79641718, 39533880, 66531934, 41205092, + 117735515, 13989682, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 6921800, 4421166, 59739491, 30510778, 43106355, 30941531, 9363541, 3394240, + 50874187, 23872585, + ]), + xy2d: FieldElement2625::from_limbs([ + 54293979, 23466866, 47184247, 20627378, 8313211, 5865878, 5948507, 32290343, + 52583140, 23139870, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 111574723, 24134616, 49842442, 23485580, 34844037, 45228427, 67103167, 25858409, + 38508586, 35097070, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 19879846, 15259900, 25020018, 14261729, 22075205, 25189303, 787540, 31325033, + 62422289, 16131171, + ]), + xy2d: FieldElement2625::from_limbs([ + 39487053, 27893575, 34654176, 25620816, 60209846, 23603919, 8931189, 12275052, + 38626469, 33438928, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 105416367, 9568747, 62672739, 49685015, 106242995, 4547918, 18403901, 38581738, + 60829966, 33150322, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 7950033, 25841033, 47276506, 3884935, 62418883, 2342083, 50269031, 14194015, + 27013685, 3320257, + ]), + xy2d: FieldElement2625::from_limbs([ + 35270691, 18076829, 46994271, 4273335, 43595882, 31742297, 58328702, 4594760, + 49180851, 18144010, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 30194115, 50068680, 49746331, 27470090, 40428285, 23271051, 70252167, 16153483, + 123511881, 27809602, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 27113466, 6865046, 4512771, 29327742, 29021084, 7405965, 33302911, 9322435, + 4307527, 32438240, + ]), + xy2d: FieldElement2625::from_limbs([ + 29337813, 24673346, 10359233, 30347534, 57709483, 9930840, 60607771, 24076133, + 20985293, 22480923, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 14579237, 33467236, 85745988, 15769997, 101228358, 21649866, 82685456, 59023858, + 86175344, 24337101, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 4472119, 14702190, 10432042, 22460027, 708461, 18783996, 34234374, 30870323, + 63796457, 10370850, + ]), + xy2d: FieldElement2625::from_limbs([ + 36957127, 19555637, 16244231, 24367549, 58999881, 13440043, 35147632, 8718974, + 43101064, 18487380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 21818223, 34477173, 23913863, 22441963, 129271975, 14842154, 43035020, 9485973, + 53819529, 22318987, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 10874834, 4351765, 66252340, 17269436, 64427034, 30735311, 5883785, 28998531, + 44403022, 26064601, + ]), + xy2d: FieldElement2625::from_limbs([ + 64017630, 9755550, 37507935, 22752543, 4031638, 29903925, 47267417, 32706846, + 39147952, 21635901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 81365001, 44927611, 97395185, 43985591, 66242539, 38517499, 52937891, 37374973, + 73352483, 38476849, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 43460763, 24260930, 21493330, 30888969, 23329454, 24545577, 58286855, 12750266, + 22391140, 26198125, + ]), + xy2d: FieldElement2625::from_limbs([ + 20477567, 24078713, 1674568, 4102219, 25208396, 13972305, 30389482, 19572626, + 1485666, 17679765, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 100511110, 23887606, 116505658, 30877106, 45483774, 25222431, 67931340, 37154158, + 32618865, 18610785, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 48647066, 166413, 55454758, 8889513, 21027475, 32728181, 43100067, 4690060, + 7520989, 16421303, + ]), + xy2d: FieldElement2625::from_limbs([ + 14868391, 20996450, 64836606, 1042490, 27060176, 10253541, 53431276, 19516737, + 41808946, 2239538, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 50228416, 29594943, 62030348, 10307368, 70970997, 20292574, 126292474, 51543890, + 67827181, 15848795, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 5548701, 17911007, 33137864, 32764443, 31146554, 17931096, 64023370, 7290289, + 6361313, 32861205, + ]), + xy2d: FieldElement2625::from_limbs([ + 63374742, 30320053, 4091667, 30955480, 44819449, 2212055, 52638826, 22391938, + 38484599, 7051029, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 50485560, 7033600, 57711425, 10740562, 72347547, 42328739, 7593987, 46950560, + 85560721, 41970063, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 40930651, 3776911, 39108529, 2508077, 19371703, 7626128, 4092943, 15778278, + 42044145, 24540103, + ]), + xy2d: FieldElement2625::from_limbs([ + 44128555, 8867576, 8645499, 22222278, 11497130, 4344907, 10788462, 23382703, + 3547104, 15368835, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 81786515, 51902785, 74560130, 22753403, 52379722, 41395524, 57994925, 6818020, + 57707296, 16352835, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 21622574, 18581624, 36511951, 1212467, 36930308, 7910192, 20622927, 2438677, + 52628762, 29068327, + ]), + xy2d: FieldElement2625::from_limbs([ + 6797431, 2854059, 4269865, 8037366, 32016522, 15223213, 34765784, 15297582, + 3559197, 26425254, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 107761639, 61759660, 79235166, 8794359, 48418924, 60111631, 87862210, 33613219, + 68436482, 40229362, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 52388944, 32880897, 37676257, 8253690, 32826330, 2707379, 25088512, 17182878, + 15053907, 11601568, + ]), + xy2d: FieldElement2625::from_limbs([ + 43894091, 25425955, 50962615, 28097648, 30129084, 13258436, 39364589, 8197601, + 58181660, 15003422, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 13470722, 47835674, 31012390, 30525035, 89789519, 50713267, 39648035, 13815677, + 94028755, 62582101, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 54478677, 14782829, 56712503, 7094748, 41775828, 29409658, 9084386, 30179063, + 64014926, 32519086, + ]), + xy2d: FieldElement2625::from_limbs([ + 6314429, 20018828, 12535891, 19610611, 10074031, 28087963, 50489447, 26314252, + 24553876, 32746308, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 105768482, 46629424, 103418946, 65789027, 85765355, 28316167, 56299027, 22780838, + 122676432, 32376204, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 5654403, 26425050, 39347935, 963424, 5032477, 19850195, 30011537, 11153401, + 63182039, 13343989, + ]), + xy2d: FieldElement2625::from_limbs([ + 1130444, 29814849, 40569426, 8144467, 24179188, 6267924, 63847147, 2912740, + 63870704, 29186744, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 49722534, 11073633, 52865263, 50829611, 33921405, 38614719, 32360242, 35465390, + 50107050, 45035301, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 2003571, 2472803, 46902183, 1716406, 58609069, 15922982, 43766122, 27456369, + 33468339, 29346282, + ]), + xy2d: FieldElement2625::from_limbs([ + 18834217, 8245144, 29896065, 3490830, 62967493, 7220277, 146130, 18459164, + 57533060, 30070422, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 77805507, 38474121, 73459597, 18553340, 107508318, 52705654, 33655873, 27331956, + 44498407, 13768350, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 23652128, 27647291, 43351590, 13262712, 65238054, 26296349, 11902126, 2949002, + 34445239, 25602117, + ]), + xy2d: FieldElement2625::from_limbs([ + 55906958, 19046111, 28501158, 28224561, 14495533, 14714956, 32929972, 2643566, + 17034893, 11645825, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 38181639, 29751709, 73650473, 17760526, 80753587, 17992258, 72670209, 41214427, + 87524152, 37630124, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 6498441, 12053607, 10375600, 14764370, 24795955, 16159258, 57849421, 16071837, + 31008329, 3792564, + ]), + xy2d: FieldElement2625::from_limbs([ + 47930485, 9176956, 54248931, 8732776, 58000258, 10333519, 96092, 29273884, + 13051277, 20121493, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 54190492, 49837594, 61282066, 10734597, 67926686, 36967416, 115462142, 30339271, + 37200685, 30036936, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 21193614, 19929501, 18841215, 29565554, 64002173, 11123558, 14111648, 6069945, + 30307604, 25935103, + ]), + xy2d: FieldElement2625::from_limbs([ + 58539773, 2098685, 38301131, 15844175, 41633654, 16934366, 15145895, 5543861, + 64050790, 6595361, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 34107945, 34731353, 51956038, 5614778, 79079051, 30288154, 47460410, 22186730, + 30689695, 19628976, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 25043248, 19224237, 46048097, 32289319, 29339134, 12397721, 37385860, 12978240, + 57951631, 31419653, + ]), + xy2d: FieldElement2625::from_limbs([ + 46038439, 28501736, 62566522, 12609283, 35236982, 30457796, 64113609, 14800343, + 6412849, 6276813, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 124528774, 39505727, 83050803, 41361190, 116071796, 37845759, 61633481, 38385016, + 71255100, 31629488, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 249426, 17196749, 35434953, 13884216, 11701636, 24553269, 51821986, 12900910, + 34844073, 16150118, + ]), + xy2d: FieldElement2625::from_limbs([ + 2520516, 14697628, 15319213, 22684490, 62866663, 29666431, 13872507, 7473319, + 12419515, 2958466, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 101517167, 22298305, 98222207, 59471046, 61547444, 50370568, 97111094, 42539051, + 14298448, 49873561, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 19427905, 12004555, 9971383, 28189868, 32306269, 23648270, 34176633, 10760437, + 53354280, 5634974, + ]), + xy2d: FieldElement2625::from_limbs([ + 30044319, 23677863, 60273406, 14563839, 9734978, 19808149, 30899064, 30835691, + 22828539, 23633348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 25513026, 37111929, 37113703, 29589233, 77394412, 34745965, 95889446, 61766763, + 92876242, 37566563, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 42139852, 9176396, 16274786, 33467453, 52558621, 7190768, 1490604, 31312359, + 44767199, 18491072, + ]), + xy2d: FieldElement2625::from_limbs([ + 4272877, 21431483, 45594743, 13027605, 59232641, 24151956, 38390319, 12906718, + 45915869, 15503563, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 29874396, 35808736, 25494239, 37976524, 43036007, 37144111, 18198811, 35141252, + 53490316, 47742788, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 59518553, 28520621, 59946871, 29462027, 3630300, 29398589, 60425462, 24588735, + 53129947, 28399367, + ]), + xy2d: FieldElement2625::from_limbs([ + 18192774, 12787801, 32021061, 9158184, 48389348, 16385092, 11799402, 9492011, + 43154220, 15950102, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 68768204, 54638026, 33464925, 53430209, 66037964, 35360373, 22565155, 39168685, + 46605438, 51897954, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 57660336, 29715319, 64414626, 32753338, 16894121, 935644, 53848937, 22684138, + 10541713, 14174330, + ]), + xy2d: FieldElement2625::from_limbs([ + 22888141, 12700209, 40301697, 6435658, 56329485, 5524686, 56715961, 6520808, + 15754965, 9355803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 79549820, 26746924, 54931884, 38547877, 49672847, 19708985, 52599424, 12757151, + 93328625, 39524327, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 33888606, 13911610, 18921581, 1162763, 46616901, 13799218, 29525142, 21929286, + 59295464, 503508, + ]), + xy2d: FieldElement2625::from_limbs([ + 57865531, 22043577, 17998312, 3038439, 52838371, 9832208, 43311531, 660991, + 25265267, 18977724, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 64010269, 23727746, 42277281, 48089313, 102316973, 34946803, 127880577, 38411468, + 114816699, 43712746, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56859315, 32558245, 41017090, 22610758, 13704990, 23215119, 2475037, 32344984, + 12799418, 11135856, + ]), + xy2d: FieldElement2625::from_limbs([ + 1867214, 27167702, 19772099, 16925005, 15366693, 25797692, 10829276, 15372827, + 26582557, 31642714, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 57265197, 20059797, 107314987, 30587501, 60553812, 25602102, 29690666, 37127097, + 103070929, 51772159, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56432653, 6329655, 42770975, 4187982, 30677076, 9335071, 60103332, 14755050, + 9451294, 574767, + ]), + xy2d: FieldElement2625::from_limbs([ + 52859018, 2867107, 56258365, 15719081, 5959372, 8703738, 29137781, 21575537, + 20249840, 31808689, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 74749335, 47235127, 9995910, 52200224, 92069015, 8964515, 33248715, 21201554, + 57573145, 31605506, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 56307055, 23891752, 3613811, 30787942, 49031222, 26667524, 26985478, 31973510, + 26785294, 29587427, + ]), + xy2d: FieldElement2625::from_limbs([ + 30891460, 5254655, 47414930, 12769216, 42912782, 11830405, 7411958, 1394027, + 18778535, 18209370, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 61227949, 26179350, 57501473, 13585864, 102855675, 40344975, 54134826, 59707765, + 74122694, 12256219, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 5975515, 16302413, 24341148, 28270615, 18786096, 22405501, 28243950, 28328004, + 53412289, 4381960, + ]), + xy2d: FieldElement2625::from_limbs([ + 9394648, 8758552, 26189703, 16642536, 35993528, 5117040, 5977877, 13955594, + 19244020, 24493735, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 111388362, 51822507, 30193028, 3993472, 110736308, 44014764, 107346699, 48464072, + 92830877, 56442511, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 7236795, 30433657, 63588571, 620817, 11118384, 24979014, 66780154, 19877679, + 16217590, 26311105, + ]), + xy2d: FieldElement2625::from_limbs([ + 42540794, 21657271, 16455973, 23630199, 3992015, 21894417, 44876052, 19291718, + 55429803, 30442389, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement2625::from_limbs([ + 69421833, 26972132, 58859271, 20240912, 119664007, 29643940, 93968457, 34515112, + 110902491, 44996669, + ]), + y_minus_x: FieldElement2625::from_limbs([ + 3428668, 27807272, 41139948, 24786894, 4167808, 21423270, 52199622, 8021269, + 53172251, 18070808, + ]), + xy2d: FieldElement2625::from_limbs([ + 30631113, 26363656, 21279866, 23275794, 18311406, 466071, 42527968, 7989982, + 29641567, 29446694, + ]), + }, + ]); diff --git a/src/backend/serial/u32/field.rs b/curve25519-dalek/src/backend/serial/u32/field.rs similarity index 75% rename from src/backend/serial/u32/field.rs rename to curve25519-dalek/src/backend/serial/u32/field.rs index c8f3e5e7f..7319288a0 100644 --- a/src/backend/serial/u32/field.rs +++ b/curve25519-dalek/src/backend/serial/u32/field.rs @@ -25,6 +25,7 @@ use core::ops::{Sub, SubAssign}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; /// A `FieldElement2625` represents an element of the field @@ -50,14 +51,15 @@ use zeroize::Zeroize; /// The backend-specific type `FieldElement2625` should not be used /// outside of the `curve25519_dalek::field` module. #[derive(Copy, Clone)] -pub struct FieldElement2625(pub (crate) [u32; 10]); +pub struct FieldElement2625(pub(crate) [u32; 10]); impl Debug for FieldElement2625 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "FieldElement2625({:?})", &self.0[..]) } } +#[cfg(feature = "zeroize")] impl Zeroize for FieldElement2625 { fn zeroize(&mut self) { self.0.zeroize(); @@ -98,7 +100,8 @@ impl<'b> SubAssign<&'b FieldElement2625> for FieldElement2625 { ((self.0[7] + (0x1ffffff << 4)) - b[7]) as u64, ((self.0[8] + (0x3ffffff << 4)) - b[8]) as u64, ((self.0[9] + (0x1ffffff << 4)) - b[9]) as u64, - ]).0; + ]) + .0; } } @@ -120,14 +123,19 @@ impl<'b> MulAssign<&'b FieldElement2625> for FieldElement2625 { impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { type Output = FieldElement2625; + + #[rustfmt::skip] // keep alignment of z* calculations fn mul(self, _rhs: &'b FieldElement2625) -> FieldElement2625 { /// Helper function to multiply two 32-bit integers with 64 bits /// of output. #[inline(always)] - fn m(x: u32, y: u32) -> u64 { (x as u64) * (y as u64) } + fn m(x: u32, y: u32) -> u64 { + (x as u64) * (y as u64) + } // Alias self, _rhs for more readable formulas - let x: &[u32;10] = &self.0; let y: &[u32;10] = &_rhs.0; + let x: &[u32; 10] = &self.0; + let y: &[u32; 10] = &_rhs.0; // We assume that the input limbs x[i], y[i] are bounded by: // @@ -177,16 +185,16 @@ impl<'a, 'b> Mul<&'b FieldElement2625> for &'a FieldElement2625 { let x7_2 = 2 * x[7]; let x9_2 = 2 * x[9]; - let z0 = m(x[0],y[0]) + m(x1_2,y9_19) + m(x[2],y8_19) + m(x3_2,y7_19) + m(x[4],y6_19) + m(x5_2,y5_19) + m(x[6],y4_19) + m(x7_2,y3_19) + m(x[8],y2_19) + m(x9_2,y1_19); - let z1 = m(x[0],y[1]) + m(x[1],y[0]) + m(x[2],y9_19) + m(x[3],y8_19) + m(x[4],y7_19) + m(x[5],y6_19) + m(x[6],y5_19) + m(x[7],y4_19) + m(x[8],y3_19) + m(x[9],y2_19); - let z2 = m(x[0],y[2]) + m(x1_2,y[1]) + m(x[2],y[0]) + m(x3_2,y9_19) + m(x[4],y8_19) + m(x5_2,y7_19) + m(x[6],y6_19) + m(x7_2,y5_19) + m(x[8],y4_19) + m(x9_2,y3_19); - let z3 = m(x[0],y[3]) + m(x[1],y[2]) + m(x[2],y[1]) + m(x[3],y[0]) + m(x[4],y9_19) + m(x[5],y8_19) + m(x[6],y7_19) + m(x[7],y6_19) + m(x[8],y5_19) + m(x[9],y4_19); - let z4 = m(x[0],y[4]) + m(x1_2,y[3]) + m(x[2],y[2]) + m(x3_2,y[1]) + m(x[4],y[0]) + m(x5_2,y9_19) + m(x[6],y8_19) + m(x7_2,y7_19) + m(x[8],y6_19) + m(x9_2,y5_19); - let z5 = m(x[0],y[5]) + m(x[1],y[4]) + m(x[2],y[3]) + m(x[3],y[2]) + m(x[4],y[1]) + m(x[5],y[0]) + m(x[6],y9_19) + m(x[7],y8_19) + m(x[8],y7_19) + m(x[9],y6_19); - let z6 = m(x[0],y[6]) + m(x1_2,y[5]) + m(x[2],y[4]) + m(x3_2,y[3]) + m(x[4],y[2]) + m(x5_2,y[1]) + m(x[6],y[0]) + m(x7_2,y9_19) + m(x[8],y8_19) + m(x9_2,y7_19); - let z7 = m(x[0],y[7]) + m(x[1],y[6]) + m(x[2],y[5]) + m(x[3],y[4]) + m(x[4],y[3]) + m(x[5],y[2]) + m(x[6],y[1]) + m(x[7],y[0]) + m(x[8],y9_19) + m(x[9],y8_19); - let z8 = m(x[0],y[8]) + m(x1_2,y[7]) + m(x[2],y[6]) + m(x3_2,y[5]) + m(x[4],y[4]) + m(x5_2,y[3]) + m(x[6],y[2]) + m(x7_2,y[1]) + m(x[8],y[0]) + m(x9_2,y9_19); - let z9 = m(x[0],y[9]) + m(x[1],y[8]) + m(x[2],y[7]) + m(x[3],y[6]) + m(x[4],y[5]) + m(x[5],y[4]) + m(x[6],y[3]) + m(x[7],y[2]) + m(x[8],y[1]) + m(x[9],y[0]); + let z0 = m(x[0], y[0]) + m(x1_2, y9_19) + m(x[2], y8_19) + m(x3_2, y7_19) + m(x[4], y6_19) + m(x5_2, y5_19) + m(x[6], y4_19) + m(x7_2, y3_19) + m(x[8], y2_19) + m(x9_2, y1_19); + let z1 = m(x[0], y[1]) + m(x[1], y[0]) + m(x[2], y9_19) + m(x[3], y8_19) + m(x[4], y7_19) + m(x[5], y6_19) + m(x[6], y5_19) + m(x[7], y4_19) + m(x[8], y3_19) + m(x[9], y2_19); + let z2 = m(x[0], y[2]) + m(x1_2, y[1]) + m(x[2], y[0]) + m(x3_2, y9_19) + m(x[4], y8_19) + m(x5_2, y7_19) + m(x[6], y6_19) + m(x7_2, y5_19) + m(x[8], y4_19) + m(x9_2, y3_19); + let z3 = m(x[0], y[3]) + m(x[1], y[2]) + m(x[2], y[1]) + m(x[3], y[0]) + m(x[4], y9_19) + m(x[5], y8_19) + m(x[6], y7_19) + m(x[7], y6_19) + m(x[8], y5_19) + m(x[9], y4_19); + let z4 = m(x[0], y[4]) + m(x1_2, y[3]) + m(x[2], y[2]) + m(x3_2, y[1]) + m(x[4], y[0]) + m(x5_2, y9_19) + m(x[6], y8_19) + m(x7_2, y7_19) + m(x[8], y6_19) + m(x9_2, y5_19); + let z5 = m(x[0], y[5]) + m(x[1], y[4]) + m(x[2], y[3]) + m(x[3], y[2]) + m(x[4], y[1]) + m(x[5], y[0]) + m(x[6], y9_19) + m(x[7], y8_19) + m(x[8], y7_19) + m(x[9], y6_19); + let z6 = m(x[0], y[6]) + m(x1_2, y[5]) + m(x[2], y[4]) + m(x3_2, y[3]) + m(x[4], y[2]) + m(x5_2, y[1]) + m(x[6], y[0]) + m(x7_2, y9_19) + m(x[8], y8_19) + m(x9_2, y7_19); + let z7 = m(x[0], y[7]) + m(x[1], y[6]) + m(x[2], y[5]) + m(x[3], y[4]) + m(x[4], y[3]) + m(x[5], y[2]) + m(x[6], y[1]) + m(x[7], y[0]) + m(x[8], y9_19) + m(x[9], y8_19); + let z8 = m(x[0], y[8]) + m(x1_2, y[7]) + m(x[2], y[6]) + m(x3_2, y[5]) + m(x[4], y[4]) + m(x5_2, y[3]) + m(x[6], y[2]) + m(x7_2, y[1]) + m(x[8], y[0]) + m(x9_2, y9_19); + let z9 = m(x[0], y[9]) + m(x[1], y[8]) + m(x[2], y[7]) + m(x[3], y[6]) + m(x[4], y[5]) + m(x[5], y[4]) + m(x[6], y[3]) + m(x[7], y[2]) + m(x[8], y[1]) + m(x[9], y[0]); // How big is the contribution to z[i+j] from x[i], y[j]? // @@ -276,6 +284,20 @@ impl ConditionallySelectable for FieldElement2625 { } impl FieldElement2625 { + pub(crate) const fn from_limbs(limbs: [u32; 10]) -> FieldElement2625 { + FieldElement2625(limbs) + } + + /// The scalar \\( 0 \\). + pub const ZERO: FieldElement2625 = FieldElement2625::from_limbs([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// The scalar \\( 1 \\). + pub const ONE: FieldElement2625 = FieldElement2625::from_limbs([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + /// The scalar \\( -1 \\). + pub const MINUS_ONE: FieldElement2625 = FieldElement2625::from_limbs([ + 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, + 0x3ffffff, 0x1ffffff, + ]); + /// Invert the sign of this field element pub fn negate(&mut self) { // Compute -b as ((2^4 * p) - b) to avoid underflow. @@ -294,27 +316,9 @@ impl FieldElement2625 { self.0 = neg.0; } - /// Construct zero. - pub fn zero() -> FieldElement2625 { - FieldElement2625([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) - } - - /// Construct one. - pub fn one() -> FieldElement2625 { - FieldElement2625([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]) - } - - /// Construct -1. - pub fn minus_one() -> FieldElement2625 { - FieldElement2625([ - 0x3ffffec, 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, - 0x1ffffff, 0x3ffffff, 0x1ffffff, 0x3ffffff, 0x1ffffff, - ]) - } - /// Given `k > 0`, return `self^(2^k)`. pub fn pow2k(&self, k: u32) -> FieldElement2625 { - debug_assert!( k > 0 ); + debug_assert!(k > 0); let mut z = self.square(); for _ in 1..k { z = z.square(); @@ -328,6 +332,7 @@ impl FieldElement2625 { /// /// In other words, each coefficient of the result is bounded by /// either `2^(25 + 0.007)` or `2^(26 + 0.007)`, as appropriate. + #[rustfmt::skip] // keep alignment of carry chain fn reduce(mut z: [u64; 10]) -> FieldElement2625 { const LOW_25_BITS: u64 = (1 << 25) - 1; @@ -339,11 +344,11 @@ impl FieldElement2625 { debug_assert!(i < 9); if i % 2 == 0 { // Even limbs have 26 bits - z[i+1] += z[i] >> 26; + z[i + 1] += z[i] >> 26; z[i] &= LOW_26_BITS; } else { // Odd limbs have 25 bits - z[i+1] += z[i] >> 25; + z[i + 1] += z[i] >> 25; z[i] &= LOW_25_BITS; } } @@ -360,7 +365,7 @@ impl FieldElement2625 { // and z[5] < 2^25 + 2^13.0002 < 2^25.0004 (good enough) // Last carry has a multiplication by 19: - z[0] += 19*(z[9] >> 25); + z[0] += 19 * (z[9] >> 25); z[9] &= LOW_25_BITS; // Since z[9] < 2^64, c < 2^(64-25) = 2^39, @@ -371,8 +376,16 @@ impl FieldElement2625 { // and we're done. FieldElement2625([ - z[0] as u32, z[1] as u32, z[2] as u32, z[3] as u32, z[4] as u32, - z[5] as u32, z[6] as u32, z[7] as u32, z[8] as u32, z[9] as u32, + z[0] as u32, + z[1] as u32, + z[2] as u32, + z[3] as u32, + z[4] as u32, + z[5] as u32, + z[6] as u32, + z[7] as u32, + z[8] as u32, + z[9] as u32, ]) } @@ -387,7 +400,8 @@ impl FieldElement2625 { /// encoding of every field element should decode, re-encode to /// the canonical encoding, and check that the input was /// canonical. - pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 { //FeFromBytes + #[rustfmt::skip] // keep alignment of h[*] values + pub fn from_bytes(data: &[u8; 32]) -> FieldElement2625 { #[inline] fn load3(b: &[u8]) -> u64 { (b[0] as u64) | ((b[1] as u64) << 8) | ((b[2] as u64) << 16) @@ -416,15 +430,24 @@ impl FieldElement2625 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { - + #[allow(clippy::identity_op)] + pub fn as_bytes(&self) -> [u8; 32] { let inp = &self.0; // Reduce the value represented by `in` to the range [0,2*p) let mut h: [u32; 10] = FieldElement2625::reduce([ // XXX this cast is annoying - inp[0] as u64, inp[1] as u64, inp[2] as u64, inp[3] as u64, inp[4] as u64, - inp[5] as u64, inp[6] as u64, inp[7] as u64, inp[8] as u64, inp[9] as u64, - ]).0; + inp[0] as u64, + inp[1] as u64, + inp[2] as u64, + inp[3] as u64, + inp[4] as u64, + inp[5] as u64, + inp[6] as u64, + inp[7] as u64, + inp[8] as u64, + inp[9] as u64, + ]) + .0; // Let h be the value to encode. // @@ -446,40 +469,40 @@ impl FieldElement2625 { q = (h[8] + q) >> 26; q = (h[9] + q) >> 25; - debug_assert!( q == 0 || q == 1 ); + debug_assert!(q == 0 || q == 1); // Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q const LOW_25_BITS: u32 = (1 << 25) - 1; const LOW_26_BITS: u32 = (1 << 26) - 1; - h[0] += 19*q; + h[0] += 19 * q; // Now carry the result to compute r + 19q... h[1] += h[0] >> 26; - h[0] = h[0] & LOW_26_BITS; + h[0] &= LOW_26_BITS; h[2] += h[1] >> 25; - h[1] = h[1] & LOW_25_BITS; + h[1] &= LOW_25_BITS; h[3] += h[2] >> 26; - h[2] = h[2] & LOW_26_BITS; + h[2] &= LOW_26_BITS; h[4] += h[3] >> 25; - h[3] = h[3] & LOW_25_BITS; + h[3] &= LOW_25_BITS; h[5] += h[4] >> 26; - h[4] = h[4] & LOW_26_BITS; + h[4] &= LOW_26_BITS; h[6] += h[5] >> 25; - h[5] = h[5] & LOW_25_BITS; + h[5] &= LOW_25_BITS; h[7] += h[6] >> 26; - h[6] = h[6] & LOW_26_BITS; + h[6] &= LOW_26_BITS; h[8] += h[7] >> 25; - h[7] = h[7] & LOW_25_BITS; + h[7] &= LOW_25_BITS; h[9] += h[8] >> 26; - h[8] = h[8] & LOW_26_BITS; + h[8] &= LOW_26_BITS; // ... but instead of carrying the value // (h[9] >> 25) = q*2^255 into another limb, // discard it, subtracting the value from h. - debug_assert!( (h[9] >> 25) == 0 || (h[9] >> 25) == 1); - h[9] = h[9] & LOW_25_BITS; + debug_assert!((h[9] >> 25) == 0 || (h[9] >> 25) == 1); + h[9] &= LOW_25_BITS; let mut s = [0u8; 32]; s[0] = (h[0] >> 0) as u8; @@ -521,43 +544,46 @@ impl FieldElement2625 { s } + #[rustfmt::skip] // keep alignment of z* calculations fn square_inner(&self) -> [u64; 10] { // Optimized version of multiplication for the case of squaring. // Pre- and post- conditions identical to multiplication function. let x = &self.0; - let x0_2 = 2 * x[0]; - let x1_2 = 2 * x[1]; - let x2_2 = 2 * x[2]; - let x3_2 = 2 * x[3]; - let x4_2 = 2 * x[4]; - let x5_2 = 2 * x[5]; - let x6_2 = 2 * x[6]; - let x7_2 = 2 * x[7]; - let x5_19 = 19 * x[5]; - let x6_19 = 19 * x[6]; - let x7_19 = 19 * x[7]; - let x8_19 = 19 * x[8]; - let x9_19 = 19 * x[9]; + let x0_2 = 2 * x[0]; + let x1_2 = 2 * x[1]; + let x2_2 = 2 * x[2]; + let x3_2 = 2 * x[3]; + let x4_2 = 2 * x[4]; + let x5_2 = 2 * x[5]; + let x6_2 = 2 * x[6]; + let x7_2 = 2 * x[7]; + let x5_19 = 19 * x[5]; + let x6_19 = 19 * x[6]; + let x7_19 = 19 * x[7]; + let x8_19 = 19 * x[8]; + let x9_19 = 19 * x[9]; /// Helper function to multiply two 32-bit integers with 64 bits /// of output. #[inline(always)] - fn m(x: u32, y: u32) -> u64 { (x as u64) * (y as u64) } + fn m(x: u32, y: u32) -> u64 { + (x as u64) * (y as u64) + } // This block is rearranged so that instead of doing a 32-bit multiplication by 38, we do a // 64-bit multiplication by 2 on the results. This is because lg(38) is too big: we would // have less than 1 bit of headroom left, which is too little. - let mut z = [0u64;10]; - z[0] = m(x[0],x[0]) + m(x2_2,x8_19) + m(x4_2,x6_19) + (m(x1_2,x9_19) + m(x3_2,x7_19) + m(x[5],x5_19))*2; - z[1] = m(x0_2,x[1]) + m(x3_2,x8_19) + m(x5_2,x6_19) + (m(x[2],x9_19) + m(x[4],x7_19))*2; - z[2] = m(x0_2,x[2]) + m(x1_2,x[1]) + m(x4_2,x8_19) + m(x[6],x6_19) + (m(x3_2,x9_19) + m(x5_2,x7_19))*2; - z[3] = m(x0_2,x[3]) + m(x1_2,x[2]) + m(x5_2,x8_19) + (m(x[4],x9_19) + m(x[6],x7_19))*2; - z[4] = m(x0_2,x[4]) + m(x1_2,x3_2) + m(x[2],x[2]) + m(x6_2,x8_19) + (m(x5_2,x9_19) + m(x[7],x7_19))*2; - z[5] = m(x0_2,x[5]) + m(x1_2,x[4]) + m(x2_2,x[3]) + m(x7_2,x8_19) + m(x[6],x9_19)*2; - z[6] = m(x0_2,x[6]) + m(x1_2,x5_2) + m(x2_2,x[4]) + m(x3_2,x[3]) + m(x[8],x8_19) + m(x7_2,x9_19)*2; - z[7] = m(x0_2,x[7]) + m(x1_2,x[6]) + m(x2_2,x[5]) + m(x3_2,x[4]) + m(x[8],x9_19)*2; - z[8] = m(x0_2,x[8]) + m(x1_2,x7_2) + m(x2_2,x[6]) + m(x3_2,x5_2) + m(x[4],x[4]) + m(x[9],x9_19)*2; - z[9] = m(x0_2,x[9]) + m(x1_2,x[8]) + m(x2_2,x[7]) + m(x3_2,x[6]) + m(x4_2,x[5]) ; + let mut z = [0u64; 10]; + z[0] = m(x[0], x[0]) + m(x2_2, x8_19) + m(x4_2, x6_19) + (m(x1_2, x9_19) + m(x3_2, x7_19) + m(x[5], x5_19)) * 2; + z[1] = m(x0_2, x[1]) + m(x3_2, x8_19) + m(x5_2, x6_19) + (m(x[2], x9_19) + m(x[4], x7_19) ) * 2; + z[2] = m(x0_2, x[2]) + m(x1_2, x[1]) + m(x4_2, x8_19) + m(x[6], x6_19) + (m(x3_2, x9_19) + m(x5_2, x7_19)) * 2; + z[3] = m(x0_2, x[3]) + m(x1_2, x[2]) + m(x5_2, x8_19) + (m(x[4], x9_19) + m(x[6], x7_19) ) * 2; + z[4] = m(x0_2, x[4]) + m(x1_2, x3_2) + m(x[2], x[2]) + m(x6_2, x8_19) + (m(x5_2, x9_19) + m(x[7], x7_19)) * 2; + z[5] = m(x0_2, x[5]) + m(x1_2, x[4]) + m(x2_2, x[3]) + m(x7_2, x8_19) + m(x[6], x9_19) * 2; + z[6] = m(x0_2, x[6]) + m(x1_2, x5_2) + m(x2_2, x[4]) + m(x3_2, x[3]) + m(x[8], x8_19) + m(x7_2, x9_19) * 2; + z[7] = m(x0_2, x[7]) + m(x1_2, x[6]) + m(x2_2, x[5]) + m(x3_2, x[4]) + m(x[8], x9_19) * 2; + z[8] = m(x0_2, x[8]) + m(x1_2, x7_2) + m(x2_2, x[6]) + m(x3_2, x5_2) + m(x[4], x[4]) + m(x[9], x9_19) * 2; + z[9] = m(x0_2, x[9]) + m(x1_2, x[8]) + m(x2_2, x[7]) + m(x3_2, x[6]) + m(x4_2, x[5]) ; z } @@ -570,8 +596,8 @@ impl FieldElement2625 { /// Compute `2*self^2`. pub fn square2(&self) -> FieldElement2625 { let mut coeffs = self.square_inner(); - for i in 0..self.0.len() { - coeffs[i] += coeffs[i]; + for coeff in &mut coeffs { + *coeff += *coeff; } FieldElement2625::reduce(coeffs) } diff --git a/src/backend/serial/u32/mod.rs b/curve25519-dalek/src/backend/serial/u32/mod.rs similarity index 100% rename from src/backend/serial/u32/mod.rs rename to curve25519-dalek/src/backend/serial/u32/mod.rs diff --git a/src/backend/serial/u32/scalar.rs b/curve25519-dalek/src/backend/serial/u32/scalar.rs similarity index 59% rename from src/backend/serial/u32/scalar.rs rename to curve25519-dalek/src/backend/serial/u32/scalar.rs index 8dd54bd29..2d135d1d4 100644 --- a/src/backend/serial/u32/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u32/scalar.rs @@ -13,20 +13,23 @@ use core::fmt::Debug; use core::ops::{Index, IndexMut}; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; -use constants; +use crate::constants; -/// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs -#[derive(Copy,Clone)] +/// The `Scalar29` struct represents an element in \\(\mathbb{Z} / \ell\mathbb{Z}\\) as 9 29-bit +/// limbs +#[derive(Copy, Clone)] pub struct Scalar29(pub [u32; 9]); impl Debug for Scalar29 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Scalar29: {:?}", &self.0[..]) } } +#[cfg(feature = "zeroize")] impl Zeroize for Scalar29 { fn zeroize(&mut self) { self.0.zeroize(); @@ -53,12 +56,11 @@ fn m(x: u32, y: u32) -> u64 { } impl Scalar29 { - /// Return the zero scalar. - pub fn zero() -> Scalar29 { - Scalar29([0,0,0,0,0,0,0,0,0]) - } + /// The scalar \\( 0 \\). + pub const ZERO: Scalar29 = Scalar29([0, 0, 0, 0, 0, 0, 0, 0, 0]); /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn from_bytes(bytes: &[u8; 32]) -> Scalar29 { let mut words = [0u32; 8]; for i in 0..8 { @@ -69,22 +71,23 @@ impl Scalar29 { let mask = (1u32 << 29) - 1; let top_mask = (1u32 << 24) - 1; - let mut s = Scalar29::zero(); - - s[ 0] = words[0] & mask; - s[ 1] = ((words[0] >> 29) | (words[1] << 3)) & mask; - s[ 2] = ((words[1] >> 26) | (words[2] << 6)) & mask; - s[ 3] = ((words[2] >> 23) | (words[3] << 9)) & mask; - s[ 4] = ((words[3] >> 20) | (words[4] << 12)) & mask; - s[ 5] = ((words[4] >> 17) | (words[5] << 15)) & mask; - s[ 6] = ((words[5] >> 14) | (words[6] << 18)) & mask; - s[ 7] = ((words[6] >> 11) | (words[7] << 21)) & mask; - s[ 8] = (words[7] >> 8) & top_mask; + let mut s = Scalar29::ZERO; + + s[0] = words[0] & mask; + s[1] = ((words[0] >> 29) | (words[1] << 3)) & mask; + s[2] = ((words[1] >> 26) | (words[2] << 6)) & mask; + s[3] = ((words[2] >> 23) | (words[3] << 9)) & mask; + s[4] = ((words[3] >> 20) | (words[4] << 12)) & mask; + s[5] = ((words[4] >> 17) | (words[5] << 15)) & mask; + s[6] = ((words[5] >> 14) | (words[6] << 18)) & mask; + s[7] = ((words[6] >> 11) | (words[7] << 21)) & mask; + s[8] = (words[7] >> 8) & top_mask; s } /// Reduce a 64 byte / 512 bit scalar mod l. + #[rustfmt::skip] // keep alignment of lo[*] calculations pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar29 { let mut words = [0u32; 16]; for i in 0..16 { @@ -94,8 +97,8 @@ impl Scalar29 { } let mask = (1u32 << 29) - 1; - let mut lo = Scalar29::zero(); - let mut hi = Scalar29::zero(); + let mut lo = Scalar29::ZERO; + let mut hi = Scalar29::ZERO; lo[0] = words[ 0] & mask; lo[1] = ((words[ 0] >> 29) | (words[ 1] << 3)) & mask; @@ -123,48 +126,50 @@ impl Scalar29 { } /// Pack the limbs of this `Scalar29` into 32 bytes. - pub fn to_bytes(&self) -> [u8; 32] { + #[rustfmt::skip] // keep alignment of s[*] calculations + #[allow(clippy::identity_op)] + pub fn as_bytes(&self) -> [u8; 32] { let mut s = [0u8; 32]; - s[0] = (self.0[ 0] >> 0) as u8; - s[1] = (self.0[ 0] >> 8) as u8; - s[2] = (self.0[ 0] >> 16) as u8; - s[3] = ((self.0[ 0] >> 24) | (self.0[ 1] << 5)) as u8; - s[4] = (self.0[ 1] >> 3) as u8; - s[5] = (self.0[ 1] >> 11) as u8; - s[6] = (self.0[ 1] >> 19) as u8; - s[7] = ((self.0[ 1] >> 27) | (self.0[ 2] << 2)) as u8; - s[8] = (self.0[ 2] >> 6) as u8; - s[9] = (self.0[ 2] >> 14) as u8; - s[10] = ((self.0[ 2] >> 22) | (self.0[ 3] << 7)) as u8; - s[11] = (self.0[ 3] >> 1) as u8; - s[12] = (self.0[ 3] >> 9) as u8; - s[13] = (self.0[ 3] >> 17) as u8; - s[14] = ((self.0[ 3] >> 25) | (self.0[ 4] << 4)) as u8; - s[15] = (self.0[ 4] >> 4) as u8; - s[16] = (self.0[ 4] >> 12) as u8; - s[17] = (self.0[ 4] >> 20) as u8; - s[18] = ((self.0[ 4] >> 28) | (self.0[ 5] << 1)) as u8; - s[19] = (self.0[ 5] >> 7) as u8; - s[20] = (self.0[ 5] >> 15) as u8; - s[21] = ((self.0[ 5] >> 23) | (self.0[ 6] << 6)) as u8; - s[22] = (self.0[ 6] >> 2) as u8; - s[23] = (self.0[ 6] >> 10) as u8; - s[24] = (self.0[ 6] >> 18) as u8; - s[25] = ((self.0[ 6] >> 26) | (self.0[ 7] << 3)) as u8; - s[26] = (self.0[ 7] >> 5) as u8; - s[27] = (self.0[ 7] >> 13) as u8; - s[28] = (self.0[ 7] >> 21) as u8; - s[29] = (self.0[ 8] >> 0) as u8; - s[30] = (self.0[ 8] >> 8) as u8; - s[31] = (self.0[ 8] >> 16) as u8; + s[ 0] = (self.0[0] >> 0) as u8; + s[ 1] = (self.0[0] >> 8) as u8; + s[ 2] = (self.0[0] >> 16) as u8; + s[ 3] = ((self.0[0] >> 24) | (self.0[1] << 5)) as u8; + s[ 4] = (self.0[1] >> 3) as u8; + s[ 5] = (self.0[1] >> 11) as u8; + s[ 6] = (self.0[1] >> 19) as u8; + s[ 7] = ((self.0[1] >> 27) | (self.0[2] << 2)) as u8; + s[ 8] = (self.0[2] >> 6) as u8; + s[ 9] = (self.0[2] >> 14) as u8; + s[10] = ((self.0[2] >> 22) | (self.0[3] << 7)) as u8; + s[11] = (self.0[3] >> 1) as u8; + s[12] = (self.0[3] >> 9) as u8; + s[13] = (self.0[3] >> 17) as u8; + s[14] = ((self.0[3] >> 25) | (self.0[4] << 4)) as u8; + s[15] = (self.0[4] >> 4) as u8; + s[16] = (self.0[4] >> 12) as u8; + s[17] = (self.0[4] >> 20) as u8; + s[18] = ((self.0[4] >> 28) | (self.0[5] << 1)) as u8; + s[19] = (self.0[5] >> 7) as u8; + s[20] = (self.0[5] >> 15) as u8; + s[21] = ((self.0[5] >> 23) | (self.0[6] << 6)) as u8; + s[22] = (self.0[6] >> 2) as u8; + s[23] = (self.0[6] >> 10) as u8; + s[24] = (self.0[6] >> 18) as u8; + s[25] = ((self.0[6] >> 26) | (self.0[7] << 3)) as u8; + s[26] = (self.0[7] >> 5) as u8; + s[27] = (self.0[7] >> 13) as u8; + s[28] = (self.0[7] >> 21) as u8; + s[29] = (self.0[8] >> 0) as u8; + s[30] = (self.0[8] >> 8) as u8; + s[31] = (self.0[8] >> 16) as u8; s } /// Compute `a + b` (mod l). pub fn add(a: &Scalar29, b: &Scalar29) -> Scalar29 { - let mut sum = Scalar29::zero(); + let mut sum = Scalar29::ZERO; let mask = (1u32 << 29) - 1; // a + b @@ -180,7 +185,7 @@ impl Scalar29 { /// Compute `a - b` (mod l). pub fn sub(a: &Scalar29, b: &Scalar29) -> Scalar29 { - let mut difference = Scalar29::zero(); + let mut difference = Scalar29::ZERO; let mask = (1u32 << 29) - 1; // a - b @@ -205,26 +210,27 @@ impl Scalar29 { /// /// This is implemented with a one-level refined Karatsuba decomposition #[inline(always)] + #[rustfmt::skip] // keep alignment of z[*] calculations pub (crate) fn mul_internal(a: &Scalar29, b: &Scalar29) -> [u64; 17] { let mut z = [0u64; 17]; - z[0] = m(a[0],b[0]); // c00 - z[1] = m(a[0],b[1]) + m(a[1],b[0]); // c01 - z[2] = m(a[0],b[2]) + m(a[1],b[1]) + m(a[2],b[0]); // c02 - z[3] = m(a[0],b[3]) + m(a[1],b[2]) + m(a[2],b[1]) + m(a[3],b[0]); // c03 - z[4] = m(a[0],b[4]) + m(a[1],b[3]) + m(a[2],b[2]) + m(a[3],b[1]) + m(a[4],b[0]); // c04 - z[5] = m(a[1],b[4]) + m(a[2],b[3]) + m(a[3],b[2]) + m(a[4],b[1]); // c05 - z[6] = m(a[2],b[4]) + m(a[3],b[3]) + m(a[4],b[2]); // c06 - z[7] = m(a[3],b[4]) + m(a[4],b[3]); // c07 - z[8] = (m(a[4],b[4])).wrapping_sub(z[3]); // c08 - c03 - - z[10] = z[5].wrapping_sub(m(a[5],b[5])); // c05mc10 - z[11] = z[6].wrapping_sub(m(a[5],b[6]) + m(a[6],b[5])); // c06mc11 - z[12] = z[7].wrapping_sub(m(a[5],b[7]) + m(a[6],b[6]) + m(a[7],b[5])); // c07mc12 - z[13] = m(a[5],b[8]) + m(a[6],b[7]) + m(a[7],b[6]) + m(a[8],b[5]); // c13 - z[14] = m(a[6],b[8]) + m(a[7],b[7]) + m(a[8],b[6]); // c14 - z[15] = m(a[7],b[8]) + m(a[8],b[7]); // c15 - z[16] = m(a[8],b[8]); // c16 + z[0] = m(a[0], b[0]); // c00 + z[1] = m(a[0], b[1]) + m(a[1], b[0]); // c01 + z[2] = m(a[0], b[2]) + m(a[1], b[1]) + m(a[2], b[0]); // c02 + z[3] = m(a[0], b[3]) + m(a[1], b[2]) + m(a[2], b[1]) + m(a[3], b[0]); // c03 + z[4] = m(a[0], b[4]) + m(a[1], b[3]) + m(a[2], b[2]) + m(a[3], b[1]) + m(a[4], b[0]); // c04 + z[5] = m(a[1], b[4]) + m(a[2], b[3]) + m(a[3], b[2]) + m(a[4], b[1]); // c05 + z[6] = m(a[2], b[4]) + m(a[3], b[3]) + m(a[4], b[2]); // c06 + z[7] = m(a[3], b[4]) + m(a[4], b[3]); // c07 + z[8] = (m(a[4], b[4])).wrapping_sub(z[3]); // c08 - c03 + + z[10] = z[5].wrapping_sub(m(a[5], b[5])); // c05mc10 + z[11] = z[6].wrapping_sub(m(a[5], b[6]) + m(a[6], b[5])); // c06mc11 + z[12] = z[7].wrapping_sub(m(a[5], b[7]) + m(a[6], b[6]) + m(a[7], b[5])); // c07mc12 + z[13] = m(a[5], b[8]) + m(a[6], b[7]) + m(a[7], b[6]) + m(a[8], b[5]); // c13 + z[14] = m(a[6], b[8]) + m(a[7], b[7]) + m(a[8], b[6]); // c14 + z[15] = m(a[7], b[8]) + m(a[8], b[7]); // c15 + z[16] = m(a[8], b[8]); // c16 z[ 5] = z[10].wrapping_sub(z[ 0]); // c05mc10 - c00 z[ 6] = z[11].wrapping_sub(z[ 1]); // c06mc11 - c01 @@ -235,68 +241,70 @@ impl Scalar29 { z[11] = z[16].wrapping_add(z[11]); // c16 + c06mc11 let aa = [ - a[0]+a[5], - a[1]+a[6], - a[2]+a[7], - a[3]+a[8] + a[0] + a[5], + a[1] + a[6], + a[2] + a[7], + a[3] + a[8] ]; let bb = [ - b[0]+b[5], - b[1]+b[6], - b[2]+b[7], - b[3]+b[8] + b[0] + b[5], + b[1] + b[6], + b[2] + b[7], + b[3] + b[8] ]; - z[ 5] = (m(aa[0],bb[0])) .wrapping_add(z[ 5]); // c20 + c05mc10 - c00 - z[ 6] = (m(aa[0],bb[1]) + m(aa[1],bb[0])) .wrapping_add(z[ 6]); // c21 + c06mc11 - c01 - z[ 7] = (m(aa[0],bb[2]) + m(aa[1],bb[1]) + m(aa[2],bb[0])) .wrapping_add(z[ 7]); // c22 + c07mc12 - c02 - z[ 8] = (m(aa[0],bb[3]) + m(aa[1],bb[2]) + m(aa[2],bb[1]) + m(aa[3],bb[0])) .wrapping_add(z[ 8]); // c23 + c08mc13 - c03 - z[ 9] = (m(aa[0], b[4]) + m(aa[1],bb[3]) + m(aa[2],bb[2]) + m(aa[3],bb[1]) + m(a[4],bb[0])).wrapping_sub(z[ 9]); // c24 - c14 - c04 - z[10] = ( m(aa[1], b[4]) + m(aa[2],bb[3]) + m(aa[3],bb[2]) + m(a[4],bb[1])).wrapping_sub(z[10]); // c25 - c15 - c05mc10 - z[11] = ( m(aa[2], b[4]) + m(aa[3],bb[3]) + m(a[4],bb[2])).wrapping_sub(z[11]); // c26 - c16 - c06mc11 - z[12] = ( m(aa[3], b[4]) + m(a[4],bb[3])).wrapping_sub(z[12]); // c27 - c07mc12 + z[ 5] = (m(aa[0], bb[0])) .wrapping_add(z[ 5]); // c20 + c05mc10 - c00 + z[ 6] = (m(aa[0], bb[1]) + m(aa[1], bb[0])) .wrapping_add(z[ 6]); // c21 + c06mc11 - c01 + z[ 7] = (m(aa[0], bb[2]) + m(aa[1], bb[1]) + m(aa[2], bb[0])) .wrapping_add(z[ 7]); // c22 + c07mc12 - c02 + z[ 8] = (m(aa[0], bb[3]) + m(aa[1], bb[2]) + m(aa[2], bb[1]) + m(aa[3], bb[0])) .wrapping_add(z[ 8]); // c23 + c08mc13 - c03 + z[ 9] = (m(aa[0], b[4]) + m(aa[1], bb[3]) + m(aa[2], bb[2]) + m(aa[3], bb[1]) + m(a[4], bb[0])).wrapping_sub(z[ 9]); // c24 - c14 - c04 + z[10] = ( m(aa[1], b[4]) + m(aa[2], bb[3]) + m(aa[3], bb[2]) + m(a[4], bb[1])).wrapping_sub(z[10]); // c25 - c15 - c05mc10 + z[11] = ( m(aa[2], b[4]) + m(aa[3], bb[3]) + m(a[4], bb[2])).wrapping_sub(z[11]); // c26 - c16 - c06mc11 + z[12] = ( m(aa[3], b[4]) + m(a[4], bb[3])).wrapping_sub(z[12]); // c27 - c07mc12 z } /// Compute `a^2`. #[inline(always)] + #[rustfmt::skip] // keep alignment of calculations fn square_internal(a: &Scalar29) -> [u64; 17] { let aa = [ - a[0]*2, - a[1]*2, - a[2]*2, - a[3]*2, - a[4]*2, - a[5]*2, - a[6]*2, - a[7]*2 + a[0] * 2, + a[1] * 2, + a[2] * 2, + a[3] * 2, + a[4] * 2, + a[5] * 2, + a[6] * 2, + a[7] * 2 ]; [ - m( a[0],a[0]), - m(aa[0],a[1]), - m(aa[0],a[2]) + m( a[1],a[1]), - m(aa[0],a[3]) + m(aa[1],a[2]), - m(aa[0],a[4]) + m(aa[1],a[3]) + m( a[2],a[2]), - m(aa[0],a[5]) + m(aa[1],a[4]) + m(aa[2],a[3]), - m(aa[0],a[6]) + m(aa[1],a[5]) + m(aa[2],a[4]) + m( a[3],a[3]), - m(aa[0],a[7]) + m(aa[1],a[6]) + m(aa[2],a[5]) + m(aa[3],a[4]), - m(aa[0],a[8]) + m(aa[1],a[7]) + m(aa[2],a[6]) + m(aa[3],a[5]) + m( a[4],a[4]), - m(aa[1],a[8]) + m(aa[2],a[7]) + m(aa[3],a[6]) + m(aa[4],a[5]), - m(aa[2],a[8]) + m(aa[3],a[7]) + m(aa[4],a[6]) + m( a[5],a[5]), - m(aa[3],a[8]) + m(aa[4],a[7]) + m(aa[5],a[6]), - m(aa[4],a[8]) + m(aa[5],a[7]) + m( a[6],a[6]), - m(aa[5],a[8]) + m(aa[6],a[7]), - m(aa[6],a[8]) + m( a[7],a[7]), - m(aa[7],a[8]), - m( a[8],a[8]), + m( a[0], a[0]), + m(aa[0], a[1]), + m(aa[0], a[2]) + m( a[1], a[1]), + m(aa[0], a[3]) + m(aa[1], a[2]), + m(aa[0], a[4]) + m(aa[1], a[3]) + m( a[2], a[2]), + m(aa[0], a[5]) + m(aa[1], a[4]) + m(aa[2], a[3]), + m(aa[0], a[6]) + m(aa[1], a[5]) + m(aa[2], a[4]) + m( a[3], a[3]), + m(aa[0], a[7]) + m(aa[1], a[6]) + m(aa[2], a[5]) + m(aa[3], a[4]), + m(aa[0], a[8]) + m(aa[1], a[7]) + m(aa[2], a[6]) + m(aa[3], a[5]) + m( a[4], a[4]), + m(aa[1], a[8]) + m(aa[2], a[7]) + m(aa[3], a[6]) + m(aa[4], a[5]), + m(aa[2], a[8]) + m(aa[3], a[7]) + m(aa[4], a[6]) + m( a[5], a[5]), + m(aa[3], a[8]) + m(aa[4], a[7]) + m(aa[5], a[6]), + m(aa[4], a[8]) + m(aa[5], a[7]) + m( a[6], a[6]), + m(aa[5], a[8]) + m(aa[6], a[7]), + m(aa[6], a[8]) + m( a[7], a[7]), + m(aa[7], a[8]), + m( a[8], a[8]), ] } /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^261 #[inline(always)] + #[rustfmt::skip] // keep alignment of part1() and part2() computations pub (crate) fn montgomery_reduce(limbs: &[u64; 17]) -> Scalar29 { #[inline(always)] @@ -369,11 +377,12 @@ impl Scalar29 { /// Puts a Scalar29 in to Montgomery form, i.e. computes `a*R (mod l)` #[inline(never)] - pub fn to_montgomery(&self) -> Scalar29 { + pub fn as_montgomery(&self) -> Scalar29 { Scalar29::montgomery_mul(self, &constants::RR) } /// Takes a Scalar29 out of Montgomery form, i.e. computes `a/R (mod l)` + #[allow(clippy::wrong_self_convention)] pub fn from_montgomery(&self) -> Scalar29 { let mut limbs = [0u64; 17]; for i in 0..9 { @@ -393,65 +402,65 @@ mod test { /// x = 2^253-1 = 14474011154664524427946373126085988481658748083205070504932198000989141204991 /// x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l /// x = 5147078182513738803124273553712992179887200054963030844803268920753008712037*R mod l in Montgomery form - pub static X: Scalar29 = Scalar29( - [0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, - 0x001fffff]); + pub static X: Scalar29 = Scalar29([ + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x1fffffff, 0x001fffff, + ]); /// x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l - pub static XX: Scalar29 = Scalar29( - [0x00217559, 0x000b3401, 0x103ff43b, 0x1462a62c, - 0x1d6f9f38, 0x18e7a42f, 0x09a3dcee, 0x008dbe18, - 0x0006ce65]); + pub static XX: Scalar29 = Scalar29([ + 0x00217559, 0x000b3401, 0x103ff43b, 0x1462a62c, 0x1d6f9f38, 0x18e7a42f, 0x09a3dcee, + 0x008dbe18, 0x0006ce65, + ]); /// x^2 = 2912514428060642753613814151688322857484807845836623976981729207238463947987*R mod l in Montgomery form - pub static XX_MONT: Scalar29 = Scalar29( - [0x152b4d2e, 0x0571d53b, 0x1da6d964, 0x188663b6, - 0x1d1b5f92, 0x19d50e3f, 0x12306c29, 0x0c6f26fe, - 0x00030edb]); + pub static XX_MONT: Scalar29 = Scalar29([ + 0x152b4d2e, 0x0571d53b, 0x1da6d964, 0x188663b6, 0x1d1b5f92, 0x19d50e3f, 0x12306c29, + 0x0c6f26fe, 0x00030edb, + ]); /// y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 - pub static Y: Scalar29 = Scalar29( - [0x1e1458fa, 0x165ba838, 0x1d787b36, 0x0e577f3a, - 0x1d2baf06, 0x1d689a19, 0x1fff3047, 0x117704ab, - 0x000d9601]); + pub static Y: Scalar29 = Scalar29([ + 0x1e1458fa, 0x165ba838, 0x1d787b36, 0x0e577f3a, 0x1d2baf06, 0x1d689a19, 0x1fff3047, + 0x117704ab, 0x000d9601, + ]); /// x*y = 36752150652102274958925982391442301741 - pub static XY: Scalar29 = Scalar29( - [0x0ba7632d, 0x017736bb, 0x15c76138, 0x0c69daa1, - 0x000001ba, 0x00000000, 0x00000000, 0x00000000, - 0x00000000]); + pub static XY: Scalar29 = Scalar29([ + 0x0ba7632d, 0x017736bb, 0x15c76138, 0x0c69daa1, 0x000001ba, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, + ]); /// x*y = 3783114862749659543382438697751927473898937741870308063443170013240655651591*R mod l in Montgomery form - pub static XY_MONT: Scalar29 = Scalar29( - [0x077b51e1, 0x1c64e119, 0x02a19ef5, 0x18d2129e, - 0x00de0430, 0x045a7bc8, 0x04cfc7c9, 0x1c002681, - 0x000bdc1c]); + pub static XY_MONT: Scalar29 = Scalar29([ + 0x077b51e1, 0x1c64e119, 0x02a19ef5, 0x18d2129e, 0x00de0430, 0x045a7bc8, 0x04cfc7c9, + 0x1c002681, 0x000bdc1c, + ]); /// a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 - pub static A: Scalar29 = Scalar29( - [0x07b3be89, 0x02291b60, 0x14a99f03, 0x07dc3787, - 0x0a782aae, 0x16262525, 0x0cfdb93f, 0x13f5718d, - 0x000532da]); + pub static A: Scalar29 = Scalar29([ + 0x07b3be89, 0x02291b60, 0x14a99f03, 0x07dc3787, 0x0a782aae, 0x16262525, 0x0cfdb93f, + 0x13f5718d, 0x000532da, + ]); /// b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 - pub static B: Scalar29 = Scalar29( - [0x15421564, 0x1e69fd72, 0x093d9692, 0x161785be, - 0x1587d69f, 0x09d9dada, 0x130246c0, 0x0c0a8e72, - 0x000acd25]); + pub static B: Scalar29 = Scalar29([ + 0x15421564, 0x1e69fd72, 0x093d9692, 0x161785be, 0x1587d69f, 0x09d9dada, 0x130246c0, + 0x0c0a8e72, 0x000acd25, + ]); /// a+b = 0 /// a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 - pub static AB: Scalar29 = Scalar29( - [0x0f677d12, 0x045236c0, 0x09533e06, 0x0fb86f0f, - 0x14f0555c, 0x0c4c4a4a, 0x19fb727f, 0x07eae31a, - 0x000a65b5]); + pub static AB: Scalar29 = Scalar29([ + 0x0f677d12, 0x045236c0, 0x09533e06, 0x0fb86f0f, 0x14f0555c, 0x0c4c4a4a, 0x19fb727f, + 0x07eae31a, 0x000a65b5, + ]); // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 - pub static C: Scalar29 = Scalar29( - [0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, - 0x1be65d00, 0x19e90bfa, 0x08f73bb1, 0x036f8613, - 0x00039941]); + pub static C: Scalar29 = Scalar29([ + 0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, 0x1be65d00, 0x19e90bfa, 0x08f73bb1, + 0x036f8613, 0x00039941, + ]); #[test] fn mul_max() { @@ -504,7 +513,7 @@ mod test { #[test] fn add() { let res = Scalar29::add(&A, &B); - let zero = Scalar29::zero(); + let zero = Scalar29::ZERO; for i in 0..9 { assert!(res[i] == zero[i]); } diff --git a/src/backend/serial/u32e/constants.rs b/curve25519-dalek/src/backend/serial/u32e/constants.rs similarity index 99% rename from src/backend/serial/u32e/constants.rs rename to curve25519-dalek/src/backend/serial/u32e/constants.rs index 77bbe147d..2e4a5e82c 100644 --- a/src/backend/serial/u32e/constants.rs +++ b/curve25519-dalek/src/backend/serial/u32e/constants.rs @@ -11,11 +11,15 @@ //! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. -use backend::serial::curve_models::AffineNielsPoint; use super::field::Engine25519; use super::scalar::Scalar29; -use edwards::{EdwardsBasepointTable, EdwardsPoint}; -use window::{LookupTable, NafLookupTable8}; +use crate::edwards::EdwardsPoint; +#[cfg(feature = "precomputed-tables")] +use crate::{ + backend::serial::curve_models::AffineNielsPoint, + edwards::EdwardsBasepointTable, + window::{LookupTable, NafLookupTable8}, +}; /// The value of minus one, equal to `-&FieldElement::one()` pub(crate) const MINUS_ONE: Engine25519 = Engine25519([ @@ -198,11 +202,13 @@ pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ ]; /// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). -pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; +#[cfg(feature = "precomputed-tables")] +pub static ED25519_BASEPOINT_TABLE: &'static EdwardsBasepointTable = &ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; /// Inner constant, used to avoid filling the docs with precomputed points. #[doc(hidden)] -pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = +#[cfg(feature = "precomputed-tables")] +static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ LookupTable([ AffineNielsPoint { @@ -2319,6 +2325,8 @@ pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = ]); /// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +#[cfg(feature = "precomputed-tables")] +#[allow(dead_code)] pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = NafLookupTable8([ AffineNielsPoint { diff --git a/src/backend/serial/u32e/field.rs b/curve25519-dalek/src/backend/serial/u32e/field.rs similarity index 92% rename from src/backend/serial/u32e/field.rs rename to curve25519-dalek/src/backend/serial/u32e/field.rs index df367a054..85a560b3f 100644 --- a/src/backend/serial/u32e/field.rs +++ b/curve25519-dalek/src/backend/serial/u32e/field.rs @@ -59,17 +59,25 @@ pub(crate) enum EngineOp { Sub, } +#[allow(unused_qualifications)] pub(crate) fn engine(a: &[u8; 32], b: &[u8; 32], op: EngineOp) -> Engine25519 { use utralib::generated::*; - let mut engine = utralib::CSR::new(utra::engine::HW_ENGINE_BASE as *mut u32); - let mcode: &'static mut [u32] = unsafe{ core::slice::from_raw_parts_mut(utralib::HW_ENGINE_MEM as *mut u32, 1024) }; - // allocate the first three registers - let rf: [&'static mut [u32]; 3] = - unsafe { [ - core::slice::from_raw_parts_mut((utralib::HW_ENGINE_MEM + 0x1_0000 + 0 * 32) as *mut u32, 8), - core::slice::from_raw_parts_mut((utralib::HW_ENGINE_MEM + 0x1_0000 + 1 * 32) as *mut u32, 8), - core::slice::from_raw_parts_mut((utralib::HW_ENGINE_MEM + 0x1_0000 + 2 * 32) as *mut u32, 8), - ] }; + use crate::backend::serial::u32e::*; + + crate::backend::serial::u32e::ensure_engine(); + let mut engine = utralib::CSR::new(unsafe{ENGINE_BASE.unwrap()}.as_mut_ptr() as *mut u32); + let mcode: &'static mut [u32] = unsafe{ + core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) + }; + let rf: [&'static mut [u32]; 3] = [ + unsafe{core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + 0x1_0000 + 0 * 32) as *mut u32, 8)}, + unsafe{core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + 0x1_0000 + 1 * 32) as *mut u32, 8)}, + unsafe{core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + 0x1_0000 + 2 * 32) as *mut u32, 8)}, + ]; + match op { EngineOp::Mul => { let prog = assemble_engine25519!( @@ -322,23 +330,18 @@ impl Engine25519 { } /// Construct zero. - pub fn zero() -> Engine25519 { - Engine25519([ 0 ; 32 ]) - } + pub const ZERO: Engine25519 = Engine25519([ 0 ; 32 ]); /// Construct one. - pub fn one() -> Engine25519 { - Engine25519([ 1, 0, 0, 0, 0, 0, 0, 0, + pub const ONE: Engine25519 = Engine25519([ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ]) - } + ]); /// Construct -1. - pub fn minus_one() -> Engine25519 { - Engine25519([236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127]) - } + pub const MINUS_ONE: Engine25519 = + Engine25519([236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127]); /// Given `k > 0`, return `self^(2^k)`. pub fn pow2k(&self, k: u32) -> Engine25519 { @@ -371,7 +374,7 @@ impl Engine25519 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { + pub fn as_bytes(&self) -> [u8; 32] { self.0 } diff --git a/curve25519-dalek/src/backend/serial/u32e/mod.rs b/curve25519-dalek/src/backend/serial/u32e/mod.rs new file mode 100644 index 000000000..64cb11116 --- /dev/null +++ b/curve25519-dalek/src/backend/serial/u32e/mod.rs @@ -0,0 +1,157 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. +//! +//! This code is intended to be portable, but it requires that +//! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result +//! is constant-time on the target platform. + +use utralib::generated::*; + +pub mod field; + +pub mod scalar; + +pub mod constants; + +pub(crate) static mut ENGINE_BASE: Option = None; +pub(crate) static mut ENGINE_MEM: Option = None; + +pub(crate) const NUM_REGS: usize = 32; +pub(crate) const BITWIDTH: usize = 256; +pub(crate) const NUM_WINDOWS: usize = 16; +pub(crate) const RF_SIZE_IN_U32: usize = NUM_REGS * (BITWIDTH / 32); // 32 registers, 256 bits/register/32 bits per u32 +pub(crate) const TOTAL_RF_SIZE_IN_U32: usize = NUM_REGS * (BITWIDTH / 32) * NUM_WINDOWS; // 32 registers, 256 bits/register/32 bits per u32, times 16 windows +pub(crate) const RF_U8_BASE: usize = 0x1_0000; +#[allow(dead_code)] +pub(crate) const RF_U32_BASE: usize = 0x1_0000 / 4; + +pub fn free_engine() { + log::debug!("free engine"); + if let Some(base) = unsafe { ENGINE_BASE.take() } { + let mut engine = utralib::CSR::new(base.as_mut_ptr() as *mut u32); + engine.rmwf(utra::engine::POWER_ON, 1); + xous::unmap_memory(base).unwrap(); + } + if let Some(mem) = unsafe { ENGINE_MEM.take() } { + xous::unmap_memory(mem).unwrap(); + } +} + +pub fn ensure_engine() { + if unsafe { ENGINE_BASE.is_none() } { + let base = xous::syscall::map_memory( + xous::MemoryAddress::new(utra::engine::HW_ENGINE_BASE), + None, + 4096, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("couldn't map engine CSR range"); + log::debug!("claiming engine csr {:x?}", base.as_ptr()); + unsafe { + ENGINE_BASE = Some(base); + } + } + if unsafe { ENGINE_MEM.is_none() } { + let mem = xous::syscall::map_memory( + xous::MemoryAddress::new(HW_ENGINE_MEM), + None, + HW_ENGINE_MEM_LEN, + xous::MemoryFlags::R | xous::MemoryFlags::W, + ) + .expect("couldn't map engine memory window range"); + log::debug!("claiming engine mem {:x?}", mem.as_ptr()); + unsafe { ENGINE_MEM = Some(mem) }; + } + let mut engine = utralib::CSR::new(unsafe { ENGINE_BASE.unwrap() }.as_mut_ptr() as *mut u32); + engine.rmwf(utra::engine::POWER_ON, 1); +} + +/// Safety: must be called after ensure_engine() +pub unsafe fn get_ucode() -> &'static mut [u32] { + core::slice::from_raw_parts_mut(ENGINE_MEM.unwrap().as_mut_ptr() as *mut u32, 1024) +} +/// Safety: must be called after ensure_engine() +pub unsafe fn get_rf() -> &'static mut [u32] { + core::slice::from_raw_parts_mut( + (ENGINE_MEM.unwrap().as_mut_ptr() as usize + RF_U8_BASE) as *mut u32, + TOTAL_RF_SIZE_IN_U32, + ) +} + +pub fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32], window: usize) { + use core::convert::TryInto; + for (byte, rf_dst) in bytes.chunks_exact(4).zip( + rf[window * RF_SIZE_IN_U32 + register * 8..window * RF_SIZE_IN_U32 + (register + 1) * 8] + .iter_mut(), + ) { + *rf_dst = u32::from_le_bytes(byte.try_into().expect("chunks_exact failed us")); + } +} + +pub fn copy_from_rf(register: usize, rf: &[u32], window: usize) -> [u8; 32] { + let mut ret: [u8; 32] = [0; 32]; + + for (src, dst) in rf + [window * RF_SIZE_IN_U32 + register * 8..window * RF_SIZE_IN_U32 + (register + 1) * 8] + .iter() + .zip(ret.chunks_exact_mut(4).into_iter()) + { + for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { + *dst_byte = src_byte; + } + } + + ret +} + +pub fn get_single_result(rf_hw: &[u32], window: usize, r: usize) -> [u8; 32] { + // TODO: put handlers for illegal opcodes, suspend/resume catch + + let mut ret_r: [u8; 32] = [0; 32]; + for (&src, dst) in rf_hw[window * RF_SIZE_IN_U32 + r * 8..window * RF_SIZE_IN_U32 + (r + 1) * 8] + .iter() + .zip(ret_r.chunks_exact_mut(4)) + { + for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { + *dst_byte = src_byte; + } + } + ret_r +} + +/// This assumes that arguments have been loaded in appropriate locations for the microcode +/// and that the result is always in r31. +pub fn run_job( + ucode_hw: &mut [u32], + rf_hw: &[u32], + mcode: &[i32], + window: usize, +) -> [u8; 32] { + let mut engine = utralib::CSR::new(unsafe { ENGINE_BASE.unwrap() }.as_mut_ptr() as *mut u32); + + let mpstart = 0; + + for (&src, dst) in mcode.iter().zip(ucode_hw[mpstart as usize..].iter_mut()) { + unsafe { (dst as *mut u32).write_volatile(src as u32) }; + } + let job_len = mcode.len() as u32; + + engine.wfo(utra::engine::WINDOW_WINDOW, window as u32); // this value should now be validated because an invalid window would cause a panic on slice copy + engine.wfo(utra::engine::MPSTART_MPSTART, mpstart); + engine.wfo(utra::engine::MPLEN_MPLEN, job_len); + + engine.wfo(utra::engine::CONTROL_GO, 1); + while engine.rf(utra::engine::STATUS_RUNNING) != 0 {} + + get_single_result(&rf_hw, window, 31) +} diff --git a/src/backend/serial/u32e/scalar.rs b/curve25519-dalek/src/backend/serial/u32e/scalar.rs similarity index 58% rename from src/backend/serial/u32e/scalar.rs rename to curve25519-dalek/src/backend/serial/u32e/scalar.rs index cc313150d..c251e8bbe 100644 --- a/src/backend/serial/u32e/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u32e/scalar.rs @@ -10,16 +10,26 @@ //! -0x1ffffffe00000008 (62 bits with sign bit) to //! 0x43fffffbc0000011 (63 bits), which is still safe. +use core::fmt::Debug; use core::ops::{Index, IndexMut}; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; -use constants; +use crate::constants; -/// The `Scalar29` struct represents an element in ℤ/lℤ as 9 29-bit limbs -#[derive(Copy,Clone)] +/// The `Scalar29` struct represents an element in \\(\mathbb{Z} / \ell\mathbb{Z}\\) as 9 29-bit +/// limbs +#[derive(Copy, Clone)] pub struct Scalar29(pub [u32; 9]); +impl Debug for Scalar29 { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + write!(f, "Scalar29: {:?}", &self.0[..]) + } +} + +#[cfg(feature = "zeroize")] impl Zeroize for Scalar29 { fn zeroize(&mut self) { self.0.zeroize(); @@ -46,12 +56,11 @@ fn m(x: u32, y: u32) -> u64 { } impl Scalar29 { - /// Return the zero scalar. - pub fn zero() -> Scalar29 { - Scalar29([0,0,0,0,0,0,0,0,0]) - } + /// The scalar \\( 0 \\). + pub const ZERO: Scalar29 = Scalar29([0, 0, 0, 0, 0, 0, 0, 0, 0]); /// Unpack a 32 byte / 256 bit scalar into 9 29-bit limbs. + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn from_bytes(bytes: &[u8; 32]) -> Scalar29 { let mut words = [0u32; 8]; for i in 0..8 { @@ -62,22 +71,23 @@ impl Scalar29 { let mask = (1u32 << 29) - 1; let top_mask = (1u32 << 24) - 1; - let mut s = Scalar29::zero(); - - s[ 0] = words[0] & mask; - s[ 1] = ((words[0] >> 29) | (words[1] << 3)) & mask; - s[ 2] = ((words[1] >> 26) | (words[2] << 6)) & mask; - s[ 3] = ((words[2] >> 23) | (words[3] << 9)) & mask; - s[ 4] = ((words[3] >> 20) | (words[4] << 12)) & mask; - s[ 5] = ((words[4] >> 17) | (words[5] << 15)) & mask; - s[ 6] = ((words[5] >> 14) | (words[6] << 18)) & mask; - s[ 7] = ((words[6] >> 11) | (words[7] << 21)) & mask; - s[ 8] = (words[7] >> 8) & top_mask; + let mut s = Scalar29::ZERO; + + s[0] = words[0] & mask; + s[1] = ((words[0] >> 29) | (words[1] << 3)) & mask; + s[2] = ((words[1] >> 26) | (words[2] << 6)) & mask; + s[3] = ((words[2] >> 23) | (words[3] << 9)) & mask; + s[4] = ((words[3] >> 20) | (words[4] << 12)) & mask; + s[5] = ((words[4] >> 17) | (words[5] << 15)) & mask; + s[6] = ((words[5] >> 14) | (words[6] << 18)) & mask; + s[7] = ((words[6] >> 11) | (words[7] << 21)) & mask; + s[8] = (words[7] >> 8) & top_mask; s } /// Reduce a 64 byte / 512 bit scalar mod l. + #[rustfmt::skip] // keep alignment of lo[*] calculations pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar29 { let mut words = [0u32; 16]; for i in 0..16 { @@ -87,8 +97,8 @@ impl Scalar29 { } let mask = (1u32 << 29) - 1; - let mut lo = Scalar29::zero(); - let mut hi = Scalar29::zero(); + let mut lo = Scalar29::ZERO; + let mut hi = Scalar29::ZERO; lo[0] = words[ 0] & mask; lo[1] = ((words[ 0] >> 29) | (words[ 1] << 3)) & mask; @@ -116,48 +126,50 @@ impl Scalar29 { } /// Pack the limbs of this `Scalar29` into 32 bytes. - pub fn to_bytes(&self) -> [u8; 32] { + #[rustfmt::skip] // keep alignment of s[*] calculations + #[allow(clippy::identity_op)] + pub fn as_bytes(&self) -> [u8; 32] { let mut s = [0u8; 32]; - s[0] = (self.0[ 0] >> 0) as u8; - s[1] = (self.0[ 0] >> 8) as u8; - s[2] = (self.0[ 0] >> 16) as u8; - s[3] = ((self.0[ 0] >> 24) | (self.0[ 1] << 5)) as u8; - s[4] = (self.0[ 1] >> 3) as u8; - s[5] = (self.0[ 1] >> 11) as u8; - s[6] = (self.0[ 1] >> 19) as u8; - s[7] = ((self.0[ 1] >> 27) | (self.0[ 2] << 2)) as u8; - s[8] = (self.0[ 2] >> 6) as u8; - s[9] = (self.0[ 2] >> 14) as u8; - s[10] = ((self.0[ 2] >> 22) | (self.0[ 3] << 7)) as u8; - s[11] = (self.0[ 3] >> 1) as u8; - s[12] = (self.0[ 3] >> 9) as u8; - s[13] = (self.0[ 3] >> 17) as u8; - s[14] = ((self.0[ 3] >> 25) | (self.0[ 4] << 4)) as u8; - s[15] = (self.0[ 4] >> 4) as u8; - s[16] = (self.0[ 4] >> 12) as u8; - s[17] = (self.0[ 4] >> 20) as u8; - s[18] = ((self.0[ 4] >> 28) | (self.0[ 5] << 1)) as u8; - s[19] = (self.0[ 5] >> 7) as u8; - s[20] = (self.0[ 5] >> 15) as u8; - s[21] = ((self.0[ 5] >> 23) | (self.0[ 6] << 6)) as u8; - s[22] = (self.0[ 6] >> 2) as u8; - s[23] = (self.0[ 6] >> 10) as u8; - s[24] = (self.0[ 6] >> 18) as u8; - s[25] = ((self.0[ 6] >> 26) | (self.0[ 7] << 3)) as u8; - s[26] = (self.0[ 7] >> 5) as u8; - s[27] = (self.0[ 7] >> 13) as u8; - s[28] = (self.0[ 7] >> 21) as u8; - s[29] = (self.0[ 8] >> 0) as u8; - s[30] = (self.0[ 8] >> 8) as u8; - s[31] = (self.0[ 8] >> 16) as u8; + s[ 0] = (self.0[0] >> 0) as u8; + s[ 1] = (self.0[0] >> 8) as u8; + s[ 2] = (self.0[0] >> 16) as u8; + s[ 3] = ((self.0[0] >> 24) | (self.0[1] << 5)) as u8; + s[ 4] = (self.0[1] >> 3) as u8; + s[ 5] = (self.0[1] >> 11) as u8; + s[ 6] = (self.0[1] >> 19) as u8; + s[ 7] = ((self.0[1] >> 27) | (self.0[2] << 2)) as u8; + s[ 8] = (self.0[2] >> 6) as u8; + s[ 9] = (self.0[2] >> 14) as u8; + s[10] = ((self.0[2] >> 22) | (self.0[3] << 7)) as u8; + s[11] = (self.0[3] >> 1) as u8; + s[12] = (self.0[3] >> 9) as u8; + s[13] = (self.0[3] >> 17) as u8; + s[14] = ((self.0[3] >> 25) | (self.0[4] << 4)) as u8; + s[15] = (self.0[4] >> 4) as u8; + s[16] = (self.0[4] >> 12) as u8; + s[17] = (self.0[4] >> 20) as u8; + s[18] = ((self.0[4] >> 28) | (self.0[5] << 1)) as u8; + s[19] = (self.0[5] >> 7) as u8; + s[20] = (self.0[5] >> 15) as u8; + s[21] = ((self.0[5] >> 23) | (self.0[6] << 6)) as u8; + s[22] = (self.0[6] >> 2) as u8; + s[23] = (self.0[6] >> 10) as u8; + s[24] = (self.0[6] >> 18) as u8; + s[25] = ((self.0[6] >> 26) | (self.0[7] << 3)) as u8; + s[26] = (self.0[7] >> 5) as u8; + s[27] = (self.0[7] >> 13) as u8; + s[28] = (self.0[7] >> 21) as u8; + s[29] = (self.0[8] >> 0) as u8; + s[30] = (self.0[8] >> 8) as u8; + s[31] = (self.0[8] >> 16) as u8; s } /// Compute `a + b` (mod l). pub fn add(a: &Scalar29, b: &Scalar29) -> Scalar29 { - let mut sum = Scalar29::zero(); + let mut sum = Scalar29::ZERO; let mask = (1u32 << 29) - 1; // a + b @@ -173,7 +185,7 @@ impl Scalar29 { /// Compute `a - b` (mod l). pub fn sub(a: &Scalar29, b: &Scalar29) -> Scalar29 { - let mut difference = Scalar29::zero(); + let mut difference = Scalar29::ZERO; let mask = (1u32 << 29) - 1; // a - b @@ -198,26 +210,27 @@ impl Scalar29 { /// /// This is implemented with a one-level refined Karatsuba decomposition #[inline(always)] + #[rustfmt::skip] // keep alignment of z[*] calculations pub (crate) fn mul_internal(a: &Scalar29, b: &Scalar29) -> [u64; 17] { let mut z = [0u64; 17]; - z[0] = m(a[0],b[0]); // c00 - z[1] = m(a[0],b[1]) + m(a[1],b[0]); // c01 - z[2] = m(a[0],b[2]) + m(a[1],b[1]) + m(a[2],b[0]); // c02 - z[3] = m(a[0],b[3]) + m(a[1],b[2]) + m(a[2],b[1]) + m(a[3],b[0]); // c03 - z[4] = m(a[0],b[4]) + m(a[1],b[3]) + m(a[2],b[2]) + m(a[3],b[1]) + m(a[4],b[0]); // c04 - z[5] = m(a[1],b[4]) + m(a[2],b[3]) + m(a[3],b[2]) + m(a[4],b[1]); // c05 - z[6] = m(a[2],b[4]) + m(a[3],b[3]) + m(a[4],b[2]); // c06 - z[7] = m(a[3],b[4]) + m(a[4],b[3]); // c07 - z[8] = (m(a[4],b[4])).wrapping_sub(z[3]); // c08 - c03 - - z[10] = z[5].wrapping_sub(m(a[5],b[5])); // c05mc10 - z[11] = z[6].wrapping_sub(m(a[5],b[6]) + m(a[6],b[5])); // c06mc11 - z[12] = z[7].wrapping_sub(m(a[5],b[7]) + m(a[6],b[6]) + m(a[7],b[5])); // c07mc12 - z[13] = m(a[5],b[8]) + m(a[6],b[7]) + m(a[7],b[6]) + m(a[8],b[5]); // c13 - z[14] = m(a[6],b[8]) + m(a[7],b[7]) + m(a[8],b[6]); // c14 - z[15] = m(a[7],b[8]) + m(a[8],b[7]); // c15 - z[16] = m(a[8],b[8]); // c16 + z[0] = m(a[0], b[0]); // c00 + z[1] = m(a[0], b[1]) + m(a[1], b[0]); // c01 + z[2] = m(a[0], b[2]) + m(a[1], b[1]) + m(a[2], b[0]); // c02 + z[3] = m(a[0], b[3]) + m(a[1], b[2]) + m(a[2], b[1]) + m(a[3], b[0]); // c03 + z[4] = m(a[0], b[4]) + m(a[1], b[3]) + m(a[2], b[2]) + m(a[3], b[1]) + m(a[4], b[0]); // c04 + z[5] = m(a[1], b[4]) + m(a[2], b[3]) + m(a[3], b[2]) + m(a[4], b[1]); // c05 + z[6] = m(a[2], b[4]) + m(a[3], b[3]) + m(a[4], b[2]); // c06 + z[7] = m(a[3], b[4]) + m(a[4], b[3]); // c07 + z[8] = (m(a[4], b[4])).wrapping_sub(z[3]); // c08 - c03 + + z[10] = z[5].wrapping_sub(m(a[5], b[5])); // c05mc10 + z[11] = z[6].wrapping_sub(m(a[5], b[6]) + m(a[6], b[5])); // c06mc11 + z[12] = z[7].wrapping_sub(m(a[5], b[7]) + m(a[6], b[6]) + m(a[7], b[5])); // c07mc12 + z[13] = m(a[5], b[8]) + m(a[6], b[7]) + m(a[7], b[6]) + m(a[8], b[5]); // c13 + z[14] = m(a[6], b[8]) + m(a[7], b[7]) + m(a[8], b[6]); // c14 + z[15] = m(a[7], b[8]) + m(a[8], b[7]); // c15 + z[16] = m(a[8], b[8]); // c16 z[ 5] = z[10].wrapping_sub(z[ 0]); // c05mc10 - c00 z[ 6] = z[11].wrapping_sub(z[ 1]); // c06mc11 - c01 @@ -228,68 +241,70 @@ impl Scalar29 { z[11] = z[16].wrapping_add(z[11]); // c16 + c06mc11 let aa = [ - a[0]+a[5], - a[1]+a[6], - a[2]+a[7], - a[3]+a[8] + a[0] + a[5], + a[1] + a[6], + a[2] + a[7], + a[3] + a[8] ]; let bb = [ - b[0]+b[5], - b[1]+b[6], - b[2]+b[7], - b[3]+b[8] + b[0] + b[5], + b[1] + b[6], + b[2] + b[7], + b[3] + b[8] ]; - z[ 5] = (m(aa[0],bb[0])) .wrapping_add(z[ 5]); // c20 + c05mc10 - c00 - z[ 6] = (m(aa[0],bb[1]) + m(aa[1],bb[0])) .wrapping_add(z[ 6]); // c21 + c06mc11 - c01 - z[ 7] = (m(aa[0],bb[2]) + m(aa[1],bb[1]) + m(aa[2],bb[0])) .wrapping_add(z[ 7]); // c22 + c07mc12 - c02 - z[ 8] = (m(aa[0],bb[3]) + m(aa[1],bb[2]) + m(aa[2],bb[1]) + m(aa[3],bb[0])) .wrapping_add(z[ 8]); // c23 + c08mc13 - c03 - z[ 9] = (m(aa[0], b[4]) + m(aa[1],bb[3]) + m(aa[2],bb[2]) + m(aa[3],bb[1]) + m(a[4],bb[0])).wrapping_sub(z[ 9]); // c24 - c14 - c04 - z[10] = ( m(aa[1], b[4]) + m(aa[2],bb[3]) + m(aa[3],bb[2]) + m(a[4],bb[1])).wrapping_sub(z[10]); // c25 - c15 - c05mc10 - z[11] = ( m(aa[2], b[4]) + m(aa[3],bb[3]) + m(a[4],bb[2])).wrapping_sub(z[11]); // c26 - c16 - c06mc11 - z[12] = ( m(aa[3], b[4]) + m(a[4],bb[3])).wrapping_sub(z[12]); // c27 - c07mc12 + z[ 5] = (m(aa[0], bb[0])) .wrapping_add(z[ 5]); // c20 + c05mc10 - c00 + z[ 6] = (m(aa[0], bb[1]) + m(aa[1], bb[0])) .wrapping_add(z[ 6]); // c21 + c06mc11 - c01 + z[ 7] = (m(aa[0], bb[2]) + m(aa[1], bb[1]) + m(aa[2], bb[0])) .wrapping_add(z[ 7]); // c22 + c07mc12 - c02 + z[ 8] = (m(aa[0], bb[3]) + m(aa[1], bb[2]) + m(aa[2], bb[1]) + m(aa[3], bb[0])) .wrapping_add(z[ 8]); // c23 + c08mc13 - c03 + z[ 9] = (m(aa[0], b[4]) + m(aa[1], bb[3]) + m(aa[2], bb[2]) + m(aa[3], bb[1]) + m(a[4], bb[0])).wrapping_sub(z[ 9]); // c24 - c14 - c04 + z[10] = ( m(aa[1], b[4]) + m(aa[2], bb[3]) + m(aa[3], bb[2]) + m(a[4], bb[1])).wrapping_sub(z[10]); // c25 - c15 - c05mc10 + z[11] = ( m(aa[2], b[4]) + m(aa[3], bb[3]) + m(a[4], bb[2])).wrapping_sub(z[11]); // c26 - c16 - c06mc11 + z[12] = ( m(aa[3], b[4]) + m(a[4], bb[3])).wrapping_sub(z[12]); // c27 - c07mc12 z } /// Compute `a^2`. #[inline(always)] + #[rustfmt::skip] // keep alignment of calculations fn square_internal(a: &Scalar29) -> [u64; 17] { let aa = [ - a[0]*2, - a[1]*2, - a[2]*2, - a[3]*2, - a[4]*2, - a[5]*2, - a[6]*2, - a[7]*2 + a[0] * 2, + a[1] * 2, + a[2] * 2, + a[3] * 2, + a[4] * 2, + a[5] * 2, + a[6] * 2, + a[7] * 2 ]; [ - m( a[0],a[0]), - m(aa[0],a[1]), - m(aa[0],a[2]) + m( a[1],a[1]), - m(aa[0],a[3]) + m(aa[1],a[2]), - m(aa[0],a[4]) + m(aa[1],a[3]) + m( a[2],a[2]), - m(aa[0],a[5]) + m(aa[1],a[4]) + m(aa[2],a[3]), - m(aa[0],a[6]) + m(aa[1],a[5]) + m(aa[2],a[4]) + m( a[3],a[3]), - m(aa[0],a[7]) + m(aa[1],a[6]) + m(aa[2],a[5]) + m(aa[3],a[4]), - m(aa[0],a[8]) + m(aa[1],a[7]) + m(aa[2],a[6]) + m(aa[3],a[5]) + m( a[4],a[4]), - m(aa[1],a[8]) + m(aa[2],a[7]) + m(aa[3],a[6]) + m(aa[4],a[5]), - m(aa[2],a[8]) + m(aa[3],a[7]) + m(aa[4],a[6]) + m( a[5],a[5]), - m(aa[3],a[8]) + m(aa[4],a[7]) + m(aa[5],a[6]), - m(aa[4],a[8]) + m(aa[5],a[7]) + m( a[6],a[6]), - m(aa[5],a[8]) + m(aa[6],a[7]), - m(aa[6],a[8]) + m( a[7],a[7]), - m(aa[7],a[8]), - m( a[8],a[8]), + m( a[0], a[0]), + m(aa[0], a[1]), + m(aa[0], a[2]) + m( a[1], a[1]), + m(aa[0], a[3]) + m(aa[1], a[2]), + m(aa[0], a[4]) + m(aa[1], a[3]) + m( a[2], a[2]), + m(aa[0], a[5]) + m(aa[1], a[4]) + m(aa[2], a[3]), + m(aa[0], a[6]) + m(aa[1], a[5]) + m(aa[2], a[4]) + m( a[3], a[3]), + m(aa[0], a[7]) + m(aa[1], a[6]) + m(aa[2], a[5]) + m(aa[3], a[4]), + m(aa[0], a[8]) + m(aa[1], a[7]) + m(aa[2], a[6]) + m(aa[3], a[5]) + m( a[4], a[4]), + m(aa[1], a[8]) + m(aa[2], a[7]) + m(aa[3], a[6]) + m(aa[4], a[5]), + m(aa[2], a[8]) + m(aa[3], a[7]) + m(aa[4], a[6]) + m( a[5], a[5]), + m(aa[3], a[8]) + m(aa[4], a[7]) + m(aa[5], a[6]), + m(aa[4], a[8]) + m(aa[5], a[7]) + m( a[6], a[6]), + m(aa[5], a[8]) + m(aa[6], a[7]), + m(aa[6], a[8]) + m( a[7], a[7]), + m(aa[7], a[8]), + m( a[8], a[8]), ] } /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^261 #[inline(always)] + #[rustfmt::skip] // keep alignment of part1() and part2() computations pub (crate) fn montgomery_reduce(limbs: &[u64; 17]) -> Scalar29 { #[inline(always)] @@ -362,11 +377,12 @@ impl Scalar29 { /// Puts a Scalar29 in to Montgomery form, i.e. computes `a*R (mod l)` #[inline(never)] - pub fn to_montgomery(&self) -> Scalar29 { + pub fn as_montgomery(&self) -> Scalar29 { Scalar29::montgomery_mul(self, &constants::RR) } /// Takes a Scalar29 out of Montgomery form, i.e. computes `a/R (mod l)` + #[allow(clippy::wrong_self_convention)] pub fn from_montgomery(&self) -> Scalar29 { let mut limbs = [0u64; 17]; for i in 0..9 { @@ -376,7 +392,6 @@ impl Scalar29 { } } - #[cfg(test)] mod test { use super::*; @@ -387,65 +402,65 @@ mod test { /// x = 2^253-1 = 14474011154664524427946373126085988481658748083205070504932198000989141204991 /// x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l /// x = 5147078182513738803124273553712992179887200054963030844803268920753008712037*R mod l in Montgomery form - pub static X: Scalar29 = Scalar29( - [0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, - 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, - 0x001fffff]); + pub static X: Scalar29 = Scalar29([ + 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, 0x1fffffff, + 0x1fffffff, 0x001fffff, + ]); /// x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l - pub static XX: Scalar29 = Scalar29( - [0x00217559, 0x000b3401, 0x103ff43b, 0x1462a62c, - 0x1d6f9f38, 0x18e7a42f, 0x09a3dcee, 0x008dbe18, - 0x0006ce65]); + pub static XX: Scalar29 = Scalar29([ + 0x00217559, 0x000b3401, 0x103ff43b, 0x1462a62c, 0x1d6f9f38, 0x18e7a42f, 0x09a3dcee, + 0x008dbe18, 0x0006ce65, + ]); /// x^2 = 2912514428060642753613814151688322857484807845836623976981729207238463947987*R mod l in Montgomery form - pub static XX_MONT: Scalar29 = Scalar29( - [0x152b4d2e, 0x0571d53b, 0x1da6d964, 0x188663b6, - 0x1d1b5f92, 0x19d50e3f, 0x12306c29, 0x0c6f26fe, - 0x00030edb]); + pub static XX_MONT: Scalar29 = Scalar29([ + 0x152b4d2e, 0x0571d53b, 0x1da6d964, 0x188663b6, 0x1d1b5f92, 0x19d50e3f, 0x12306c29, + 0x0c6f26fe, 0x00030edb, + ]); /// y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 - pub static Y: Scalar29 = Scalar29( - [0x1e1458fa, 0x165ba838, 0x1d787b36, 0x0e577f3a, - 0x1d2baf06, 0x1d689a19, 0x1fff3047, 0x117704ab, - 0x000d9601]); + pub static Y: Scalar29 = Scalar29([ + 0x1e1458fa, 0x165ba838, 0x1d787b36, 0x0e577f3a, 0x1d2baf06, 0x1d689a19, 0x1fff3047, + 0x117704ab, 0x000d9601, + ]); /// x*y = 36752150652102274958925982391442301741 - pub static XY: Scalar29 = Scalar29( - [0x0ba7632d, 0x017736bb, 0x15c76138, 0x0c69daa1, - 0x000001ba, 0x00000000, 0x00000000, 0x00000000, - 0x00000000]); + pub static XY: Scalar29 = Scalar29([ + 0x0ba7632d, 0x017736bb, 0x15c76138, 0x0c69daa1, 0x000001ba, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, + ]); /// x*y = 3783114862749659543382438697751927473898937741870308063443170013240655651591*R mod l in Montgomery form - pub static XY_MONT: Scalar29 = Scalar29( - [0x077b51e1, 0x1c64e119, 0x02a19ef5, 0x18d2129e, - 0x00de0430, 0x045a7bc8, 0x04cfc7c9, 0x1c002681, - 0x000bdc1c]); + pub static XY_MONT: Scalar29 = Scalar29([ + 0x077b51e1, 0x1c64e119, 0x02a19ef5, 0x18d2129e, 0x00de0430, 0x045a7bc8, 0x04cfc7c9, + 0x1c002681, 0x000bdc1c, + ]); /// a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 - pub static A: Scalar29 = Scalar29( - [0x07b3be89, 0x02291b60, 0x14a99f03, 0x07dc3787, - 0x0a782aae, 0x16262525, 0x0cfdb93f, 0x13f5718d, - 0x000532da]); + pub static A: Scalar29 = Scalar29([ + 0x07b3be89, 0x02291b60, 0x14a99f03, 0x07dc3787, 0x0a782aae, 0x16262525, 0x0cfdb93f, + 0x13f5718d, 0x000532da, + ]); /// b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 - pub static B: Scalar29 = Scalar29( - [0x15421564, 0x1e69fd72, 0x093d9692, 0x161785be, - 0x1587d69f, 0x09d9dada, 0x130246c0, 0x0c0a8e72, - 0x000acd25]); + pub static B: Scalar29 = Scalar29([ + 0x15421564, 0x1e69fd72, 0x093d9692, 0x161785be, 0x1587d69f, 0x09d9dada, 0x130246c0, + 0x0c0a8e72, 0x000acd25, + ]); /// a+b = 0 /// a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 - pub static AB: Scalar29 = Scalar29( - [0x0f677d12, 0x045236c0, 0x09533e06, 0x0fb86f0f, - 0x14f0555c, 0x0c4c4a4a, 0x19fb727f, 0x07eae31a, - 0x000a65b5]); + pub static AB: Scalar29 = Scalar29([ + 0x0f677d12, 0x045236c0, 0x09533e06, 0x0fb86f0f, 0x14f0555c, 0x0c4c4a4a, 0x19fb727f, + 0x07eae31a, 0x000a65b5, + ]); // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 - pub static C: Scalar29 = Scalar29( - [0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, - 0x1be65d00, 0x19e90bfa, 0x08f73bb1, 0x036f8613, - 0x00039941]); + pub static C: Scalar29 = Scalar29([ + 0x049c0f00, 0x00308f1a, 0x0164d1e9, 0x1c374ed1, 0x1be65d00, 0x19e90bfa, 0x08f73bb1, + 0x036f8613, 0x00039941, + ]); #[test] fn mul_max() { @@ -498,7 +513,7 @@ mod test { #[test] fn add() { let res = Scalar29::add(&A, &B); - let zero = Scalar29::zero(); + let zero = Scalar29::ZERO; for i in 0..9 { assert!(res[i] == zero[i]); } diff --git a/curve25519-dalek/src/backend/serial/u64/constants.rs b/curve25519-dalek/src/backend/serial/u64/constants.rs new file mode 100644 index 000000000..baeb1dd5d --- /dev/null +++ b/curve25519-dalek/src/backend/serial/u64/constants.rs @@ -0,0 +1,7769 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. + +use super::field::FieldElement51; +use super::scalar::Scalar52; +use crate::edwards::EdwardsPoint; + +#[cfg(feature = "precomputed-tables")] +use crate::{ + backend::serial::curve_models::AffineNielsPoint, + edwards::EdwardsBasepointTable, + window::{LookupTable, NafLookupTable8}, +}; + +/// The value of minus one, equal to `-&FieldElement::ONE` +pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51::from_limbs([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, +]); + +/// Edwards `d` value, equal to `-121665/121666 mod p`. +pub(crate) const EDWARDS_D: FieldElement51 = FieldElement51::from_limbs([ + 929955233495203, + 466365720129213, + 1662059464998953, + 2033849074728123, + 1442794654840575, +]); + +/// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. +pub(crate) const EDWARDS_D2: FieldElement51 = FieldElement51::from_limbs([ + 1859910466990425, + 932731440258426, + 1072319116312658, + 1815898335770999, + 633789495995903, +]); + +/// One minus edwards `d` value squared, equal to `(1 - (-121665/121666) mod p) pow 2` +pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51::from_limbs([ + 1136626929484150, + 1998550399581263, + 496427632559748, + 118527312129759, + 45110755273534, +]); + +/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` +pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51::from_limbs([ + 1507062230895904, + 1572317787530805, + 683053064812840, + 317374165784489, + 1572899562415810, +]); + +/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const SQRT_AD_MINUS_ONE: FieldElement51 = FieldElement51::from_limbs([ + 2241493124984347, + 425987919032274, + 2207028919301688, + 1220490630685848, + 974799131293748, +]); + +/// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. +pub(crate) const INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51::from_limbs([ + 278908739862762, + 821645201101625, + 8113234426968, + 1777959178193151, + 2118520810568447, +]); + +/// Precomputed value of one of the square roots of -1 (mod p) +pub(crate) const SQRT_M1: FieldElement51 = FieldElement51::from_limbs([ + 1718705420411056, + 234908883556509, + 2233514472574048, + 2117202627021982, + 765476049583133, +]); + +/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) +pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = + FieldElement51::from_limbs([121666, 0, 0, 0, 0]); + +/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation +/// for Curve25519 in its Montgomery form. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A: FieldElement51 = FieldElement51::from_limbs([486662, 0, 0, 0, 0]); + +/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the +/// Elligator map.) +pub(crate) const MONTGOMERY_A_NEG: FieldElement51 = FieldElement51::from_limbs([ + 2251799813198567, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, +]); + +/// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493 +pub(crate) const L: Scalar52 = Scalar52([ + 0x0002631a5cf5d3ed, + 0x000dea2f79cd6581, + 0x000000000014def9, + 0x0000000000000000, + 0x0000100000000000, +]); + +/// `L` * `LFACTOR` = -1 (mod 2^52) +pub(crate) const LFACTOR: u64 = 0x51da312547e1b; + +/// `R` = R % L where R = 2^260 +pub(crate) const R: Scalar52 = Scalar52([ + 0x000f48bd6721e6ed, + 0x0003bab5ac67e45a, + 0x000fffffeb35e51b, + 0x000fffffffffffff, + 0x00000fffffffffff, +]); + +/// `RR` = (R^2) % L where R = 2^260 +pub(crate) const RR: Scalar52 = Scalar52([ + 0x0009d265e952d13b, + 0x000d63c715bea69f, + 0x0005be65cb687604, + 0x0003dceec73d217f, + 0x000009411b7c309a, +]); + +/// The Ed25519 basepoint, as an `EdwardsPoint`. +/// +/// This is called `_POINT` to distinguish it from +/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar +/// multiplication (it's much faster). +pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { + X: FieldElement51::from_limbs([ + 1738742601995546, + 1146398526822698, + 2070867633025821, + 562264141797630, + 587772402128613, + ]), + Y: FieldElement51::from_limbs([ + 1801439850948184, + 1351079888211148, + 450359962737049, + 900719925474099, + 1801439850948198, + ]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ + 1841354044333475, + 16398895984059, + 755974180946558, + 900171276175154, + 1821297809914039, + ]), +}; + +/// The 8-torsion subgroup \\(\mathcal E \[8\]\\). +/// +/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of +/// the array is \\(\[i\]P\\), where \\(P\\) is a point of order \\(8\\) +/// generating \\(\mathcal E\[8\]\\). +/// +/// Thus \\(\mathcal E\[4\]\\) is the points indexed by `0,2,4,6`, and +/// \\(\mathcal E\[2\]\\) is the points indexed by `0,4`. +pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; + +/// Inner item used to hide limb constants from cargo doc output. +#[doc(hidden)] +pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ + EdwardsPoint { + X: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + Y: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51::from_limbs([ + 358744748052810, + 1691584618240980, + 977650209285361, + 1429865912637724, + 560044844278676, + ]), + Y: FieldElement51::from_limbs([ + 84926274344903, + 473620666599931, + 365590438845504, + 1028470286882429, + 2146499180330972, + ]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ + 1448326834587521, + 1857896831960481, + 1093722731865333, + 1677408490711241, + 1915505153018406, + ]), + }, + EdwardsPoint { + X: FieldElement51::from_limbs([ + 533094393274173, + 2016890930128738, + 18285341111199, + 134597186663265, + 1486323764102114, + ]), + Y: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51::from_limbs([ + 358744748052810, + 1691584618240980, + 977650209285361, + 1429865912637724, + 560044844278676, + ]), + Y: FieldElement51::from_limbs([ + 2166873539340326, + 1778179147085316, + 1886209374839743, + 1223329526802818, + 105300633354275, + ]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ + 803472979097708, + 393902981724766, + 1158077081819914, + 574391322974006, + 336294660666841, + ]), + }, + EdwardsPoint { + X: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + Y: FieldElement51::from_limbs([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, + ]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51::from_limbs([ + 1893055065632419, + 560215195444267, + 1274149604399886, + 821933901047523, + 1691754969406571, + ]), + Y: FieldElement51::from_limbs([ + 2166873539340326, + 1778179147085316, + 1886209374839743, + 1223329526802818, + 105300633354275, + ]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ + 1448326834587521, + 1857896831960481, + 1093722731865333, + 1677408490711241, + 1915505153018406, + ]), + }, + EdwardsPoint { + X: FieldElement51::from_limbs([ + 1718705420411056, + 234908883556509, + 2233514472574048, + 2117202627021982, + 765476049583133, + ]), + Y: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([0, 0, 0, 0, 0]), + }, + EdwardsPoint { + X: FieldElement51::from_limbs([ + 1893055065632419, + 560215195444267, + 1274149604399886, + 821933901047523, + 1691754969406571, + ]), + Y: FieldElement51::from_limbs([ + 84926274344903, + 473620666599931, + 365590438845504, + 1028470286882429, + 2146499180330972, + ]), + Z: FieldElement51::from_limbs([1, 0, 0, 0, 0]), + T: FieldElement51::from_limbs([ + 803472979097708, + 393902981724766, + 1158077081819914, + 574391322974006, + 336294660666841, + ]), + }, +]; + +/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). +#[cfg(feature = "precomputed-tables")] +pub static ED25519_BASEPOINT_TABLE: &EdwardsBasepointTable = + &ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; + +/// Inner constant, used to avoid filling the docs with precomputed points. +#[doc(hidden)] +#[cfg(feature = "precomputed-tables")] +static ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = EdwardsBasepointTable([ + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3540182452943730, + 2497478415033846, + 2521227595762870, + 1462984067271729, + 2389212253076811, + ]), + y_minus_x: FieldElement51::from_limbs([ + 62697248952638, + 204681361388450, + 631292143396476, + 338455783676468, + 1213667448819585, + ]), + xy2d: FieldElement51::from_limbs([ + 301289933810280, + 1259582250014073, + 1422107436869536, + 796239922652654, + 1953934009299142, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3632771708514775, + 790832306631235, + 2067202295274102, + 1995808275510000, + 1566530869037010, + ]), + y_minus_x: FieldElement51::from_limbs([ + 463307831301544, + 432984605774163, + 1610641361907204, + 750899048855000, + 1894842303421586, + ]), + xy2d: FieldElement51::from_limbs([ + 748439484463711, + 1033211726465151, + 1396005112841647, + 1611506220286469, + 1972177495910992, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1601611775252272, + 1720807796594148, + 1132070835939856, + 3512254832574799, + 2147779492816910, + ]), + y_minus_x: FieldElement51::from_limbs([ + 316559037616741, + 2177824224946892, + 1459442586438991, + 1461528397712656, + 751590696113597, + ]), + xy2d: FieldElement51::from_limbs([ + 1850748884277385, + 1200145853858453, + 1068094770532492, + 672251375690438, + 1586055907191707, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 934282339813791, + 1846903124198670, + 1172395437954843, + 1007037127761661, + 1830588347719256, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1694390458783935, + 1735906047636159, + 705069562067493, + 648033061693059, + 696214010414170, + ]), + xy2d: FieldElement51::from_limbs([ + 1121406372216585, + 192876649532226, + 190294192191717, + 1994165897297032, + 2245000007398739, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 769950342298400, + 2384754244604994, + 3095885746880802, + 3225892188161580, + 2977876099231263, + ]), + y_minus_x: FieldElement51::from_limbs([ + 425251763115706, + 608463272472562, + 442562545713235, + 837766094556764, + 374555092627893, + ]), + xy2d: FieldElement51::from_limbs([ + 1086255230780037, + 274979815921559, + 1960002765731872, + 929474102396301, + 1190409889297339, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1388594989461809, + 316767091099457, + 2646098655878230, + 1230079486801004, + 1440737038838979, + ]), + y_minus_x: FieldElement51::from_limbs([ + 7380825640100, + 146210432690483, + 304903576448906, + 1198869323871120, + 997689833219095, + ]), + xy2d: FieldElement51::from_limbs([ + 1181317918772081, + 114573476638901, + 262805072233344, + 265712217171332, + 294181933805782, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2916800678241215, + 2065379846933858, + 2622030924071124, + 2602788184473875, + 1233371373142984, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2019367628972465, + 676711900706637, + 110710997811333, + 1108646842542025, + 517791959672113, + ]), + xy2d: FieldElement51::from_limbs([ + 965130719900578, + 247011430587952, + 526356006571389, + 91986625355052, + 2157223321444601, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 4320419353804412, + 4218074731744053, + 957728544705548, + 729906502578991, + 2411634706750414, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2073601412052185, + 31021124762708, + 264500969797082, + 248034690651703, + 1030252227928288, + ]), + xy2d: FieldElement51::from_limbs([ + 551790716293402, + 1989538725166328, + 801169423371717, + 2052451893578887, + 678432056995012, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1368953770187805, + 3042147450398169, + 2689308289352409, + 2142576377050579, + 1932081720066286, + ]), + y_minus_x: FieldElement51::from_limbs([ + 953638594433374, + 1092333936795051, + 1419774766716690, + 805677984380077, + 859228993502513, + ]), + xy2d: FieldElement51::from_limbs([ + 1200766035879111, + 20142053207432, + 1465634435977050, + 1645256912097844, + 295121984874596, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1735718747031538, + 1248237894295956, + 1204753118328107, + 976066523550493, + 2317743583219840, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1060098822528990, + 1586825862073490, + 212301317240126, + 1975302711403555, + 666724059764335, + ]), + xy2d: FieldElement51::from_limbs([ + 1091990273418756, + 1572899409348578, + 80968014455247, + 306009358661350, + 1520450739132526, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3732317023121341, + 1511153322193951, + 3496143672676420, + 2556587964178488, + 2620936670181690, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2151330273626164, + 762045184746182, + 1688074332551515, + 823046109005759, + 907602769079491, + ]), + xy2d: FieldElement51::from_limbs([ + 2047386910586836, + 168470092900250, + 1552838872594810, + 340951180073789, + 360819374702533, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1982622644432037, + 2014393600336956, + 2380709022489462, + 3869592437614438, + 2357094095599062, + ]), + y_minus_x: FieldElement51::from_limbs([ + 980234343912898, + 1712256739246056, + 588935272190264, + 204298813091998, + 841798321043288, + ]), + xy2d: FieldElement51::from_limbs([ + 197561292938973, + 454817274782871, + 1963754960082318, + 2113372252160468, + 971377527342673, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2416499262514576, + 2254927265442919, + 3451304785234000, + 1766155447043651, + 1899238924683527, + ]), + y_minus_x: FieldElement51::from_limbs([ + 732262946680281, + 1674412764227063, + 2182456405662809, + 1350894754474250, + 558458873295247, + ]), + xy2d: FieldElement51::from_limbs([ + 2103305098582922, + 1960809151316468, + 715134605001343, + 1454892949167181, + 40827143824949, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1239289043050193, + 1744654158124578, + 758702410031698, + 4048562808759936, + 2253402870349013, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2232056027107988, + 987343914584615, + 2115594492994461, + 1819598072792159, + 1119305654014850, + ]), + xy2d: FieldElement51::from_limbs([ + 320153677847348, + 939613871605645, + 641883205761567, + 1930009789398224, + 329165806634126, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3232730304159378, + 1242488692177892, + 1251446316964684, + 1086618677993530, + 1961430968465772, + ]), + y_minus_x: FieldElement51::from_limbs([ + 276821765317453, + 1536835591188030, + 1305212741412361, + 61473904210175, + 2051377036983058, + ]), + xy2d: FieldElement51::from_limbs([ + 833449923882501, + 1750270368490475, + 1123347002068295, + 185477424765687, + 278090826653186, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 794524995833413, + 1849907304548286, + 2305148486158393, + 1272368559505216, + 1147304168324779, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1504846112759364, + 1203096289004681, + 562139421471418, + 274333017451844, + 1284344053775441, + ]), + xy2d: FieldElement51::from_limbs([ + 483048732424432, + 2116063063343382, + 30120189902313, + 292451576741007, + 1156379271702225, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3180171966714267, + 2147692869914563, + 1455665844462196, + 1986737809425946, + 2437006863943337, + ]), + y_minus_x: FieldElement51::from_limbs([ + 137732961814206, + 706670923917341, + 1387038086865771, + 1965643813686352, + 1384777115696347, + ]), + xy2d: FieldElement51::from_limbs([ + 481144981981577, + 2053319313589856, + 2065402289827512, + 617954271490316, + 1106602634668125, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2948097833334040, + 3145099472726142, + 1148636718636008, + 2278533891034865, + 2203955659340680, + ]), + y_minus_x: FieldElement51::from_limbs([ + 657390353372855, + 998499966885562, + 991893336905797, + 810470207106761, + 343139804608786, + ]), + xy2d: FieldElement51::from_limbs([ + 791736669492960, + 934767652997115, + 824656780392914, + 1759463253018643, + 361530362383518, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2022541353055578, + 4346500076272714, + 3802807888710933, + 2494585331103411, + 2947785218648809, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1287487199965223, + 2215311941380308, + 1552928390931986, + 1664859529680196, + 1125004975265243, + ]), + xy2d: FieldElement51::from_limbs([ + 677434665154918, + 989582503122485, + 1817429540898386, + 1052904935475344, + 1143826298169798, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2619066141993637, + 2570231002607651, + 2947429167440602, + 2885885471266079, + 2276381426249673, + ]), + y_minus_x: FieldElement51::from_limbs([ + 773360688841258, + 1815381330538070, + 363773437667376, + 539629987070205, + 783280434248437, + ]), + xy2d: FieldElement51::from_limbs([ + 180820816194166, + 168937968377394, + 748416242794470, + 1227281252254508, + 1567587861004268, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2730575372268893, + 2062896624554806, + 2951191072970647, + 2609899222113120, + 1277310261461760, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1984740906540026, + 1079164179400229, + 1056021349262661, + 1659958556483663, + 1088529069025527, + ]), + xy2d: FieldElement51::from_limbs([ + 580736401511151, + 1842931091388998, + 1177201471228238, + 2075460256527244, + 1301133425678027, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1515728832059163, + 1575261009617579, + 1510246567196186, + 2442877836294952, + 2368461529974388, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1295295738269652, + 1714742313707026, + 545583042462581, + 2034411676262552, + 1513248090013606, + ]), + xy2d: FieldElement51::from_limbs([ + 230710545179830, + 30821514358353, + 760704303452229, + 390668103790604, + 573437871383156, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3421179921230875, + 2514967047430861, + 4274701112739695, + 3071700566936367, + 4275698278559832, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2102254323485823, + 1570832666216754, + 34696906544624, + 1993213739807337, + 70638552271463, + ]), + xy2d: FieldElement51::from_limbs([ + 894132856735058, + 548675863558441, + 845349339503395, + 1942269668326667, + 1615682209874691, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3539470031223082, + 1222355136884919, + 1846481788678694, + 1150426571265110, + 1613523400722047, + ]), + y_minus_x: FieldElement51::from_limbs([ + 793388516527298, + 1315457083650035, + 1972286999342417, + 1901825953052455, + 338269477222410, + ]), + xy2d: FieldElement51::from_limbs([ + 550201530671806, + 778605267108140, + 2063911101902983, + 115500557286349, + 2041641272971022, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 717255318455100, + 519313764361315, + 2080406977303708, + 541981206705521, + 774328150311600, + ]), + y_minus_x: FieldElement51::from_limbs([ + 261715221532238, + 1795354330069993, + 1496878026850283, + 499739720521052, + 389031152673770, + ]), + xy2d: FieldElement51::from_limbs([ + 1997217696294013, + 1717306351628065, + 1684313917746180, + 1644426076011410, + 1857378133465451, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3727234538477877, + 2328731709971226, + 3368528843456914, + 2002544139318041, + 2977347647489186, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2022306639183567, + 726296063571875, + 315345054448644, + 1058733329149221, + 1448201136060677, + ]), + xy2d: FieldElement51::from_limbs([ + 1710065158525665, + 1895094923036397, + 123988286168546, + 1145519900776355, + 1607510767693874, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2813405189107769, + 1071733543815036, + 2383296312486238, + 1946868434569998, + 3079937947649451, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1548495173745801, + 442310529226540, + 998072547000384, + 553054358385281, + 644824326376171, + ]), + xy2d: FieldElement51::from_limbs([ + 1445526537029440, + 2225519789662536, + 914628859347385, + 1064754194555068, + 1660295614401091, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3451490036797185, + 2275827949507588, + 2318438102929588, + 2309425969971222, + 2816893781664854, + ]), + y_minus_x: FieldElement51::from_limbs([ + 876926774220824, + 554618976488214, + 1012056309841565, + 839961821554611, + 1414499340307677, + ]), + xy2d: FieldElement51::from_limbs([ + 703047626104145, + 1266841406201770, + 165556500219173, + 486991595001879, + 1011325891650656, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1622861044480487, + 1156394801573634, + 4120932379100752, + 2578903799462977, + 2095342781472283, + ]), + y_minus_x: FieldElement51::from_limbs([ + 334886927423922, + 489511099221528, + 129160865966726, + 1720809113143481, + 619700195649254, + ]), + xy2d: FieldElement51::from_limbs([ + 1646545795166119, + 1758370782583567, + 714746174550637, + 1472693650165135, + 898994790308209, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2585203586724508, + 2547572356138185, + 1693106465353609, + 912330357530760, + 2723035471635610, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1811196219982022, + 1068969825533602, + 289602974833439, + 1988956043611592, + 863562343398367, + ]), + xy2d: FieldElement51::from_limbs([ + 906282429780072, + 2108672665779781, + 432396390473936, + 150625823801893, + 1708930497638539, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 925664675702309, + 2273216662253932, + 4083236455546587, + 601157008940112, + 2623617868729744, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1479786007267725, + 1738881859066675, + 68646196476567, + 2146507056100328, + 1247662817535471, + ]), + xy2d: FieldElement51::from_limbs([ + 52035296774456, + 939969390708103, + 312023458773250, + 59873523517659, + 1231345905848899, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2895154920100990, + 2541986621181021, + 2013561737429022, + 2571447883196794, + 2645536492181409, + ]), + y_minus_x: FieldElement51::from_limbs([ + 129358342392716, + 1932811617704777, + 1176749390799681, + 398040349861790, + 1170779668090425, + ]), + xy2d: FieldElement51::from_limbs([ + 2051980782668029, + 121859921510665, + 2048329875753063, + 1235229850149665, + 519062146124755, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3859970785658325, + 2667608874045675, + 1350468408164765, + 2038620059057678, + 3278704299674360, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1837656083115103, + 1510134048812070, + 906263674192061, + 1821064197805734, + 565375124676301, + ]), + xy2d: FieldElement51::from_limbs([ + 578027192365650, + 2034800251375322, + 2128954087207123, + 478816193810521, + 2196171989962750, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1633188840273120, + 3104586986058956, + 1548762607215795, + 1266275218902681, + 3359018017010381, + ]), + y_minus_x: FieldElement51::from_limbs([ + 462189358480054, + 1784816734159228, + 1611334301651368, + 1303938263943540, + 707589560319424, + ]), + xy2d: FieldElement51::from_limbs([ + 1038829280972848, + 38176604650029, + 753193246598573, + 1136076426528122, + 595709990562434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3660251634545082, + 2194984964010832, + 2198361797561729, + 1061962440055713, + 1645147963442934, + ]), + y_minus_x: FieldElement51::from_limbs([ + 4701053362120, + 1647641066302348, + 1047553002242085, + 1923635013395977, + 206970314902065, + ]), + xy2d: FieldElement51::from_limbs([ + 1750479161778571, + 1362553355169293, + 1891721260220598, + 966109370862782, + 1024913988299801, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2464498862816952, + 1117950018299774, + 1873945661751056, + 3655602735669306, + 2382695896337945, + ]), + y_minus_x: FieldElement51::from_limbs([ + 636808533673210, + 1262201711667560, + 390951380330599, + 1663420692697294, + 561951321757406, + ]), + xy2d: FieldElement51::from_limbs([ + 520731594438141, + 1446301499955692, + 273753264629267, + 1565101517999256, + 1019411827004672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3178327305714638, + 3443653291096626, + 734233225181170, + 2435838701226518, + 4042225960010590, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1464651961852572, + 1483737295721717, + 1519450561335517, + 1161429831763785, + 405914998179977, + ]), + xy2d: FieldElement51::from_limbs([ + 996126634382301, + 796204125879525, + 127517800546509, + 344155944689303, + 615279846169038, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2990523894660505, + 2188666632415295, + 1961313708559162, + 1506545807547587, + 3403101452654988, + ]), + y_minus_x: FieldElement51::from_limbs([ + 622917337413835, + 1218989177089035, + 1284857712846592, + 970502061709359, + 351025208117090, + ]), + xy2d: FieldElement51::from_limbs([ + 2067814584765580, + 1677855129927492, + 2086109782475197, + 235286517313238, + 1416314046739645, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2838644076315587, + 2559244195637442, + 458399356043425, + 2853867838192310, + 3280348017100490, + ]), + y_minus_x: FieldElement51::from_limbs([ + 678489922928203, + 2016657584724032, + 90977383049628, + 1026831907234582, + 615271492942522, + ]), + xy2d: FieldElement51::from_limbs([ + 301225714012278, + 1094837270268560, + 1202288391010439, + 644352775178361, + 1647055902137983, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1210746697896459, + 1416608304244708, + 2938287290903104, + 3496931005119382, + 3303038150540984, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1135604073198207, + 1683322080485474, + 769147804376683, + 2086688130589414, + 900445683120379, + ]), + xy2d: FieldElement51::from_limbs([ + 1971518477615628, + 401909519527336, + 448627091057375, + 1409486868273821, + 1214789035034363, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1364039144731711, + 1897497433586190, + 2203097701135459, + 2397261210496499, + 1349844460790698, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1045230323257973, + 818206601145807, + 630513189076103, + 1672046528998132, + 807204017562437, + ]), + xy2d: FieldElement51::from_limbs([ + 439961968385997, + 386362664488986, + 1382706320807688, + 309894000125359, + 2207801346498567, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3480804500082836, + 3172443782216110, + 2375775707596425, + 2933223806901024, + 1400559197080972, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2003766096898049, + 170074059235165, + 1141124258967971, + 1485419893480973, + 1573762821028725, + ]), + xy2d: FieldElement51::from_limbs([ + 729905708611432, + 1270323270673202, + 123353058984288, + 426460209632942, + 2195574535456672, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1271140255321216, + 2044363183174497, + 2303925201319937, + 3696920060379952, + 3194341800024331, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1761608437466135, + 583360847526804, + 1586706389685493, + 2157056599579261, + 1170692369685772, + ]), + xy2d: FieldElement51::from_limbs([ + 871476219910823, + 1878769545097794, + 2241832391238412, + 548957640601001, + 690047440233174, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2548994545820755, + 1366347803776819, + 3552985325930849, + 561849853336293, + 1533554921345731, + ]), + y_minus_x: FieldElement51::from_limbs([ + 999628998628371, + 1132836708493400, + 2084741674517453, + 469343353015612, + 678782988708035, + ]), + xy2d: FieldElement51::from_limbs([ + 2189427607417022, + 699801937082607, + 412764402319267, + 1478091893643349, + 2244675696854460, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3964091869651792, + 2456213404310121, + 3657538451018088, + 2660781114515010, + 3112882032961968, + ]), + y_minus_x: FieldElement51::from_limbs([ + 508561155940631, + 966928475686665, + 2236717801150132, + 424543858577297, + 2089272956986143, + ]), + xy2d: FieldElement51::from_limbs([ + 221245220129925, + 1156020201681217, + 491145634799213, + 542422431960839, + 828100817819207, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2405556784925632, + 1299874139923976, + 2644898978945750, + 1058234455773021, + 996989038681183, + ]), + y_minus_x: FieldElement51::from_limbs([ + 559086812798481, + 573177704212711, + 1629737083816402, + 1399819713462595, + 1646954378266038, + ]), + xy2d: FieldElement51::from_limbs([ + 1887963056288059, + 228507035730124, + 1468368348640282, + 930557653420194, + 613513962454686, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1224529808187534, + 1577022856702685, + 2206946542980843, + 625883007765001, + 2531730607197406, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1076287717051609, + 1114455570543035, + 187297059715481, + 250446884292121, + 1885187512550540, + ]), + xy2d: FieldElement51::from_limbs([ + 902497362940219, + 76749815795675, + 1657927525633846, + 1420238379745202, + 1340321636548352, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1129576631190765, + 3533793823712575, + 996844254743017, + 2509676177174497, + 3402650555740265, + ]), + y_minus_x: FieldElement51::from_limbs([ + 628740660038789, + 1943038498527841, + 467786347793886, + 1093341428303375, + 235413859513003, + ]), + xy2d: FieldElement51::from_limbs([ + 237425418909360, + 469614029179605, + 1512389769174935, + 1241726368345357, + 441602891065214, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3988217766743784, + 726531315520507, + 1833335034432527, + 1629442561574747, + 2876218732971333, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1960754663920689, + 497040957888962, + 1909832851283095, + 1271432136996826, + 2219780368020940, + ]), + xy2d: FieldElement51::from_limbs([ + 1537037379417136, + 1358865369268262, + 2130838645654099, + 828733687040705, + 1999987652890901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 629042105241795, + 1098854999137608, + 887281544569320, + 3674901833560025, + 2259711072636808, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1811562332665373, + 1501882019007673, + 2213763501088999, + 359573079719636, + 36370565049116, + ]), + xy2d: FieldElement51::from_limbs([ + 218907117361280, + 1209298913016966, + 1944312619096112, + 1130690631451061, + 1342327389191701, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1369976867854685, + 1396479602419169, + 4017456468084104, + 2203659200586298, + 3250127649802489, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2230701885562825, + 1348173180338974, + 2172856128624598, + 1426538746123771, + 444193481326151, + ]), + xy2d: FieldElement51::from_limbs([ + 784210426627951, + 918204562375674, + 1284546780452985, + 1324534636134684, + 1872449409642708, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2571438643225542, + 2848082470493653, + 2037902696412607, + 1557219121643918, + 341938082688094, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1901860206695915, + 2004489122065736, + 1625847061568236, + 973529743399879, + 2075287685312905, + ]), + xy2d: FieldElement51::from_limbs([ + 1371853944110545, + 1042332820512553, + 1949855697918254, + 1791195775521505, + 37487364849293, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 687200189577836, + 1082536651125675, + 2896024754556794, + 2592723009743198, + 2595381160432643, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2082717129583892, + 27829425539422, + 145655066671970, + 1690527209845512, + 1865260509673478, + ]), + xy2d: FieldElement51::from_limbs([ + 1059729620568824, + 2163709103470266, + 1440302280256872, + 1769143160546397, + 869830310425069, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3861316033464273, + 777277757338816, + 2101121130363987, + 550762194946473, + 1905542338659364, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2024821921041576, + 426948675450149, + 595133284085473, + 471860860885970, + 600321679413000, + ]), + xy2d: FieldElement51::from_limbs([ + 598474602406721, + 1468128276358244, + 1191923149557635, + 1501376424093216, + 1281662691293476, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1721138489890688, + 1264336102277790, + 2684864359106535, + 1359988423149465, + 3813671107094695, + ]), + y_minus_x: FieldElement51::from_limbs([ + 719520245587143, + 393380711632345, + 132350400863381, + 1543271270810729, + 1819543295798660, + ]), + xy2d: FieldElement51::from_limbs([ + 396397949784152, + 1811354474471839, + 1362679985304303, + 2117033964846756, + 498041172552279, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1812471844975748, + 1856491995543149, + 126579494584102, + 3288044672967868, + 1975108050082549, + ]), + y_minus_x: FieldElement51::from_limbs([ + 650623932407995, + 1137551288410575, + 2125223403615539, + 1725658013221271, + 2134892965117796, + ]), + xy2d: FieldElement51::from_limbs([ + 522584000310195, + 1241762481390450, + 1743702789495384, + 2227404127826575, + 1686746002148897, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 427904865186293, + 1703211129693455, + 1585368107547509, + 3688784302429584, + 3012988348299225, + ]), + y_minus_x: FieldElement51::from_limbs([ + 318101947455002, + 248138407995851, + 1481904195303927, + 309278454311197, + 1258516760217879, + ]), + xy2d: FieldElement51::from_limbs([ + 1275068538599310, + 513726919533379, + 349926553492294, + 688428871968420, + 1702400196000666, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3313663849950481, + 3213411074010628, + 2573659446386085, + 3297400443644764, + 1985130202504037, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1558816436882417, + 1962896332636523, + 1337709822062152, + 1501413830776938, + 294436165831932, + ]), + xy2d: FieldElement51::from_limbs([ + 818359826554971, + 1862173000996177, + 626821592884859, + 573655738872376, + 1749691246745455, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1988022651432119, + 3333911312271288, + 1834020786104820, + 3706626690108935, + 692929915223121, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2146513703733331, + 584788900394667, + 464965657279958, + 2183973639356127, + 238371159456790, + ]), + xy2d: FieldElement51::from_limbs([ + 1129007025494441, + 2197883144413266, + 265142755578169, + 971864464758890, + 1983715884903702, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1291366624493056, + 2633256531874362, + 1711482489312443, + 1815233647702022, + 3144079596677715, + ]), + y_minus_x: FieldElement51::from_limbs([ + 444548969917454, + 1452286453853356, + 2113731441506810, + 645188273895859, + 810317625309512, + ]), + xy2d: FieldElement51::from_limbs([ + 2242724082797924, + 1373354730327868, + 1006520110883049, + 2147330369940688, + 1151816104883620, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3997520014069025, + 4163522956860564, + 2056329390702073, + 2607026987995097, + 3131032608056347, + ]), + y_minus_x: FieldElement51::from_limbs([ + 163723479936298, + 115424889803150, + 1156016391581227, + 1894942220753364, + 1970549419986329, + ]), + xy2d: FieldElement51::from_limbs([ + 681981452362484, + 267208874112496, + 1374683991933094, + 638600984916117, + 646178654558546, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2265178468539480, + 2358037120714814, + 1944412051589650, + 4093776581610705, + 2482502633520820, + ]), + y_minus_x: FieldElement51::from_limbs([ + 260683893467075, + 854060306077237, + 913639551980112, + 4704576840123, + 280254810808712, + ]), + xy2d: FieldElement51::from_limbs([ + 715374893080287, + 1173334812210491, + 1806524662079626, + 1894596008000979, + 398905715033393, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2751826223412909, + 3848231101880618, + 1420380351989369, + 3237011375206737, + 392444930785632, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2096421546958141, + 1922523000950363, + 789831022876840, + 427295144688779, + 320923973161730, + ]), + xy2d: FieldElement51::from_limbs([ + 1927770723575450, + 1485792977512719, + 1850996108474547, + 551696031508956, + 2126047405475647, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2112099158080129, + 2994370617594963, + 2258284371762679, + 1951119898618915, + 2344890196388664, + ]), + y_minus_x: FieldElement51::from_limbs([ + 383905201636970, + 859946997631870, + 855623867637644, + 1017125780577795, + 794250831877809, + ]), + xy2d: FieldElement51::from_limbs([ + 77571826285752, + 999304298101753, + 487841111777762, + 1038031143212339, + 339066367948762, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2926794589205781, + 2517835660016036, + 826951213393477, + 1405007746162285, + 1781791018620876, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1001412661522686, + 348196197067298, + 1666614366723946, + 888424995032760, + 580747687801357, + ]), + xy2d: FieldElement51::from_limbs([ + 1939560076207777, + 1409892634407635, + 552574736069277, + 383854338280405, + 190706709864139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2177087163428741, + 1439255351721944, + 3459870654068041, + 2230616362004768, + 1396886392021913, + ]), + y_minus_x: FieldElement51::from_limbs([ + 676962063230039, + 1880275537148808, + 2046721011602706, + 888463247083003, + 1318301552024067, + ]), + xy2d: FieldElement51::from_limbs([ + 1466980508178206, + 617045217998949, + 652303580573628, + 757303753529064, + 207583137376902, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3762856566592150, + 2357202940576524, + 2745234706458093, + 1091943425335975, + 1802717338077427, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1853982405405128, + 1878664056251147, + 1528011020803992, + 1019626468153565, + 1128438412189035, + ]), + xy2d: FieldElement51::from_limbs([ + 1963939888391106, + 293456433791664, + 697897559513649, + 985882796904380, + 796244541237972, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2668570812315008, + 2641455366112301, + 1314476859406755, + 1749382513022778, + 3413705412424739, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1428358296490651, + 1027115282420478, + 304840698058337, + 441410174026628, + 1819358356278573, + ]), + xy2d: FieldElement51::from_limbs([ + 204943430200135, + 1554861433819175, + 216426658514651, + 264149070665950, + 2047097371738319, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1934415182909015, + 1393285083565062, + 2768209145458208, + 3409490548679139, + 2372839480279515, + ]), + y_minus_x: FieldElement51::from_limbs([ + 662035583584445, + 286736105093098, + 1131773000510616, + 818494214211439, + 472943792054479, + ]), + xy2d: FieldElement51::from_limbs([ + 665784778135882, + 1893179629898606, + 808313193813106, + 276797254706413, + 1563426179676396, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 945205108984213, + 2778077376644543, + 1324180513733565, + 1666970227868664, + 2405347422974421, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2031433403516252, + 203996615228162, + 170487168837083, + 981513604791390, + 843573964916831, + ]), + xy2d: FieldElement51::from_limbs([ + 1476570093962618, + 838514669399805, + 1857930577281364, + 2017007352225784, + 317085545220047, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1461557121912823, + 1600674043318359, + 2157134900399597, + 1670641601940616, + 2379565397488531, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1293543509393474, + 2143624609202546, + 1058361566797508, + 214097127393994, + 946888515472729, + ]), + xy2d: FieldElement51::from_limbs([ + 357067959932916, + 1290876214345711, + 521245575443703, + 1494975468601005, + 800942377643885, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2817916472785262, + 820247422481739, + 994464017954148, + 2578957425371613, + 2344391131796991, + ]), + y_minus_x: FieldElement51::from_limbs([ + 617256647603209, + 1652107761099439, + 1857213046645471, + 1085597175214970, + 817432759830522, + ]), + xy2d: FieldElement51::from_limbs([ + 771808161440705, + 1323510426395069, + 680497615846440, + 851580615547985, + 1320806384849017, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1219260086131896, + 2898968820282063, + 2331400938444953, + 2161724213426747, + 2656661710745446, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1327968293887866, + 1335500852943256, + 1401587164534264, + 558137311952440, + 1551360549268902, + ]), + xy2d: FieldElement51::from_limbs([ + 417621685193956, + 1429953819744454, + 396157358457099, + 1940470778873255, + 214000046234152, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1268047918491954, + 2172375426948536, + 1533916099229249, + 1761293575457130, + 3842422480712013, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1627072914981959, + 2211603081280073, + 1912369601616504, + 1191770436221309, + 2187309757525860, + ]), + xy2d: FieldElement51::from_limbs([ + 1149147819689533, + 378692712667677, + 828475842424202, + 2218619146419342, + 70688125792186, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3551539230764990, + 3690416477138006, + 3788528892189659, + 2053896748919837, + 3260220846276494, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2040723824657366, + 399555637875075, + 632543375452995, + 872649937008051, + 1235394727030233, + ]), + xy2d: FieldElement51::from_limbs([ + 2211311599327900, + 2139787259888175, + 938706616835350, + 12609661139114, + 2081897930719789, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1324994503390431, + 2588782144267879, + 1183998925654176, + 3343454479598522, + 2300527487656566, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1845522914617879, + 1222198248335542, + 150841072760134, + 1927029069940982, + 1189913404498011, + ]), + xy2d: FieldElement51::from_limbs([ + 1079559557592645, + 2215338383666441, + 1903569501302605, + 49033973033940, + 305703433934152, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2346453219102138, + 3637921163538246, + 3313930291577009, + 2288353761164521, + 3085469462634093, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1432015813136298, + 440364795295369, + 1395647062821501, + 1976874522764578, + 934452372723352, + ]), + xy2d: FieldElement51::from_limbs([ + 1296625309219774, + 2068273464883862, + 1858621048097805, + 1492281814208508, + 2235868981918946, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1490330266465551, + 1858795661361448, + 3688040948655011, + 2546373032584894, + 3459939824714180, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1282462923712748, + 741885683986255, + 2027754642827561, + 518989529541027, + 1826610009555945, + ]), + xy2d: FieldElement51::from_limbs([ + 1525827120027511, + 723686461809551, + 1597702369236987, + 244802101764964, + 1502833890372311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2365421849929742, + 3485539881431101, + 2925909765963743, + 2114345180342964, + 2418564326541511, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2041668749310338, + 2184405322203901, + 1633400637611036, + 2110682505536899, + 2048144390084644, + ]), + xy2d: FieldElement51::from_limbs([ + 503058759232932, + 760293024620937, + 2027152777219493, + 666858468148475, + 1539184379870952, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1916168475367211, + 3167426246226591, + 883217071712574, + 363427871374304, + 1976029821251593, + ]), + y_minus_x: FieldElement51::from_limbs([ + 678039535434506, + 570587290189340, + 1605302676614120, + 2147762562875701, + 1706063797091704, + ]), + xy2d: FieldElement51::from_limbs([ + 1439489648586438, + 2194580753290951, + 832380563557396, + 561521973970522, + 584497280718389, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2439789269177838, + 681223515948274, + 1933493571072456, + 1872921007304880, + 2739962177820919, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1413466089534451, + 410844090765630, + 1397263346404072, + 408227143123410, + 1594561803147811, + ]), + xy2d: FieldElement51::from_limbs([ + 2102170800973153, + 719462588665004, + 1479649438510153, + 1097529543970028, + 1302363283777685, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3193865531532443, + 3321113493038208, + 2007341951411050, + 2322773230131539, + 1419433790163705, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1146565545556377, + 1661971299445212, + 406681704748893, + 564452436406089, + 1109109865829139, + ]), + xy2d: FieldElement51::from_limbs([ + 2214421081775077, + 1165671861210569, + 1890453018796184, + 3556249878661, + 442116172656317, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3005630360306059, + 1666955059895018, + 1530775289309243, + 3371786842789394, + 2164156153857579, + ]), + y_minus_x: FieldElement51::from_limbs([ + 615171919212796, + 1523849404854568, + 854560460547503, + 2067097370290715, + 1765325848586042, + ]), + xy2d: FieldElement51::from_limbs([ + 1094538949313667, + 1796592198908825, + 870221004284388, + 2025558921863561, + 1699010892802384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1951351290725195, + 1916457206844795, + 2449824998123274, + 1909076887557594, + 1938542290318919, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1014323197538413, + 869150639940606, + 1756009942696599, + 1334952557375672, + 1544945379082874, + ]), + xy2d: FieldElement51::from_limbs([ + 764055910920305, + 1603590757375439, + 146805246592357, + 1843313433854297, + 954279890114939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 80113526615731, + 764536758732259, + 3306939158785481, + 2721052465444637, + 2869697326116762, + ]), + y_minus_x: FieldElement51::from_limbs([ + 74497112547268, + 740094153192149, + 1745254631717581, + 727713886503130, + 1283034364416928, + ]), + xy2d: FieldElement51::from_limbs([ + 525892105991110, + 1723776830270342, + 1476444848991936, + 573789489857760, + 133864092632978, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2794411533877810, + 1986812262899320, + 1162535242465837, + 2733298779828712, + 2796400347268869, + ]), + y_minus_x: FieldElement51::from_limbs([ + 64123227344372, + 1239927720647794, + 1360722983445904, + 222610813654661, + 62429487187991, + ]), + xy2d: FieldElement51::from_limbs([ + 1793193323953132, + 91096687857833, + 70945970938921, + 2158587638946380, + 1537042406482111, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1895854577604590, + 3646695522634664, + 1728548428495943, + 3392664713925397, + 2815445147288308, + ]), + y_minus_x: FieldElement51::from_limbs([ + 141358280486863, + 91435889572504, + 1087208572552643, + 1829599652522921, + 1193307020643647, + ]), + xy2d: FieldElement51::from_limbs([ + 1611230858525381, + 950720175540785, + 499589887488610, + 2001656988495019, + 88977313255908, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3440880315164906, + 2184348804772596, + 3292618539427567, + 2018318290311833, + 1712060030915354, + ]), + y_minus_x: FieldElement51::from_limbs([ + 873966876953756, + 1090638350350440, + 1708559325189137, + 672344594801910, + 1320437969700239, + ]), + xy2d: FieldElement51::from_limbs([ + 1508590048271766, + 1131769479776094, + 101550868699323, + 428297785557897, + 561791648661744, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3008217384184691, + 2489682092917849, + 2136263418594015, + 1701968045454886, + 2955512998822720, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1781187809325462, + 1697624151492346, + 1381393690939988, + 175194132284669, + 1483054666415238, + ]), + xy2d: FieldElement51::from_limbs([ + 2175517777364616, + 708781536456029, + 955668231122942, + 1967557500069555, + 2021208005604118, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3366935780292116, + 2476017186636029, + 915967306279221, + 593866251291540, + 2813546907893254, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1443163092879439, + 391875531646162, + 2180847134654632, + 464538543018753, + 1594098196837178, + ]), + xy2d: FieldElement51::from_limbs([ + 850858855888869, + 319436476624586, + 327807784938441, + 740785849558761, + 17128415486016, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2132756334090048, + 2788047633840893, + 2300706964962114, + 2860273011285942, + 3513489358708031, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1525176236978354, + 974205476721062, + 293436255662638, + 148269621098039, + 137961998433963, + ]), + xy2d: FieldElement51::from_limbs([ + 1121075518299410, + 2071745529082111, + 1265567917414828, + 1648196578317805, + 496232102750820, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2374121042985030, + 3274721891178932, + 2001275453369483, + 2017441881607947, + 3245005694463250, + ]), + y_minus_x: FieldElement51::from_limbs([ + 654925550560074, + 1168810995576858, + 575655959430926, + 905758704861388, + 496774564663534, + ]), + xy2d: FieldElement51::from_limbs([ + 1954109525779738, + 2117022646152485, + 338102630417180, + 1194140505732026, + 107881734943492, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1714785840001267, + 4288299832366837, + 1876380234251965, + 2056717182974196, + 1645855254384642, + ]), + y_minus_x: FieldElement51::from_limbs([ + 106431476499341, + 62482972120563, + 1513446655109411, + 807258751769522, + 538491469114, + ]), + xy2d: FieldElement51::from_limbs([ + 2002850762893643, + 1243624520538135, + 1486040410574605, + 2184752338181213, + 378495998083531, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 922510868424903, + 1089502620807680, + 402544072617374, + 1131446598479839, + 1290278588136533, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1867998812076769, + 715425053580701, + 39968586461416, + 2173068014586163, + 653822651801304, + ]), + xy2d: FieldElement51::from_limbs([ + 162892278589453, + 182585796682149, + 75093073137630, + 497037941226502, + 133871727117371, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 4166396390264918, + 1608999621851577, + 1987629837704609, + 1519655314857977, + 1819193753409464, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1949315551096831, + 1069003344994464, + 1939165033499916, + 1548227205730856, + 1933767655861407, + ]), + xy2d: FieldElement51::from_limbs([ + 1730519386931635, + 1393284965610134, + 1597143735726030, + 416032382447158, + 1429665248828629, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 360275475604546, + 2799635544748326, + 2467160717872776, + 2848446553564254, + 2584509464110332, + ]), + y_minus_x: FieldElement51::from_limbs([ + 47602113726801, + 1522314509708010, + 437706261372925, + 814035330438027, + 335930650933545, + ]), + xy2d: FieldElement51::from_limbs([ + 1291597595523886, + 1058020588994081, + 402837842324045, + 1363323695882781, + 2105763393033193, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2361321796251793, + 3967057562270386, + 1112231216891515, + 2046641005101484, + 2386048970842261, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2156991030936798, + 2227544497153325, + 1869050094431622, + 754875860479115, + 1754242344267058, + ]), + xy2d: FieldElement51::from_limbs([ + 1846089562873800, + 98894784984326, + 1412430299204844, + 171351226625762, + 1100604760929008, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2335972195815721, + 2751510784385293, + 425749630620777, + 1762872794206857, + 2864642415813208, + ]), + y_minus_x: FieldElement51::from_limbs([ + 868309334532756, + 1703010512741873, + 1952690008738057, + 4325269926064, + 2071083554962116, + ]), + xy2d: FieldElement51::from_limbs([ + 523094549451158, + 401938899487815, + 1407690589076010, + 2022387426254453, + 158660516411257, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 612867287630009, + 2700012425789062, + 2823428891104443, + 1466796750919375, + 1728478129663858, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1723848973783452, + 2208822520534681, + 1718748322776940, + 1974268454121942, + 1194212502258141, + ]), + xy2d: FieldElement51::from_limbs([ + 1254114807944608, + 977770684047110, + 2010756238954993, + 1783628927194099, + 1525962994408256, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2484263871921055, + 1948628555342433, + 1835348780427694, + 1031609499437291, + 2316271920603621, + ]), + y_minus_x: FieldElement51::from_limbs([ + 767338676040683, + 754089548318405, + 1523192045639075, + 435746025122062, + 512692508440385, + ]), + xy2d: FieldElement51::from_limbs([ + 1255955808701983, + 1700487367990941, + 1166401238800299, + 1175121994891534, + 1190934801395380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2600943821853521, + 1337012557669161, + 1475912332999108, + 3573418268585706, + 2299411105589567, + ]), + y_minus_x: FieldElement51::from_limbs([ + 877519947135419, + 2172838026132651, + 272304391224129, + 1655143327559984, + 886229406429814, + ]), + xy2d: FieldElement51::from_limbs([ + 375806028254706, + 214463229793940, + 572906353144089, + 572168269875638, + 697556386112979, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1168827102357825, + 823864273033637, + 4323338565789945, + 788062026895923, + 2851378154428610, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1948116082078088, + 2054898304487796, + 2204939184983900, + 210526805152138, + 786593586607626, + ]), + xy2d: FieldElement51::from_limbs([ + 1915320147894736, + 156481169009469, + 655050471180417, + 592917090415421, + 2165897438660879, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1726336468579724, + 1119932070398949, + 1929199510967666, + 2285718602008207, + 1836837863503149, + ]), + y_minus_x: FieldElement51::from_limbs([ + 829996854845988, + 217061778005138, + 1686565909803640, + 1346948817219846, + 1723823550730181, + ]), + xy2d: FieldElement51::from_limbs([ + 384301494966394, + 687038900403062, + 2211195391021739, + 254684538421383, + 1245698430589680, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1247567493562669, + 4229981908141095, + 2435671288478202, + 806570235643434, + 2540261331753164, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1449077384734201, + 38285445457996, + 2136537659177832, + 2146493000841573, + 725161151123125, + ]), + xy2d: FieldElement51::from_limbs([ + 1201928866368855, + 800415690605445, + 1703146756828343, + 997278587541744, + 1858284414104014, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2608268623334125, + 3034173730618399, + 1718002439402869, + 3644022065904502, + 663171266061950, + ]), + y_minus_x: FieldElement51::from_limbs([ + 759628738230460, + 1012693474275852, + 353780233086498, + 246080061387552, + 2030378857679162, + ]), + xy2d: FieldElement51::from_limbs([ + 2040672435071076, + 888593182036908, + 1298443657189359, + 1804780278521327, + 354070726137060, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1894938527423184, + 3715012855162525, + 2726210319182898, + 2499094776718546, + 877975941029127, + ]), + y_minus_x: FieldElement51::from_limbs([ + 207937160991127, + 12966911039119, + 820997788283092, + 1010440472205286, + 1701372890140810, + ]), + xy2d: FieldElement51::from_limbs([ + 218882774543183, + 533427444716285, + 1233243976733245, + 435054256891319, + 1509568989549904, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 4140638349397055, + 3303977572025869, + 3465353617009382, + 2420981822812579, + 2715174081801119, + ]), + y_minus_x: FieldElement51::from_limbs([ + 299137589460312, + 1594371588983567, + 868058494039073, + 257771590636681, + 1805012993142921, + ]), + xy2d: FieldElement51::from_limbs([ + 1806842755664364, + 2098896946025095, + 1356630998422878, + 1458279806348064, + 347755825962072, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1402334161391744, + 3811883484731547, + 1008585416617746, + 1147797150908892, + 1420416683642459, + ]), + y_minus_x: FieldElement51::from_limbs([ + 665506704253369, + 273770475169863, + 799236974202630, + 848328990077558, + 1811448782807931, + ]), + xy2d: FieldElement51::from_limbs([ + 1468412523962641, + 771866649897997, + 1931766110147832, + 799561180078482, + 524837559150077, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2223212657821831, + 2882216061048914, + 2144451165500327, + 3068710944633039, + 3276150872095279, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1266603897524861, + 156378408858100, + 1275649024228779, + 447738405888420, + 253186462063095, + ]), + xy2d: FieldElement51::from_limbs([ + 2022215964509735, + 136144366993649, + 1800716593296582, + 1193970603800203, + 871675847064218, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1862751661970309, + 851596246739884, + 1519315554814041, + 3794598280232697, + 3669775149586767, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1228168094547481, + 334133883362894, + 587567568420081, + 433612590281181, + 603390400373205, + ]), + xy2d: FieldElement51::from_limbs([ + 121893973206505, + 1843345804916664, + 1703118377384911, + 497810164760654, + 101150811654673, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2710146069631716, + 2542709749304591, + 1452768413850678, + 2802722688939463, + 1537286854336537, + ]), + y_minus_x: FieldElement51::from_limbs([ + 584322311184395, + 380661238802118, + 114839394528060, + 655082270500073, + 2111856026034852, + ]), + xy2d: FieldElement51::from_limbs([ + 996965581008991, + 2148998626477022, + 1012273164934654, + 1073876063914522, + 1688031788934939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3175286832534829, + 2085106799623354, + 2779882615305384, + 1606206360876187, + 2987706905397772, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1697697887804317, + 1335343703828273, + 831288615207040, + 949416685250051, + 288760277392022, + ]), + xy2d: FieldElement51::from_limbs([ + 1419122478109648, + 1325574567803701, + 602393874111094, + 2107893372601700, + 1314159682671307, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2201150872731785, + 2180241023425241, + 2349463270108411, + 1633405770247823, + 3100744856129234, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1173339555550611, + 818605084277583, + 47521504364289, + 924108720564965, + 735423405754506, + ]), + xy2d: FieldElement51::from_limbs([ + 830104860549448, + 1886653193241086, + 1600929509383773, + 1475051275443631, + 286679780900937, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3828911108518224, + 3282698983453994, + 2396700729978777, + 4216472406664814, + 2820189914640497, + ]), + y_minus_x: FieldElement51::from_limbs([ + 278388655910247, + 487143369099838, + 927762205508727, + 181017540174210, + 1616886700741287, + ]), + xy2d: FieldElement51::from_limbs([ + 1191033906638969, + 940823957346562, + 1606870843663445, + 861684761499847, + 658674867251089, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1875032594195527, + 1427106132796197, + 2976536204647406, + 3153660325729987, + 2887068310954007, + ]), + y_minus_x: FieldElement51::from_limbs([ + 622869792298357, + 1903919278950367, + 1922588621661629, + 1520574711600434, + 1087100760174640, + ]), + xy2d: FieldElement51::from_limbs([ + 25465949416618, + 1693639527318811, + 1526153382657203, + 125943137857169, + 145276964043999, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2466539671654587, + 920212862967914, + 4191701364657517, + 3463662605460468, + 2336897329405367, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2006245852772938, + 734762734836159, + 254642929763427, + 1406213292755966, + 239303749517686, + ]), + xy2d: FieldElement51::from_limbs([ + 1619678837192149, + 1919424032779215, + 1357391272956794, + 1525634040073113, + 1310226789796241, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3292563523447371, + 1704449869235351, + 2857062884141577, + 1998838089036354, + 1312142911487502, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1996723311435669, + 1844342766567060, + 985455700466044, + 1165924681400960, + 311508689870129, + ]), + xy2d: FieldElement51::from_limbs([ + 43173156290518, + 2202883069785309, + 1137787467085917, + 1733636061944606, + 1394992037553852, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 670078326344559, + 2807454838744604, + 2723759199967685, + 2141455487356408, + 849015953823125, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2197214573372804, + 794254097241315, + 1030190060513737, + 267632515541902, + 2040478049202624, + ]), + xy2d: FieldElement51::from_limbs([ + 1812516004670529, + 1609256702920783, + 1706897079364493, + 258549904773295, + 996051247540686, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1540374301420565, + 1764656898914615, + 1810104162020396, + 3175608592848336, + 2916189887881826, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1323460699404750, + 1262690757880991, + 871777133477900, + 1060078894988977, + 1712236889662886, + ]), + xy2d: FieldElement51::from_limbs([ + 1696163952057966, + 1391710137550823, + 608793846867416, + 1034391509472039, + 1780770894075012, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1367603834210822, + 4383788460268472, + 890353773628143, + 1908908219165595, + 2522636708938139, + ]), + y_minus_x: FieldElement51::from_limbs([ + 597536315471731, + 40375058742586, + 1942256403956049, + 1185484645495932, + 312666282024145, + ]), + xy2d: FieldElement51::from_limbs([ + 1919411405316294, + 1234508526402192, + 1066863051997083, + 1008444703737597, + 1348810787701552, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2102881477513865, + 3822074379630609, + 1573617900503707, + 2270462449417831, + 2232324307922097, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1853931367696942, + 8107973870707, + 350214504129299, + 775206934582587, + 1752317649166792, + ]), + xy2d: FieldElement51::from_limbs([ + 1417148368003523, + 721357181628282, + 505725498207811, + 373232277872983, + 261634707184480, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2186733281493248, + 2250694917008620, + 1014829812957440, + 2731797975137637, + 2335366007561721, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1268116367301224, + 560157088142809, + 802626839600444, + 2210189936605713, + 1129993785579988, + ]), + xy2d: FieldElement51::from_limbs([ + 615183387352312, + 917611676109240, + 878893615973325, + 978940963313282, + 938686890583575, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 522024729211672, + 3296859129001056, + 1892245413707789, + 1907891107684253, + 2059998109500714, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1799679152208884, + 912132775900387, + 25967768040979, + 432130448590461, + 274568990261996, + ]), + xy2d: FieldElement51::from_limbs([ + 98698809797682, + 2144627600856209, + 1907959298569602, + 811491302610148, + 1262481774981493, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1791451399743152, + 1713538728337276, + 2370149810942738, + 1882306388849953, + 158235232210248, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1217809823321928, + 2173947284933160, + 1986927836272325, + 1388114931125539, + 12686131160169, + ]), + xy2d: FieldElement51::from_limbs([ + 1650875518872272, + 1136263858253897, + 1732115601395988, + 734312880662190, + 1252904681142109, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2624786269799113, + 2777230729143418, + 2116279931702134, + 2753222527273063, + 1907002872974924, + ]), + y_minus_x: FieldElement51::from_limbs([ + 803147181835288, + 868941437997146, + 316299302989663, + 943495589630550, + 571224287904572, + ]), + xy2d: FieldElement51::from_limbs([ + 227742695588364, + 1776969298667369, + 628602552821802, + 457210915378118, + 2041906378111140, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 815000523470260, + 3164885502413555, + 3303859931956420, + 1345536665214222, + 541623413135555, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1580216071604333, + 1877997504342444, + 857147161260913, + 703522726778478, + 2182763974211603, + ]), + xy2d: FieldElement51::from_limbs([ + 1870080310923419, + 71988220958492, + 1783225432016732, + 615915287105016, + 1035570475990230, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2982787564515398, + 857613889540279, + 1083813157271766, + 1002817255970169, + 1719228484436074, + ]), + y_minus_x: FieldElement51::from_limbs([ + 377616581647602, + 1581980403078513, + 804044118130621, + 2034382823044191, + 643844048472185, + ]), + xy2d: FieldElement51::from_limbs([ + 176957326463017, + 1573744060478586, + 528642225008045, + 1816109618372371, + 1515140189765006, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1888911448245718, + 3638910709296328, + 4176303607751676, + 1731539523700948, + 2230378382645454, + ]), + y_minus_x: FieldElement51::from_limbs([ + 443392177002051, + 233793396845137, + 2199506622312416, + 1011858706515937, + 974676837063129, + ]), + xy2d: FieldElement51::from_limbs([ + 1846351103143623, + 1949984838808427, + 671247021915253, + 1946756846184401, + 1929296930380217, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 849646212451983, + 1410198775302919, + 2325567699868943, + 1641663456615811, + 3014056086137659, + ]), + y_minus_x: FieldElement51::from_limbs([ + 692017667358279, + 723305578826727, + 1638042139863265, + 748219305990306, + 334589200523901, + ]), + xy2d: FieldElement51::from_limbs([ + 22893968530686, + 2235758574399251, + 1661465835630252, + 925707319443452, + 1203475116966621, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3053098849470395, + 3985092410411378, + 1664508947088595, + 2719548934677170, + 3899298398220870, + ]), + y_minus_x: FieldElement51::from_limbs([ + 903105258014366, + 427141894933047, + 561187017169777, + 1884330244401954, + 1914145708422219, + ]), + xy2d: FieldElement51::from_limbs([ + 1344191060517578, + 1960935031767890, + 1518838929955259, + 1781502350597190, + 1564784025565682, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2925523165433334, + 1979969272514922, + 3427087126180756, + 1187589090978665, + 1881897672213940, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1917185587363432, + 1098342571752737, + 5935801044414, + 2000527662351839, + 1538640296181569, + ]), + xy2d: FieldElement51::from_limbs([ + 2495540013192, + 678856913479236, + 224998292422872, + 219635787698590, + 1972465269000940, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 271413961212179, + 3604851875156899, + 2596511104968730, + 2014925838520661, + 2006221033113941, + ]), + y_minus_x: FieldElement51::from_limbs([ + 194583029968109, + 514316781467765, + 829677956235672, + 1676415686873082, + 810104584395840, + ]), + xy2d: FieldElement51::from_limbs([ + 1980510813313589, + 1948645276483975, + 152063780665900, + 129968026417582, + 256984195613935, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1860190562533083, + 1936576191345085, + 2712900106391212, + 1811043097042829, + 3209286562992083, + ]), + y_minus_x: FieldElement51::from_limbs([ + 796664815624365, + 1543160838872951, + 1500897791837765, + 1667315977988401, + 599303877030711, + ]), + xy2d: FieldElement51::from_limbs([ + 1151480509533204, + 2136010406720455, + 738796060240027, + 319298003765044, + 1150614464349587, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1731069268103131, + 2987442261301335, + 1364750481334267, + 2669032653668119, + 3178908082812908, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1017222050227968, + 1987716148359, + 2234319589635701, + 621282683093392, + 2132553131763026, + ]), + xy2d: FieldElement51::from_limbs([ + 1567828528453324, + 1017807205202360, + 565295260895298, + 829541698429100, + 307243822276582, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 249079270936229, + 1501514259790706, + 3199709537890096, + 944551802437486, + 2804458577667728, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2089966982947227, + 1854140343916181, + 2151980759220007, + 2139781292261749, + 158070445864917, + ]), + xy2d: FieldElement51::from_limbs([ + 1338766321464554, + 1906702607371284, + 1519569445519894, + 115384726262267, + 1393058953390992, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3616421371950629, + 3764188048593604, + 1926731583198685, + 2041482526432505, + 3172200936019022, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1884844597333588, + 601480070269079, + 620203503079537, + 1079527400117915, + 1202076693132015, + ]), + xy2d: FieldElement51::from_limbs([ + 840922919763324, + 727955812569642, + 1303406629750194, + 522898432152867, + 294161410441865, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2605560604520539, + 1598361541848742, + 3374705511887547, + 4174333403844152, + 2670907514351827, + ]), + y_minus_x: FieldElement51::from_limbs([ + 359856369838236, + 180914355488683, + 861726472646627, + 218807937262986, + 575626773232501, + ]), + xy2d: FieldElement51::from_limbs([ + 755467689082474, + 909202735047934, + 730078068932500, + 936309075711518, + 2007798262842972, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1609384177904054, + 2614544999293875, + 1335318541768200, + 3052765584121496, + 2799677792952659, + ]), + y_minus_x: FieldElement51::from_limbs([ + 984339177776787, + 815727786505884, + 1645154585713747, + 1659074964378553, + 1686601651984156, + ]), + xy2d: FieldElement51::from_limbs([ + 1697863093781930, + 599794399429786, + 1104556219769607, + 830560774794755, + 12812858601017, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1168737550514982, + 897832437380552, + 463140296333799, + 2554364413707795, + 2008360505135500, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1856930662813910, + 678090852002597, + 1920179140755167, + 1259527833759868, + 55540971895511, + ]), + xy2d: FieldElement51::from_limbs([ + 1158643631044921, + 476554103621892, + 178447851439725, + 1305025542653569, + 103433927680625, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2176793111709008, + 3828525530035639, + 2009350167273522, + 2012390194631546, + 2125297410909580, + ]), + y_minus_x: FieldElement51::from_limbs([ + 825403285195098, + 2144208587560784, + 1925552004644643, + 1915177840006985, + 1015952128947864, + ]), + xy2d: FieldElement51::from_limbs([ + 1807108316634472, + 1534392066433717, + 347342975407218, + 1153820745616376, + 7375003497471, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3234860815484973, + 2683011703586488, + 2201903782961092, + 3069193724749589, + 2214616493042166, + ]), + y_minus_x: FieldElement51::from_limbs([ + 228567918409756, + 865093958780220, + 358083886450556, + 159617889659320, + 1360637926292598, + ]), + xy2d: FieldElement51::from_limbs([ + 234147501399755, + 2229469128637390, + 2175289352258889, + 1397401514549353, + 1885288963089922, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3363562226636810, + 2504649386192636, + 3300514047508588, + 2397910909286693, + 1237505378776769, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1113790697840279, + 1051167139966244, + 1045930658550944, + 2011366241542643, + 1686166824620755, + ]), + xy2d: FieldElement51::from_limbs([ + 1054097349305049, + 1872495070333352, + 182121071220717, + 1064378906787311, + 100273572924182, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3558210666856834, + 1627717417672446, + 2302783034773665, + 1109249951172249, + 3122001602766640, + ]), + y_minus_x: FieldElement51::from_limbs([ + 104233794644221, + 1548919791188248, + 2224541913267306, + 2054909377116478, + 1043803389015153, + ]), + xy2d: FieldElement51::from_limbs([ + 216762189468802, + 707284285441622, + 190678557969733, + 973969342604308, + 1403009538434867, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3530824104723725, + 2596576648903557, + 2525521909702446, + 4086000250496689, + 634517197663803, + ]), + y_minus_x: FieldElement51::from_limbs([ + 343805853118335, + 1302216857414201, + 566872543223541, + 2051138939539004, + 321428858384280, + ]), + xy2d: FieldElement51::from_limbs([ + 470067171324852, + 1618629234173951, + 2000092177515639, + 7307679772789, + 1117521120249968, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2529951391976704, + 1810282338562946, + 1771599529530998, + 3635459223356879, + 2937173228157088, + ]), + y_minus_x: FieldElement51::from_limbs([ + 577009397403102, + 1791440261786291, + 2177643735971638, + 174546149911960, + 1412505077782326, + ]), + xy2d: FieldElement51::from_limbs([ + 893719721537457, + 1201282458018197, + 1522349501711173, + 58011597740583, + 1130406465887139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 412607348255434, + 1280455764199780, + 2233277987330768, + 2265979894086913, + 2583384512102412, + ]), + y_minus_x: FieldElement51::from_limbs([ + 262483770854550, + 990511055108216, + 526885552771698, + 571664396646158, + 354086190278723, + ]), + xy2d: FieldElement51::from_limbs([ + 1820352417585487, + 24495617171480, + 1547899057533253, + 10041836186225, + 480457105094042, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2023310314989233, + 2889705151211129, + 2106474638900686, + 2809620524769320, + 1687858215057825, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1144168702609745, + 604444390410187, + 1544541121756138, + 1925315550126027, + 626401428894002, + ]), + xy2d: FieldElement51::from_limbs([ + 1922168257351784, + 2018674099908659, + 1776454117494445, + 956539191509034, + 36031129147635, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2796444352433270, + 1039872944430373, + 3128550222815858, + 2962457525011798, + 3468752501170219, + ]), + y_minus_x: FieldElement51::from_limbs([ + 58242421545916, + 2035812695641843, + 2118491866122923, + 1191684463816273, + 46921517454099, + ]), + xy2d: FieldElement51::from_limbs([ + 272268252444639, + 1374166457774292, + 2230115177009552, + 1053149803909880, + 1354288411641016, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1857910905368338, + 1754729879288912, + 3137745277795125, + 1516096106802165, + 1602902393369811, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1193437069800958, + 901107149704790, + 999672920611411, + 477584824802207, + 364239578697845, + ]), + xy2d: FieldElement51::from_limbs([ + 886299989548838, + 1538292895758047, + 1590564179491896, + 1944527126709657, + 837344427345298, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3006358179063534, + 1712186480903617, + 3955456640022779, + 3002110732175033, + 2770795853936147, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1309847803895382, + 1462151862813074, + 211370866671570, + 1544595152703681, + 1027691798954090, + ]), + xy2d: FieldElement51::from_limbs([ + 803217563745370, + 1884799722343599, + 1357706345069218, + 2244955901722095, + 730869460037413, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2941099284981214, + 1831210565161070, + 3626987155270686, + 3358084791231418, + 1893781834054268, + ]), + y_minus_x: FieldElement51::from_limbs([ + 696351368613042, + 1494385251239250, + 738037133616932, + 636385507851544, + 927483222611406, + ]), + xy2d: FieldElement51::from_limbs([ + 1949114198209333, + 1104419699537997, + 783495707664463, + 1747473107602770, + 2002634765788641, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1607325776830197, + 2782683755100581, + 1451089452727894, + 3833490970768671, + 496100432831153, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1068900648804224, + 2006891997072550, + 1134049269345549, + 1638760646180091, + 2055396084625778, + ]), + xy2d: FieldElement51::from_limbs([ + 2222475519314561, + 1870703901472013, + 1884051508440561, + 1344072275216753, + 1318025677799069, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 155711679280637, + 681100400509288, + 389811735211209, + 2135723811340709, + 2660533024889373, + ]), + y_minus_x: FieldElement51::from_limbs([ + 7813206966729, + 194444201427550, + 2071405409526507, + 1065605076176312, + 1645486789731291, + ]), + xy2d: FieldElement51::from_limbs([ + 16625790644959, + 1647648827778410, + 1579910185572704, + 436452271048548, + 121070048451050, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3289062842237779, + 2820185594063076, + 2549752917829677, + 3810384325616458, + 2238221839292470, + ]), + y_minus_x: FieldElement51::from_limbs([ + 190565267697443, + 672855706028058, + 338796554369226, + 337687268493904, + 853246848691734, + ]), + xy2d: FieldElement51::from_limbs([ + 1763863028400139, + 766498079432444, + 1321118624818005, + 69494294452268, + 858786744165651, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3543856582248253, + 1456632109855637, + 3352431060735432, + 1386133165675320, + 3484698163879000, + ]), + y_minus_x: FieldElement51::from_limbs([ + 366253102478259, + 525676242508811, + 1449610995265438, + 1183300845322183, + 185960306491545, + ]), + xy2d: FieldElement51::from_limbs([ + 28315355815982, + 460422265558930, + 1799675876678724, + 1969256312504498, + 1051823843138725, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2408714813047231, + 3857948219405196, + 1665208410108429, + 2569443092377519, + 1383783705665319, + ]), + y_minus_x: FieldElement51::from_limbs([ + 54684536365732, + 2210010038536222, + 1194984798155308, + 535239027773705, + 1516355079301361, + ]), + xy2d: FieldElement51::from_limbs([ + 1484387703771650, + 198537510937949, + 2186282186359116, + 617687444857508, + 647477376402122, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2147715541830533, + 2751832352131065, + 2898179830570073, + 2604027669016369, + 1488268620408051, + ]), + y_minus_x: FieldElement51::from_limbs([ + 159386186465542, + 1877626593362941, + 618737197060512, + 1026674284330807, + 1158121760792685, + ]), + xy2d: FieldElement51::from_limbs([ + 1744544377739822, + 1964054180355661, + 1685781755873170, + 2169740670377448, + 1286112621104591, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2333777063470241, + 3919742931398333, + 3920783633320113, + 1605016835177614, + 1353960708075544, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1602253788689063, + 439542044889886, + 2220348297664483, + 657877410752869, + 157451572512238, + ]), + xy2d: FieldElement51::from_limbs([ + 1029287186166717, + 65860128430192, + 525298368814832, + 1491902500801986, + 1461064796385400, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2660016802414475, + 2121095722306988, + 913562102267595, + 1879708920318308, + 2492861262121979, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1185483484383269, + 1356339572588553, + 584932367316448, + 102132779946470, + 1792922621116791, + ]), + xy2d: FieldElement51::from_limbs([ + 1966196870701923, + 2230044620318636, + 1425982460745905, + 261167817826569, + 46517743394330, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2358877405280588, + 3136759755857592, + 2279106683482647, + 2224911448949389, + 3216151871930471, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1730194207717538, + 431790042319772, + 1831515233279467, + 1372080552768581, + 1074513929381760, + ]), + xy2d: FieldElement51::from_limbs([ + 1450880638731607, + 1019861580989005, + 1229729455116861, + 1174945729836143, + 826083146840706, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1899935429242705, + 1602068751520477, + 940583196550370, + 2334230882739107, + 1540863155745695, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2136688454840028, + 2099509000964294, + 1690800495246475, + 1217643678575476, + 828720645084218, + ]), + xy2d: FieldElement51::from_limbs([ + 765548025667841, + 462473984016099, + 998061409979798, + 546353034089527, + 2212508972466858, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2298375097456408, + 3144370785258318, + 1281983193144089, + 1491520128287375, + 75847005908304, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1801436127943107, + 1734436817907890, + 1268728090345068, + 167003097070711, + 2233597765834956, + ]), + xy2d: FieldElement51::from_limbs([ + 1997562060465113, + 1048700225534011, + 7615603985628, + 1855310849546841, + 2242557647635213, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1161017320376250, + 2744424393854291, + 2169815802355236, + 3228296595417790, + 1770879511019628, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1357044908364776, + 729130645262438, + 1762469072918979, + 1365633616878458, + 181282906404941, + ]), + xy2d: FieldElement51::from_limbs([ + 1080413443139865, + 1155205815510486, + 1848782073549786, + 622566975152580, + 124965574467971, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1184526762066993, + 247622751762817, + 2943928830891604, + 3071818503097743, + 2188697339828084, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2020536369003019, + 202261491735136, + 1053169669150884, + 2056531979272544, + 778165514694311, + ]), + xy2d: FieldElement51::from_limbs([ + 237404399610207, + 1308324858405118, + 1229680749538400, + 720131409105291, + 1958958863624906, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2767383321724075, + 2269456792542436, + 1717918437373988, + 1568052070792483, + 2298775616809171, + ]), + y_minus_x: FieldElement51::from_limbs([ + 281527309158085, + 36970532401524, + 866906920877543, + 2222282602952734, + 1289598729589882, + ]), + xy2d: FieldElement51::from_limbs([ + 1278207464902042, + 494742455008756, + 1262082121427081, + 1577236621659884, + 1888786707293291, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 353042527954210, + 1830056151907359, + 1111731275799225, + 2426760769524072, + 404312815582674, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2064251142068628, + 1666421603389706, + 1419271365315441, + 468767774902855, + 191535130366583, + ]), + xy2d: FieldElement51::from_limbs([ + 1716987058588002, + 1859366439773457, + 1767194234188234, + 64476199777924, + 1117233614485261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3236091949205521, + 2386938060636506, + 2220652137473166, + 1722843421165029, + 2442282371698157, + ]), + y_minus_x: FieldElement51::from_limbs([ + 298845952651262, + 1166086588952562, + 1179896526238434, + 1347812759398693, + 1412945390096208, + ]), + xy2d: FieldElement51::from_limbs([ + 1143239552672925, + 906436640714209, + 2177000572812152, + 2075299936108548, + 325186347798433, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2972824668060020, + 2936287674948563, + 3625238557779406, + 2193186935276994, + 1387043709851261, + ]), + y_minus_x: FieldElement51::from_limbs([ + 418098668140962, + 715065997721283, + 1471916138376055, + 2168570337288357, + 937812682637044, + ]), + xy2d: FieldElement51::from_limbs([ + 1043584187226485, + 2143395746619356, + 2209558562919611, + 482427979307092, + 847556718384018, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1248731221520740, + 1465200936117687, + 2792603306395388, + 2304778448366139, + 2513234303861356, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1057329623869501, + 620334067429122, + 461700859268034, + 2012481616501857, + 297268569108938, + ]), + xy2d: FieldElement51::from_limbs([ + 1055352180870759, + 1553151421852298, + 1510903185371259, + 1470458349428097, + 1226259419062731, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3744788603986897, + 3042126439258578, + 3441906842094992, + 3641194565844440, + 3872208010289441, + ]), + y_minus_x: FieldElement51::from_limbs([ + 47000654413729, + 1004754424173864, + 1868044813557703, + 173236934059409, + 588771199737015, + ]), + xy2d: FieldElement51::from_limbs([ + 30498470091663, + 1082245510489825, + 576771653181956, + 806509986132686, + 1317634017056939, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2672107869436803, + 3745154677001249, + 2417006535213335, + 4136645508605033, + 2065456951573058, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1115636332012334, + 1854340990964155, + 83792697369514, + 1972177451994021, + 457455116057587, + ]), + xy2d: FieldElement51::from_limbs([ + 1698968457310898, + 1435137169051090, + 1083661677032510, + 938363267483709, + 340103887207182, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1995325341336555, + 911500251774648, + 2415810569088940, + 855378419194761, + 3825401211214090, + ]), + y_minus_x: FieldElement51::from_limbs([ + 241719380661528, + 310028521317150, + 1215881323380194, + 1408214976493624, + 2141142156467363, + ]), + xy2d: FieldElement51::from_limbs([ + 1315157046163473, + 727368447885818, + 1363466668108618, + 1668921439990361, + 1398483384337907, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2326829491984875, + 3267188020145720, + 1849729037055211, + 4191614430138232, + 2696204044080201, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2053597130993710, + 2024431685856332, + 2233550957004860, + 2012407275509545, + 872546993104440, + ]), + xy2d: FieldElement51::from_limbs([ + 1217269667678610, + 599909351968693, + 1390077048548598, + 1471879360694802, + 739586172317596, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3970118453066023, + 1560510726633957, + 3156262694845170, + 1418028351780051, + 2346204163137185, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2132502667405250, + 214379346175414, + 1502748313768060, + 1960071701057800, + 1353971822643138, + ]), + xy2d: FieldElement51::from_limbs([ + 319394212043702, + 2127459436033571, + 717646691535162, + 663366796076914, + 318459064945314, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2657789238608841, + 1960452633787082, + 2919148848086913, + 3744474074452359, + 1451061489880786, + ]), + y_minus_x: FieldElement51::from_limbs([ + 947085906234007, + 323284730494107, + 1485778563977200, + 728576821512394, + 901584347702286, + ]), + xy2d: FieldElement51::from_limbs([ + 1575783124125742, + 2126210792434375, + 1569430791264065, + 1402582372904727, + 1891780248341114, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3090232019245924, + 4249503325136911, + 3270591693593114, + 1662001808174330, + 2330127946643001, + ]), + y_minus_x: FieldElement51::from_limbs([ + 739152638255629, + 2074935399403557, + 505483666745895, + 1611883356514088, + 628654635394878, + ]), + xy2d: FieldElement51::from_limbs([ + 1822054032121349, + 643057948186973, + 7306757352712, + 577249257962099, + 284735863382083, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3618358370049178, + 1448606567552085, + 3730680834630016, + 2417602993041145, + 1115718458123497, + ]), + y_minus_x: FieldElement51::from_limbs([ + 204146226972102, + 1630511199034723, + 2215235214174763, + 174665910283542, + 956127674017216, + ]), + xy2d: FieldElement51::from_limbs([ + 1562934578796716, + 1070893489712745, + 11324610642270, + 958989751581897, + 2172552325473805, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1770564423056008, + 2987323445349813, + 1326060113795288, + 1509650369341127, + 2317692235267932, + ]), + y_minus_x: FieldElement51::from_limbs([ + 623682558650637, + 1337866509471512, + 990313350206649, + 1314236615762469, + 1164772974270275, + ]), + xy2d: FieldElement51::from_limbs([ + 223256821462517, + 723690150104139, + 1000261663630601, + 933280913953265, + 254872671543046, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1969087237026022, + 2876595539132372, + 1335555107635968, + 2069986355593023, + 3963899963027150, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1236103475266979, + 1837885883267218, + 1026072585230455, + 1025865513954973, + 1801964901432134, + ]), + xy2d: FieldElement51::from_limbs([ + 1115241013365517, + 1712251818829143, + 2148864332502771, + 2096001471438138, + 2235017246626125, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3551068012286861, + 2047148477845620, + 2165648650132450, + 1612539282026145, + 2765997725314138, + ]), + y_minus_x: FieldElement51::from_limbs([ + 118352772338543, + 1067608711804704, + 1434796676193498, + 1683240170548391, + 230866769907437, + ]), + xy2d: FieldElement51::from_limbs([ + 1850689576796636, + 1601590730430274, + 1139674615958142, + 1954384401440257, + 76039205311, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1723387471374172, + 3249101280723658, + 2785727448808904, + 2272728458379212, + 1756575222802512, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2146711623855116, + 503278928021499, + 625853062251406, + 1109121378393107, + 1033853809911861, + ]), + xy2d: FieldElement51::from_limbs([ + 571005965509422, + 2005213373292546, + 1016697270349626, + 56607856974274, + 914438579435146, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1346698876211176, + 2076651707527589, + 3336561384795453, + 2517134292513653, + 1068954492309670, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1769967932677654, + 1695893319756416, + 1151863389675920, + 1781042784397689, + 400287774418285, + ]), + xy2d: FieldElement51::from_limbs([ + 1851867764003121, + 403841933237558, + 820549523771987, + 761292590207581, + 1743735048551143, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 410915148140008, + 2107072311871739, + 3256167275561751, + 2351484709082008, + 1180818713503223, + ]), + y_minus_x: FieldElement51::from_limbs([ + 285945406881439, + 648174397347453, + 1098403762631981, + 1366547441102991, + 1505876883139217, + ]), + xy2d: FieldElement51::from_limbs([ + 672095903120153, + 1675918957959872, + 636236529315028, + 1569297300327696, + 2164144194785875, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1902708175321798, + 3287143344600686, + 1178560808893262, + 2552895497743394, + 1280977479761117, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1615357281742403, + 404257611616381, + 2160201349780978, + 1160947379188955, + 1578038619549541, + ]), + xy2d: FieldElement51::from_limbs([ + 2013087639791217, + 822734930507457, + 1785668418619014, + 1668650702946164, + 389450875221715, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2705718263383616, + 2358206633614248, + 2072540975937134, + 308588860670238, + 1304394580755385, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1295082798350326, + 2091844511495996, + 1851348972587817, + 3375039684596, + 789440738712837, + ]), + xy2d: FieldElement51::from_limbs([ + 2083069137186154, + 848523102004566, + 993982213589257, + 1405313299916317, + 1532824818698468, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3747761112537659, + 1397203457344778, + 4026750030752190, + 2391102557240943, + 2318403398028034, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1782411379088302, + 1096724939964781, + 27593390721418, + 542241850291353, + 1540337798439873, + ]), + xy2d: FieldElement51::from_limbs([ + 693543956581437, + 171507720360750, + 1557908942697227, + 1074697073443438, + 1104093109037196, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 345288228393400, + 3351443383432420, + 2386681722088990, + 1740551994106739, + 2500011992985018, + ]), + y_minus_x: FieldElement51::from_limbs([ + 231429562203065, + 1526290236421172, + 2021375064026423, + 1520954495658041, + 806337791525116, + ]), + xy2d: FieldElement51::from_limbs([ + 1079623667189886, + 872403650198613, + 766894200588288, + 2163700860774109, + 2023464507911816, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 854645372543796, + 1936406001954827, + 2403260476226501, + 3077125552956802, + 1554306377287555, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1497138821904622, + 1044820250515590, + 1742593886423484, + 1237204112746837, + 849047450816987, + ]), + xy2d: FieldElement51::from_limbs([ + 667962773375330, + 1897271816877105, + 1399712621683474, + 1143302161683099, + 2081798441209593, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2378947665252234, + 1936114012888109, + 1704424366552046, + 3108474694401560, + 2968403435020606, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1072409664800960, + 2146937497077528, + 1508780108920651, + 935767602384853, + 1112800433544068, + ]), + xy2d: FieldElement51::from_limbs([ + 333549023751292, + 280219272863308, + 2104176666454852, + 1036466864875785, + 536135186520207, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2625466093568366, + 2398257055215356, + 2555916080813104, + 2667888562832962, + 3510376944868638, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1186115062588401, + 2251609796968486, + 1098944457878953, + 1153112761201374, + 1791625503417267, + ]), + xy2d: FieldElement51::from_limbs([ + 1870078460219737, + 2129630962183380, + 852283639691142, + 292865602592851, + 401904317342226, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1361070124828016, + 815664541425524, + 3278598711049919, + 1951790935390646, + 2807674705520038, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1546301003424277, + 459094500062839, + 1097668518375311, + 1780297770129643, + 720763293687608, + ]), + xy2d: FieldElement51::from_limbs([ + 1212405311403990, + 1536693382542438, + 61028431067459, + 1863929423417129, + 1223219538638038, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1294303766540260, + 3435357279640341, + 3134071170918340, + 2315654383110622, + 2213283684565086, + ]), + y_minus_x: FieldElement51::from_limbs([ + 339050984211414, + 601386726509773, + 413735232134068, + 966191255137228, + 1839475899458159, + ]), + xy2d: FieldElement51::from_limbs([ + 235605972169408, + 2174055643032978, + 1538335001838863, + 1281866796917192, + 1815940222628465, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1632352921721536, + 1833328609514701, + 2092779091951987, + 4175756015558474, + 2210068022482918, + ]), + y_minus_x: FieldElement51::from_limbs([ + 35271216625062, + 1712350667021807, + 983664255668860, + 98571260373038, + 1232645608559836, + ]), + xy2d: FieldElement51::from_limbs([ + 1998172393429622, + 1798947921427073, + 784387737563581, + 1589352214827263, + 1589861734168180, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1733739258725305, + 2283515530744786, + 2453769758904107, + 3243892858242237, + 1194308773174555, + ]), + y_minus_x: FieldElement51::from_limbs([ + 846415389605137, + 746163495539180, + 829658752826080, + 592067705956946, + 957242537821393, + ]), + xy2d: FieldElement51::from_limbs([ + 1758148849754419, + 619249044817679, + 168089007997045, + 1371497636330523, + 1867101418880350, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2578433797894864, + 2513559319756263, + 1700682323676192, + 1577907266349064, + 3469447477068264, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1714182387328607, + 1477856482074168, + 574895689942184, + 2159118410227270, + 1555532449716575, + ]), + xy2d: FieldElement51::from_limbs([ + 853828206885131, + 998498946036955, + 1835887550391235, + 207627336608048, + 258363815956050, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2392941288336925, + 3488528558590503, + 2894901233585134, + 1646615130509172, + 1208239602291765, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1501663228068911, + 1354879465566912, + 1444432675498247, + 897812463852601, + 855062598754348, + ]), + xy2d: FieldElement51::from_limbs([ + 714380763546606, + 1032824444965790, + 1774073483745338, + 1063840874947367, + 1738680636537158, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1640635546696233, + 2884968766877360, + 2212651044092395, + 2282390772269100, + 2620315074574625, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1171650314802029, + 1567085444565577, + 1453660792008405, + 757914533009261, + 1619511342778196, + ]), + xy2d: FieldElement51::from_limbs([ + 420958967093237, + 971103481109486, + 2169549185607107, + 1301191633558497, + 1661514101014240, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3158923465503550, + 1332556122804145, + 4075855067109735, + 3619414031128206, + 1982558335973171, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1121533090144639, + 1021251337022187, + 110469995947421, + 1511059774758394, + 2110035908131662, + ]), + xy2d: FieldElement51::from_limbs([ + 303213233384524, + 2061932261128138, + 352862124777736, + 40828818670255, + 249879468482660, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 856559257852200, + 2760317478634258, + 3629993581580163, + 3975258940632376, + 1962275756614520, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1445691340537320, + 40614383122127, + 402104303144865, + 485134269878232, + 1659439323587426, + ]), + xy2d: FieldElement51::from_limbs([ + 20057458979482, + 1183363722525800, + 2140003847237215, + 2053873950687614, + 2112017736174909, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2228654250927986, + 3735391177100515, + 1368661293910955, + 3328311098862539, + 526650682059607, + ]), + y_minus_x: FieldElement51::from_limbs([ + 709481497028540, + 531682216165724, + 316963769431931, + 1814315888453765, + 258560242424104, + ]), + xy2d: FieldElement51::from_limbs([ + 1053447823660455, + 1955135194248683, + 1010900954918985, + 1182614026976701, + 1240051576966610, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1957943897155478, + 1788667368028035, + 2389492723714354, + 2252839333292309, + 3078204576998275, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1848942433095597, + 1582009882530495, + 1849292741020143, + 1068498323302788, + 2001402229799484, + ]), + xy2d: FieldElement51::from_limbs([ + 1528282417624269, + 2142492439828191, + 2179662545816034, + 362568973150328, + 1591374675250271, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2411826493119617, + 2484141002903963, + 2149181472355544, + 598041771119831, + 2435658815595421, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2013278155187349, + 662660471354454, + 793981225706267, + 411706605985744, + 804490933124791, + ]), + xy2d: FieldElement51::from_limbs([ + 2051892037280204, + 488391251096321, + 2230187337030708, + 930221970662692, + 679002758255210, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1530723630438670, + 875873929577927, + 2593359947955236, + 2701702933216000, + 1055551308214178, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1461835919309432, + 1955256480136428, + 180866187813063, + 1551979252664528, + 557743861963950, + ]), + xy2d: FieldElement51::from_limbs([ + 359179641731115, + 1324915145732949, + 902828372691474, + 294254275669987, + 1887036027752957, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 4295071423139571, + 2038225437857463, + 1317528426475850, + 1398989128982787, + 2027639881006861, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2072902725256516, + 312132452743412, + 309930885642209, + 996244312618453, + 1590501300352303, + ]), + xy2d: FieldElement51::from_limbs([ + 1397254305160710, + 695734355138021, + 2233992044438756, + 1776180593969996, + 1085588199351115, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2692366865016258, + 2506694600041928, + 2745669038615469, + 1556322069683365, + 3819256354004466, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1950722461391320, + 1907845598854797, + 1822757481635527, + 2121567704750244, + 73811931471221, + ]), + xy2d: FieldElement51::from_limbs([ + 387139307395758, + 2058036430315676, + 1220915649965325, + 1794832055328951, + 1230009312169328, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1765973779329498, + 2911143873132225, + 2271621715291913, + 3553728154996461, + 3368065817761132, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1127572801181483, + 1224743760571696, + 1276219889847274, + 1529738721702581, + 1589819666871853, + ]), + xy2d: FieldElement51::from_limbs([ + 2181229378964934, + 2190885205260020, + 1511536077659137, + 1246504208580490, + 668883326494241, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2689666469258543, + 2920826224880015, + 2333696811665585, + 523874406393177, + 2496851874620484, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1975438052228868, + 1071801519999806, + 594652299224319, + 1877697652668809, + 1489635366987285, + ]), + xy2d: FieldElement51::from_limbs([ + 958592545673770, + 233048016518599, + 851568750216589, + 567703851596087, + 1740300006094761, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2014540178270324, + 192672779514432, + 2465676996326778, + 2194819933853410, + 1716422829364835, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1540769606609725, + 2148289943846077, + 1597804156127445, + 1230603716683868, + 815423458809453, + ]), + xy2d: FieldElement51::from_limbs([ + 1738560251245018, + 1779576754536888, + 1783765347671392, + 1880170990446751, + 1088225159617541, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2911103727614740, + 1956447718227572, + 1830568515922666, + 3092868863429656, + 1669607124206367, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1143465490433355, + 1532194726196059, + 1093276745494697, + 481041706116088, + 2121405433561163, + ]), + xy2d: FieldElement51::from_limbs([ + 1686424298744462, + 1451806974487153, + 266296068846582, + 1834686947542675, + 1720762336132256, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3141016840074207, + 3295090436969907, + 3107924901237156, + 1669272323124635, + 1603340330827879, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1206396181488998, + 333158148435054, + 1402633492821422, + 1120091191722026, + 1945474114550509, + ]), + xy2d: FieldElement51::from_limbs([ + 766720088232571, + 1512222781191002, + 1189719893490790, + 2091302129467914, + 2141418006894941, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2671463460991841, + 1998875112167986, + 3678399683938955, + 3406728169064757, + 2738338345823434, + ]), + y_minus_x: FieldElement51::from_limbs([ + 938160078005954, + 1421776319053174, + 1941643234741774, + 180002183320818, + 1414380336750546, + ]), + xy2d: FieldElement51::from_limbs([ + 398001940109652, + 1577721237663248, + 1012748649830402, + 1540516006905144, + 1011684812884559, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1653276489969611, + 2257881638852872, + 1921777941170835, + 1604139841794531, + 3113010867325889, + ]), + y_minus_x: FieldElement51::from_limbs([ + 996661541407379, + 1455877387952927, + 744312806857277, + 139213896196746, + 1000282908547789, + ]), + xy2d: FieldElement51::from_limbs([ + 1450817495603008, + 1476865707053229, + 1030490562252053, + 620966950353376, + 1744760161539058, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2811528223687828, + 2288856475326432, + 2038622963352005, + 1637244893271723, + 3278365165924196, + ]), + y_minus_x: FieldElement51::from_limbs([ + 962165956135846, + 1116599660248791, + 182090178006815, + 1455605467021751, + 196053588803284, + ]), + xy2d: FieldElement51::from_limbs([ + 796863823080135, + 1897365583584155, + 420466939481601, + 2165972651724672, + 932177357788289, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 877047233620613, + 1375632631944375, + 2895573425567369, + 2911822552533124, + 2271153746017078, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2216943882299338, + 394841323190322, + 2222656898319671, + 558186553950529, + 1077236877025190, + ]), + xy2d: FieldElement51::from_limbs([ + 801118384953213, + 1914330175515892, + 574541023311511, + 1471123787903705, + 1526158900256288, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3201417702772463, + 2207116611267330, + 3164719852826535, + 2752958352884036, + 2314162374456719, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1474518386765335, + 1760793622169197, + 1157399790472736, + 1622864308058898, + 165428294422792, + ]), + xy2d: FieldElement51::from_limbs([ + 1961673048027128, + 102619413083113, + 1051982726768458, + 1603657989805485, + 1941613251499678, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1401939116319247, + 2587106153588320, + 2323846009771033, + 862423201496005, + 3102318568216632, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1234706593321979, + 1083343891215917, + 898273974314935, + 1640859118399498, + 157578398571149, + ]), + xy2d: FieldElement51::from_limbs([ + 1143483057726416, + 1992614991758919, + 674268662140796, + 1773370048077526, + 674318359920189, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1835401379538542, + 173900035308392, + 818247630716732, + 4013900225838034, + 1021506399448290, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1506632088156630, + 2127481795522179, + 513812919490255, + 140643715928370, + 442476620300318, + ]), + xy2d: FieldElement51::from_limbs([ + 2056683376856736, + 219094741662735, + 2193541883188309, + 1841182310235800, + 556477468664293, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3566819241596075, + 1049075855992602, + 4318372866671791, + 2518704280870781, + 2040482348591519, + ]), + y_minus_x: FieldElement51::from_limbs([ + 94096246544434, + 922482381166992, + 24517828745563, + 2139430508542503, + 2097139044231004, + ]), + xy2d: FieldElement51::from_limbs([ + 537697207950515, + 1399352016347350, + 1563663552106345, + 2148749520888918, + 549922092988516, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1747985413252415, + 680511052635695, + 1809559829982725, + 2846074064615302, + 2453472984431229, + ]), + y_minus_x: FieldElement51::from_limbs([ + 323583936109569, + 1973572998577657, + 1192219029966558, + 79354804385273, + 1374043025560347, + ]), + xy2d: FieldElement51::from_limbs([ + 213277331329947, + 416202017849623, + 1950535221091783, + 1313441578103244, + 2171386783823658, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2440888617915079, + 993969372859109, + 3147669935222235, + 3799101348983503, + 1477373024911349, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1620578418245010, + 541035331188469, + 2235785724453865, + 2154865809088198, + 1974627268751826, + ]), + xy2d: FieldElement51::from_limbs([ + 1346805451740245, + 1350981335690626, + 942744349501813, + 2155094562545502, + 1012483751693409, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2107080134091762, + 1132567062788208, + 1824935377687210, + 769194804343737, + 1857941799971888, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1074666112436467, + 249279386739593, + 1174337926625354, + 1559013532006480, + 1472287775519121, + ]), + xy2d: FieldElement51::from_limbs([ + 1872620123779532, + 1892932666768992, + 1921559078394978, + 1270573311796160, + 1438913646755037, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3089190001333428, + 3264053113908846, + 989780015893986, + 1351393287739814, + 2580427560230798, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1028328827183114, + 1711043289969857, + 1350832470374933, + 1923164689604327, + 1495656368846911, + ]), + xy2d: FieldElement51::from_limbs([ + 1900828492104143, + 430212361082163, + 687437570852799, + 832514536673512, + 1685641495940794, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3094432661621646, + 605670026766215, + 290836444839585, + 2415010588577604, + 2213815011799644, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1176336383453996, + 1725477294339771, + 12700622672454, + 678015708818208, + 162724078519879, + ]), + xy2d: FieldElement51::from_limbs([ + 1448049969043497, + 1789411762943521, + 385587766217753, + 90201620913498, + 832999441066823, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2767886146978542, + 2240508292484615, + 3603469341851756, + 3475055379001735, + 3002035638112385, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1263624896582495, + 1102602401673328, + 526302183714372, + 2152015839128799, + 1483839308490010, + ]), + xy2d: FieldElement51::from_limbs([ + 442991718646863, + 1599275157036458, + 1925389027579192, + 899514691371390, + 350263251085160, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1689713572022124, + 2845654372939621, + 3229894858477217, + 1985127338729498, + 3927868934032873, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1557207018622683, + 340631692799603, + 1477725909476187, + 614735951619419, + 2033237123746766, + ]), + xy2d: FieldElement51::from_limbs([ + 968764929340557, + 1225534776710944, + 662967304013036, + 1155521416178595, + 791142883466590, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1487081286167458, + 3244839255500182, + 1792378982844639, + 2950452258685122, + 2153908693179753, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1123181311102823, + 685575944875442, + 507605465509927, + 1412590462117473, + 568017325228626, + ]), + xy2d: FieldElement51::from_limbs([ + 560258797465417, + 2193971151466401, + 1824086900849026, + 579056363542056, + 1690063960036441, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1918407319222397, + 2605567366745211, + 1930426334528098, + 1564816146005724, + 4113142195393344, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2131325168777276, + 1176636658428908, + 1756922641512981, + 1390243617176012, + 1966325177038383, + ]), + xy2d: FieldElement51::from_limbs([ + 2063958120364491, + 2140267332393533, + 699896251574968, + 273268351312140, + 375580724713232, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2024297515263178, + 2668759143407935, + 3330814048702549, + 2423412039258430, + 1031677520051052, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2033900009388450, + 1744902869870788, + 2190580087917640, + 1949474984254121, + 231049754293748, + ]), + xy2d: FieldElement51::from_limbs([ + 343868674606581, + 550155864008088, + 1450580864229630, + 481603765195050, + 896972360018042, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2151139328380127, + 2566545695770176, + 2311556639460451, + 1676664391494650, + 2048348075599360, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1528930066340597, + 1605003907059576, + 1055061081337675, + 1458319101947665, + 1234195845213142, + ]), + xy2d: FieldElement51::from_limbs([ + 830430507734812, + 1780282976102377, + 1425386760709037, + 362399353095425, + 2168861579799910, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3407562046415562, + 980662895504005, + 2053766700883521, + 2742766027762854, + 2762205690726604, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1683750316716132, + 652278688286128, + 1221798761193539, + 1897360681476669, + 319658166027343, + ]), + xy2d: FieldElement51::from_limbs([ + 618808732869972, + 72755186759744, + 2060379135624181, + 1730731526741822, + 48862757828238, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3714971784278753, + 3394840525452699, + 614590986558882, + 1409210575145591, + 1882816996436803, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2230133264691131, + 563950955091024, + 2042915975426398, + 827314356293472, + 672028980152815, + ]), + xy2d: FieldElement51::from_limbs([ + 264204366029760, + 1654686424479449, + 2185050199932931, + 2207056159091748, + 506015669043634, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1784446333136550, + 1973746527984364, + 334856327359575, + 3408569589569858, + 3275749938360725, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2065270940578383, + 31477096270353, + 306421879113491, + 181958643936686, + 1907105536686083, + ]), + xy2d: FieldElement51::from_limbs([ + 1496516440779464, + 1748485652986458, + 872778352227340, + 818358834654919, + 97932669284220, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2723435829455580, + 2924255216478824, + 1804995246884102, + 1842309243470804, + 3753662318666930, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1013216974933691, + 538921919682598, + 1915776722521558, + 1742822441583877, + 1886550687916656, + ]), + xy2d: FieldElement51::from_limbs([ + 2094270000643336, + 303971879192276, + 40801275554748, + 649448917027930, + 1818544418535447, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2241737709499146, + 549397817447461, + 838180519319392, + 1725686958520781, + 3957438894582995, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1216074541925116, + 50120933933509, + 1565829004133810, + 721728156134580, + 349206064666188, + ]), + xy2d: FieldElement51::from_limbs([ + 948617110470858, + 346222547451945, + 1126511960599975, + 1759386906004538, + 493053284802266, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1454933046815146, + 3126495827951610, + 1467170975468587, + 1432316382418897, + 2111710746366763, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2105387117364450, + 1996463405126433, + 1303008614294500, + 851908115948209, + 1353742049788635, + ]), + xy2d: FieldElement51::from_limbs([ + 750300956351719, + 1487736556065813, + 15158817002104, + 1511998221598392, + 971739901354129, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1874648163531674, + 2124487685930551, + 1810030029384882, + 918400043048335, + 2838148440985898, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1235084464747900, + 1166111146432082, + 1745394857881591, + 1405516473883040, + 4463504151617, + ]), + xy2d: FieldElement51::from_limbs([ + 1663810156463827, + 327797390285791, + 1341846161759410, + 1964121122800605, + 1747470312055380, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 660005247548214, + 2071860029952887, + 3610548013635355, + 911703252219106, + 3266179736709079, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2206641276178231, + 1690587809721504, + 1600173622825126, + 2156096097634421, + 1106822408548216, + ]), + xy2d: FieldElement51::from_limbs([ + 1344788193552206, + 1949552134239140, + 1735915881729557, + 675891104100469, + 1834220014427292, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1920949492387945, + 2410685102072778, + 2322108077349280, + 2877838278583064, + 3719881539786256, + ]), + y_minus_x: FieldElement51::from_limbs([ + 622221042073383, + 1210146474039168, + 1742246422343683, + 1403839361379025, + 417189490895736, + ]), + xy2d: FieldElement51::from_limbs([ + 22727256592983, + 168471543384997, + 1324340989803650, + 1839310709638189, + 504999476432775, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3565040332441556, + 1721896294296941, + 2304063388272514, + 2065069734239231, + 3056710287109878, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1337466662091884, + 1287645354669772, + 2018019646776184, + 652181229374245, + 898011753211715, + ]), + xy2d: FieldElement51::from_limbs([ + 1969792547910734, + 779969968247557, + 2011350094423418, + 1823964252907487, + 1058949448296945, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2459143550747250, + 1118176942430252, + 3010694408233412, + 806764629546265, + 1157700123092949, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1273565321399022, + 1638509681964574, + 759235866488935, + 666015124346707, + 897983460943405, + ]), + xy2d: FieldElement51::from_limbs([ + 1717263794012298, + 1059601762860786, + 1837819172257618, + 1054130665797229, + 680893204263559, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2237039662793603, + 2249022333361206, + 2058613546633703, + 2401253908530527, + 2215176649164581, + ]), + y_minus_x: FieldElement51::from_limbs([ + 79472182719605, + 1851130257050174, + 1825744808933107, + 821667333481068, + 781795293511946, + ]), + xy2d: FieldElement51::from_limbs([ + 755822026485370, + 152464789723500, + 1178207602290608, + 410307889503239, + 156581253571278, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3669985309815545, + 2736319981413860, + 3898537095128197, + 3653287498355512, + 1349185550126960, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1495380034400429, + 325049476417173, + 46346894893933, + 1553408840354856, + 828980101835683, + ]), + xy2d: FieldElement51::from_limbs([ + 1280337889310282, + 2070832742866672, + 1640940617225222, + 2098284908289951, + 450929509534434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2659503167684029, + 2378371955168899, + 2537839641198868, + 1999255076709337, + 2030511179441770, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1254958221100483, + 1153235960999843, + 942907704968834, + 637105404087392, + 1149293270147267, + ]), + xy2d: FieldElement51::from_limbs([ + 894249020470196, + 400291701616810, + 406878712230981, + 1599128793487393, + 1145868722604026, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3749755063888563, + 2361916158338507, + 1128535642171975, + 1900106496009660, + 2381592531146157, + ]), + y_minus_x: FieldElement51::from_limbs([ + 452487513298665, + 1352120549024569, + 1173495883910956, + 1999111705922009, + 367328130454226, + ]), + xy2d: FieldElement51::from_limbs([ + 1717539401269642, + 1475188995688487, + 891921989653942, + 836824441505699, + 1885988485608364, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3493583935107776, + 2439136865632830, + 3370281625921440, + 2680547565621609, + 2282158712612572, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2022432361201842, + 1088816090685051, + 1977843398539868, + 1854834215890724, + 564238862029357, + ]), + xy2d: FieldElement51::from_limbs([ + 938868489100585, + 1100285072929025, + 1017806255688848, + 1957262154788833, + 152787950560442, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3119119231364171, + 2872271776627789, + 2477832016990963, + 2593801257642876, + 1761675818237335, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1295072362439987, + 931227904689414, + 1355731432641687, + 922235735834035, + 892227229410209, + ]), + xy2d: FieldElement51::from_limbs([ + 1680989767906154, + 535362787031440, + 2136691276706570, + 1942228485381244, + 1267350086882274, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2617818047455756, + 2684460443440843, + 2378209521329782, + 1973842949591661, + 2897427157127624, + ]), + y_minus_x: FieldElement51::from_limbs([ + 535509430575217, + 546885533737322, + 1524675609547799, + 2138095752851703, + 1260738089896827, + ]), + xy2d: FieldElement51::from_limbs([ + 1159906385590467, + 2198530004321610, + 714559485023225, + 81880727882151, + 1484020820037082, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1377485731340769, + 2046328105512000, + 1802058637158797, + 2313945950453421, + 1356993908853900, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2013612215646735, + 1830770575920375, + 536135310219832, + 609272325580394, + 270684344495013, + ]), + xy2d: FieldElement51::from_limbs([ + 1237542585982777, + 2228682050256790, + 1385281931622824, + 593183794882890, + 493654978552689, + ]), + }, + ]), + LookupTable([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2299141301692989, + 1891414891220256, + 983894663308928, + 2427961581972066, + 3378060928864955, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1694030170963455, + 502038567066200, + 1691160065225467, + 949628319562187, + 275110186693066, + ]), + xy2d: FieldElement51::from_limbs([ + 1124515748676336, + 1661673816593408, + 1499640319059718, + 1584929449166988, + 558148594103306, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1784525599998356, + 1619698033617383, + 2097300287550715, + 2510065271789004, + 1905684794832757, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1288941072872766, + 931787902039402, + 190731008859042, + 2006859954667190, + 1005931482221702, + ]), + xy2d: FieldElement51::from_limbs([ + 1465551264822703, + 152905080555927, + 680334307368453, + 173227184634745, + 666407097159852, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2111017076203943, + 3630560299479595, + 1248583954016455, + 3604089008549670, + 1895180776543895, + ]), + y_minus_x: FieldElement51::from_limbs([ + 171348223915638, + 662766099800389, + 462338943760497, + 466917763340314, + 656911292869115, + ]), + xy2d: FieldElement51::from_limbs([ + 488623681976577, + 866497561541722, + 1708105560937768, + 1673781214218839, + 1506146329818807, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2412225278142205, + 950394373239688, + 2682296937026182, + 711676555398831, + 320964687779005, + ]), + y_minus_x: FieldElement51::from_limbs([ + 988979367990485, + 1359729327576302, + 1301834257246029, + 294141160829308, + 29348272277475, + ]), + xy2d: FieldElement51::from_limbs([ + 1434382743317910, + 100082049942065, + 221102347892623, + 186982837860588, + 1305765053501834, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2205916462268190, + 2751663643476068, + 961960554686615, + 2409862576442233, + 1841471168298304, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1191737341426592, + 1847042034978363, + 1382213545049056, + 1039952395710448, + 788812858896859, + ]), + xy2d: FieldElement51::from_limbs([ + 1346965964571152, + 1291881610839830, + 2142916164336056, + 786821641205979, + 1571709146321039, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 787164375951248, + 2454669019058437, + 3608390234717387, + 1431233331032509, + 786341368775957, + ]), + y_minus_x: FieldElement51::from_limbs([ + 492448143532951, + 304105152670757, + 1761767168301056, + 233782684697790, + 1981295323106089, + ]), + xy2d: FieldElement51::from_limbs([ + 665807507761866, + 1343384868355425, + 895831046139653, + 439338948736892, + 1986828765695105, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3007896024559801, + 1721699973539148, + 2510565115413133, + 1390588532210644, + 1212530909934781, + ]), + y_minus_x: FieldElement51::from_limbs([ + 852891097972275, + 1816988871354562, + 1543772755726524, + 1174710635522444, + 202129090724628, + ]), + xy2d: FieldElement51::from_limbs([ + 1205281565824323, + 22430498399418, + 992947814485516, + 1392458699738672, + 688441466734558, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3302427242100220, + 1955849529137134, + 2171162376368357, + 2343545681983462, + 447733118757825, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1287181461435438, + 622722465530711, + 880952150571872, + 741035693459198, + 311565274989772, + ]), + xy2d: FieldElement51::from_limbs([ + 1003649078149734, + 545233927396469, + 1849786171789880, + 1318943684880434, + 280345687170552, + ]), + }, + ]), +]); + +/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. +#[cfg(feature = "precomputed-tables")] +#[allow(dead_code)] +pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = + NafLookupTable8([ + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3540182452943730, + 2497478415033846, + 2521227595762870, + 1462984067271729, + 2389212253076811, + ]), + y_minus_x: FieldElement51::from_limbs([ + 62697248952638, + 204681361388450, + 631292143396476, + 338455783676468, + 1213667448819585, + ]), + xy2d: FieldElement51::from_limbs([ + 301289933810280, + 1259582250014073, + 1422107436869536, + 796239922652654, + 1953934009299142, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1601611775252272, + 1720807796594148, + 1132070835939856, + 3512254832574799, + 2147779492816910, + ]), + y_minus_x: FieldElement51::from_limbs([ + 316559037616741, + 2177824224946892, + 1459442586438991, + 1461528397712656, + 751590696113597, + ]), + xy2d: FieldElement51::from_limbs([ + 1850748884277385, + 1200145853858453, + 1068094770532492, + 672251375690438, + 1586055907191707, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 769950342298400, + 2384754244604994, + 3095885746880802, + 3225892188161580, + 2977876099231263, + ]), + y_minus_x: FieldElement51::from_limbs([ + 425251763115706, + 608463272472562, + 442562545713235, + 837766094556764, + 374555092627893, + ]), + xy2d: FieldElement51::from_limbs([ + 1086255230780037, + 274979815921559, + 1960002765731872, + 929474102396301, + 1190409889297339, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2916800678241215, + 2065379846933858, + 2622030924071124, + 2602788184473875, + 1233371373142984, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2019367628972465, + 676711900706637, + 110710997811333, + 1108646842542025, + 517791959672113, + ]), + xy2d: FieldElement51::from_limbs([ + 965130719900578, + 247011430587952, + 526356006571389, + 91986625355052, + 2157223321444601, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1802695059464988, + 1664899123557221, + 2845359304426105, + 2160434469266658, + 3179370264440279, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1725674970513508, + 1933645953859181, + 1542344539275782, + 1767788773573747, + 1297447965928905, + ]), + xy2d: FieldElement51::from_limbs([ + 1381809363726107, + 1430341051343062, + 2061843536018959, + 1551778050872521, + 2036394857967624, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 4222693909998302, + 2779866139518454, + 1619374932191226, + 2207306624415883, + 1169170329061080, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2070390218572616, + 1458919061857835, + 624171843017421, + 1055332792707765, + 433987520732508, + ]), + xy2d: FieldElement51::from_limbs([ + 893653801273833, + 1168026499324677, + 1242553501121234, + 1306366254304474, + 1086752658510815, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2465253816303469, + 3191571337672685, + 1159882208056013, + 2569188183312765, + 621213314200686, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1971678598905747, + 338026507889165, + 762398079972271, + 655096486107477, + 42299032696322, + ]), + xy2d: FieldElement51::from_limbs([ + 177130678690680, + 1754759263300204, + 1864311296286618, + 1180675631479880, + 1292726903152791, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1913163449625248, + 2712579013977241, + 2193883288642313, + 1008900146920800, + 1721983679009502, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1070401523076875, + 1272492007800961, + 1910153608563310, + 2075579521696771, + 1191169788841221, + ]), + xy2d: FieldElement51::from_limbs([ + 692896803108118, + 500174642072499, + 2068223309439677, + 1162190621851337, + 1426986007309901, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1819621230288238, + 2735700366193240, + 1755134670739586, + 3080648199451191, + 4172807995775876, + ]), + y_minus_x: FieldElement51::from_limbs([ + 992069868904071, + 799011518185730, + 1777586403832768, + 1134820506145684, + 1999461475558530, + ]), + xy2d: FieldElement51::from_limbs([ + 425204543703124, + 2040469794090382, + 1651690622153809, + 1500530168597569, + 1253908377065966, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2105824306960939, + 1387520302709358, + 3633176580451016, + 2211816663841753, + 1629085891776489, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1485201376284999, + 1022406647424656, + 504181009209019, + 962621520820995, + 590876713147230, + ]), + xy2d: FieldElement51::from_limbs([ + 265873406365287, + 1192742653492898, + 88553098803050, + 525037770869640, + 1266933811251234, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3552316659826612, + 1254279525791875, + 1609927932077699, + 3578654071679972, + 3750681296069893, + ]), + y_minus_x: FieldElement51::from_limbs([ + 37186803519861, + 1404297334376301, + 578519728836650, + 1740727951192592, + 2095534282477028, + ]), + xy2d: FieldElement51::from_limbs([ + 833234263154399, + 2023862470013762, + 1854137933982069, + 853924318090959, + 1589812702805850, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3679150557957763, + 1319179453661745, + 497496853611112, + 2665464286942351, + 1208137952365560, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1654513078530905, + 907489875842908, + 126098711296368, + 1726320004173677, + 28269495058173, + ]), + xy2d: FieldElement51::from_limbs([ + 114436686957443, + 532739313025996, + 115428841215897, + 2191499400074366, + 370280402676434, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1111146849833253, + 2016430049079759, + 1860522747477948, + 3537164738290194, + 4137142824844184, + ]), + y_minus_x: FieldElement51::from_limbs([ + 429069864577128, + 975327637149449, + 237881983565075, + 1654761232378630, + 2122527599091807, + ]), + xy2d: FieldElement51::from_limbs([ + 2093793463548278, + 754827233241879, + 1420389751719629, + 1829952782588138, + 2011865756773717, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 676293365438898, + 2850296017886344, + 1205350322490195, + 2763699392265669, + 2133931188538142, + ]), + y_minus_x: FieldElement51::from_limbs([ + 48340340349120, + 1299261101494832, + 1137329686775218, + 1534848106674340, + 1351662218216799, + ]), + xy2d: FieldElement51::from_limbs([ + 1904520614137939, + 1590301001714014, + 215781420985270, + 2043534301034629, + 1970888949300424, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2365217962409710, + 2061307169694064, + 1887478590157603, + 2169639621284316, + 2373810867477200, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1020052624656948, + 1260412094216707, + 366721640607121, + 585331442306596, + 345876457758061, + ]), + xy2d: FieldElement51::from_limbs([ + 975390299880933, + 1066555195234642, + 12651997758352, + 1184252205433068, + 1058378155074223, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1431537716602643, + 2024827957433813, + 3746434518400495, + 1087794891033550, + 2156817571680455, + ]), + y_minus_x: FieldElement51::from_limbs([ + 929288033346881, + 255179964546973, + 711057989588035, + 208899572612840, + 185348357387383, + ]), + xy2d: FieldElement51::from_limbs([ + 823689746424808, + 47266130989546, + 209403309368097, + 1100966895202707, + 710792075292719, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2311213117823762, + 3296668540922318, + 2004276520649823, + 1861500579441125, + 3148029033359833, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1563693677475261, + 1843782073741194, + 1950700654453170, + 911540858113949, + 2085151496302359, + ]), + xy2d: FieldElement51::from_limbs([ + 1427880892005482, + 106216431121745, + 42608394782284, + 1217295886989793, + 1514235272796882, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3544335535746750, + 2367994491347456, + 2567261456502612, + 1854058085060971, + 2263545563461076, + ]), + y_minus_x: FieldElement51::from_limbs([ + 787426011300053, + 2105981035769060, + 1130476291127206, + 1748659348100075, + 53470983013756, + ]), + xy2d: FieldElement51::from_limbs([ + 553548273865386, + 5927805718390, + 65184587381926, + 633576679686953, + 576048559439973, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 993787326657446, + 3868807161609258, + 1615796046728943, + 2514644292681953, + 2059021068660907, + ]), + y_minus_x: FieldElement51::from_limbs([ + 251010270518880, + 1681684095763484, + 1521949356387564, + 431593457045116, + 1855308922422910, + ]), + xy2d: FieldElement51::from_limbs([ + 618490909691959, + 1257497595618257, + 202952467594088, + 35577762721238, + 1494883566841973, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1673474571932262, + 2409784519770613, + 2636095316260487, + 2761112584601925, + 3333713288149876, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1600640202645197, + 1019569075331823, + 1041916487915822, + 1680448171313267, + 2126903137527901, + ]), + xy2d: FieldElement51::from_limbs([ + 894964745143659, + 106116880092678, + 1009869382959477, + 317866368542032, + 1986983122763912, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1765281781276487, + 2863247187455184, + 2589075472439062, + 1386435905543054, + 2182338478845320, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1144730936996693, + 2213315231278180, + 1489676672185125, + 665039429138074, + 1131283313040268, + ]), + xy2d: FieldElement51::from_limbs([ + 2004734176670602, + 1738311085075235, + 418866995976618, + 1050782508034394, + 577747313404652, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2185209688340293, + 1309276076461009, + 2514740038571278, + 3994889904012999, + 3018098826231021, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1405936970888515, + 1754621155316654, + 1211862168554999, + 1813045702919083, + 997853418197172, + ]), + xy2d: FieldElement51::from_limbs([ + 82037622045021, + 1646398333621944, + 613095452763466, + 1312329542583705, + 81014679202721, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2389287991277873, + 403851022333257, + 1597473361477193, + 2953351602509212, + 2135174663049062, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1826548187201150, + 302299893734126, + 1475477168615781, + 842617616347376, + 1438600873676130, + ]), + xy2d: FieldElement51::from_limbs([ + 663049852468609, + 1649295727846569, + 1048009692742781, + 628866177992421, + 1914360327429204, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1795645928096646, + 306878154408959, + 2924901319092394, + 2801261341654799, + 1653782432983523, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2077597317438627, + 212642017882064, + 674844477518888, + 875487498687554, + 2060550250171182, + ]), + xy2d: FieldElement51::from_limbs([ + 1420448018683809, + 1032663994771382, + 1341927003385267, + 1340360916546159, + 1988547473895228, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1082660122598844, + 2545055705583789, + 3888919679589007, + 1670283344995811, + 3403239134794618, + ]), + y_minus_x: FieldElement51::from_limbs([ + 90430593339788, + 1838338032241275, + 571293238480915, + 1639938867416883, + 257378872001111, + ]), + xy2d: FieldElement51::from_limbs([ + 1528535658865034, + 1516636853043960, + 787000569996728, + 1464531394704506, + 1684822625133795, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 811329918113934, + 2783463529007378, + 1769095754634835, + 2970819621866866, + 881037178164325, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1784566501964517, + 433890943689325, + 1186055625589419, + 1496077405487512, + 1731807117886548, + ]), + xy2d: FieldElement51::from_limbs([ + 424909811816304, + 1355993963741797, + 409606483251841, + 455665350637068, + 1617009023642808, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2478728492077816, + 2780289048655501, + 2328687177473769, + 4107341333582032, + 1316147724308250, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1617420574301156, + 1741273341070467, + 667135503486508, + 2100436564640123, + 1032223920000865, + ]), + xy2d: FieldElement51::from_limbs([ + 1753947659404033, + 247279202390193, + 1819288880178945, + 737334285670249, + 1037873664856104, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1762568490530034, + 673742465299012, + 2054571050635888, + 2040165159255111, + 3040123733327257, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1627187989987422, + 1686331580821752, + 1309895873498183, + 719718719104086, + 300063199808722, + ]), + xy2d: FieldElement51::from_limbs([ + 238176707016164, + 1440454788877048, + 203336037573144, + 1437789888677072, + 101522256664211, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1895216760098480, + 1934324337975022, + 3677350688973167, + 2536415965456176, + 714678003308640, + ]), + y_minus_x: FieldElement51::from_limbs([ + 508185358728815, + 1691320535341855, + 2168887448239256, + 1035124393070661, + 1936603999698584, + ]), + xy2d: FieldElement51::from_limbs([ + 390562831571647, + 1390223890708972, + 1383183990676371, + 435998174196410, + 1882086414390730, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3747620842612921, + 2081794785291195, + 3284594056262745, + 2090090346797895, + 2581692978935809, + ]), + y_minus_x: FieldElement51::from_limbs([ + 244144781251265, + 1290834426417077, + 1888701171101942, + 1233922456644870, + 241117402207491, + ]), + xy2d: FieldElement51::from_limbs([ + 1266169390045455, + 1148042013187970, + 878921907853942, + 1815738019658093, + 908920199341621, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2521768507305118, + 953557056811112, + 2015863732865770, + 1358382511861315, + 2835421647899992, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2239837206240498, + 330928973149665, + 422268062913642, + 1481280019493032, + 619879520439841, + ]), + xy2d: FieldElement51::from_limbs([ + 1360166735366017, + 1770556573948510, + 1395061284191031, + 1814003148068126, + 522781147076884, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2611794802645686, + 707234844948070, + 1314059396506491, + 2919250341703934, + 2161831667832785, + ]), + y_minus_x: FieldElement51::from_limbs([ + 934831784182383, + 433734253968318, + 1660867106725771, + 1968393082772831, + 873946300968490, + ]), + xy2d: FieldElement51::from_limbs([ + 26306827827554, + 430884999378685, + 1504310424376419, + 1761358720837522, + 542195685418530, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1762131062631725, + 3123952634417535, + 3619918390837537, + 2909990877347294, + 1411594230004385, + ]), + y_minus_x: FieldElement51::from_limbs([ + 538272372224622, + 1425714779586199, + 588313661410172, + 1497062084392578, + 1602174047128512, + ]), + xy2d: FieldElement51::from_limbs([ + 907490361939255, + 1963620338391363, + 626927432296975, + 1250748516081414, + 959901171882527, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1335066153744413, + 2887804660779657, + 2653073855954038, + 2765226981667422, + 938831784476763, + ]), + y_minus_x: FieldElement51::from_limbs([ + 296699434737224, + 2047543711075683, + 2076451038937139, + 227783599906901, + 1602062110967627, + ]), + xy2d: FieldElement51::from_limbs([ + 1574834773194203, + 1384279952062839, + 393652417255803, + 2166968242848859, + 1552890441390820, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1619646774410947, + 1576090644023562, + 3035228391320965, + 1735328519940543, + 2355324535937066, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1024074573633446, + 957088456885874, + 1690425531356997, + 2102187380180052, + 1082544623222033, + ]), + xy2d: FieldElement51::from_limbs([ + 1871906170635853, + 1719383891167200, + 1584032250247862, + 823764804192117, + 2244048510084261, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 642147846489775, + 3334304977145699, + 305205716788147, + 2589176626729533, + 2224680511484174, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1734162377166545, + 260713621840346, + 157174591942595, + 952544272517991, + 222818702471733, + ]), + xy2d: FieldElement51::from_limbs([ + 1213115494182947, + 286778704335711, + 2130189536016490, + 308349182281342, + 1217623948685491, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3360052266973635, + 1843486583624091, + 1561693837124349, + 1084041964025479, + 1866270922024009, + ]), + y_minus_x: FieldElement51::from_limbs([ + 460705465481210, + 1968151453817859, + 497005926994844, + 625618055866751, + 2176893440866887, + ]), + xy2d: FieldElement51::from_limbs([ + 1655800250476757, + 2036588542300609, + 666447448675243, + 1615721995750683, + 1508669225186765, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2245948203759141, + 1058306669699396, + 1452898014240582, + 3961024141962768, + 1633235287338608, + ]), + y_minus_x: FieldElement51::from_limbs([ + 986647273684279, + 1507266907811370, + 1260572633649005, + 2071672342077446, + 695976026010857, + ]), + xy2d: FieldElement51::from_limbs([ + 1312356620823495, + 1635278548098567, + 901946076841033, + 585120475533168, + 1240667113237384, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2313723935779695, + 1506054666773895, + 996040223525031, + 636592914999692, + 1497801917020297, + ]), + y_minus_x: FieldElement51::from_limbs([ + 292042016419794, + 1158932298133044, + 2062611870323738, + 1946058478962569, + 1749165808126286, + ]), + xy2d: FieldElement51::from_limbs([ + 654683942212830, + 1526897351349087, + 2006818439922838, + 2194919327350361, + 1451960776874416, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3015041017808905, + 2951823141773809, + 2584865668253675, + 2508192032998563, + 2582137700042019, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1628123495344283, + 2072923641214546, + 1647225812023982, + 855655925244679, + 1758126430071140, + ]), + xy2d: FieldElement51::from_limbs([ + 1615895096489599, + 275295258643784, + 937665541219916, + 1313496726746346, + 1186468946422626, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1603070202850694, + 2072127623773242, + 1692648737212158, + 2493373404187852, + 1248948672117105, + ]), + y_minus_x: FieldElement51::from_limbs([ + 11167836031898, + 596565174397990, + 2196351068723859, + 314744641791907, + 1102014997250781, + ]), + xy2d: FieldElement51::from_limbs([ + 1409047922401191, + 69960384467966, + 688103515547600, + 1309746102488044, + 150292892873778, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1986083055103168, + 691715819340300, + 1361811659746933, + 3459052030333434, + 1063594696046061, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1201987338414749, + 2198784582460616, + 1203335513981498, + 489243077045066, + 2205278143582433, + ]), + xy2d: FieldElement51::from_limbs([ + 2034744376624534, + 2077387101466387, + 148448542974969, + 1502697574577258, + 473186584705655, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 472016956315960, + 720786972252993, + 2840633661190043, + 3150798753357827, + 2816563335499153, + ]), + y_minus_x: FieldElement51::from_limbs([ + 253464247569755, + 168314237403057, + 511780806170295, + 1058862316549135, + 1646858476817137, + ]), + xy2d: FieldElement51::from_limbs([ + 595092995922219, + 1491311840717691, + 291581784452778, + 1569186646367854, + 1031385061400544, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3483137021572755, + 1526955102024322, + 2778006642704458, + 457549634924205, + 1097420237736736, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1246991699537710, + 81367319519439, + 530844036072196, + 163656863755855, + 1950742455979290, + ]), + xy2d: FieldElement51::from_limbs([ + 191532664076407, + 539378506082089, + 1021612562876554, + 1026603384732632, + 1773368780410653, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 4144620731387879, + 590179521333342, + 4034023318016108, + 2255745030335426, + 2699746851701250, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2206599697359952, + 553895797384417, + 181689161933786, + 1153123447919104, + 778568064152659, + ]), + xy2d: FieldElement51::from_limbs([ + 1706307000059211, + 1885601289314487, + 889758608505788, + 550131729999853, + 1006862664714268, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3210197754285058, + 2048500453422630, + 3403309827888207, + 927154428508963, + 4199813798872019, + ]), + y_minus_x: FieldElement51::from_limbs([ + 992058915374933, + 476120535358775, + 1973648780784340, + 2025282643598818, + 2182318983793230, + ]), + xy2d: FieldElement51::from_limbs([ + 1343440812005821, + 1316045839091795, + 1884951299078063, + 1765919609219175, + 2197567554627988, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3129247779382818, + 4415026969054274, + 1900265885969643, + 1528796215447059, + 2172730393748688, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1773355092297603, + 64654329538271, + 1332124041660957, + 748492100858001, + 895500006200535, + ]), + xy2d: FieldElement51::from_limbs([ + 2000840647851980, + 546565968824914, + 420633283457524, + 195470736374507, + 1958689297569520, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 743138980705446, + 3411117504637167, + 2591389959690621, + 2380042066577202, + 3022267940115114, + ]), + y_minus_x: FieldElement51::from_limbs([ + 165947002229363, + 115186103724967, + 1068573292121517, + 1842565776920938, + 1969395681111987, + ]), + xy2d: FieldElement51::from_limbs([ + 553322266190633, + 234265665613185, + 484544650202821, + 1238773526575826, + 2017991917953668, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2581954631514051, + 1245093644265357, + 3537016673825374, + 1834216551713857, + 923978372152807, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1855378315339552, + 890045579230758, + 1764718173975590, + 197904186055854, + 1718129022310327, + ]), + xy2d: FieldElement51::from_limbs([ + 1278162928734862, + 1894118254109862, + 987503995465517, + 177406744098996, + 781538103127693, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1996603431230215, + 1191888797552937, + 1207440075928499, + 2765853449051137, + 2525314961343288, + ]), + y_minus_x: FieldElement51::from_limbs([ + 808903879370889, + 990820108751280, + 1084429472258867, + 1078562781312589, + 254514692695625, + ]), + xy2d: FieldElement51::from_limbs([ + 615855140068469, + 586046731175395, + 693470779212674, + 1964537100203868, + 1350330550265229, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3344544372023708, + 720386671449874, + 2480841360702110, + 2036034126860286, + 2015744690201389, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1337446193390478, + 1984110761311871, + 746489405020285, + 407347127604128, + 1740475330360596, + ]), + xy2d: FieldElement51::from_limbs([ + 140840424783613, + 1063284623568331, + 1136446106453878, + 372042229029799, + 442607248430694, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2330781679120937, + 376801425148230, + 2032603686676107, + 1488926293635130, + 1317278311532959, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1290116731380016, + 2166899563471713, + 831997001838078, + 870954980505220, + 2108537278055823, + ]), + xy2d: FieldElement51::from_limbs([ + 1912719171026343, + 846194720551034, + 2043988124740726, + 993234269653961, + 421229796383281, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2651184584992902, + 2775702557638963, + 2539786009779572, + 2575974880015305, + 2122619079836732, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1154054290132562, + 931753998725577, + 1647742001778052, + 865765466488226, + 1083816107290025, + ]), + xy2d: FieldElement51::from_limbs([ + 986341121095108, + 1522330369638573, + 1990880546211047, + 501525962272123, + 198539304862139, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1496414019192687, + 3991034436173951, + 3380311659062196, + 2854747485359158, + 3346958036643152, + ]), + y_minus_x: FieldElement51::from_limbs([ + 805612068303425, + 1891790027761335, + 1587008567571549, + 722120737390201, + 378156757163816, + ]), + xy2d: FieldElement51::from_limbs([ + 1588994517921951, + 977362751042302, + 1329302387067714, + 2069348224564088, + 1586007159625211, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2490539421551682, + 1985699850375015, + 2331762317128172, + 4145097393776678, + 2521049460190674, + ]), + y_minus_x: FieldElement51::from_limbs([ + 615817553313996, + 2245962768078178, + 482564324326173, + 2101336843140780, + 1240914880829407, + ]), + xy2d: FieldElement51::from_limbs([ + 1438242482238189, + 874267817785463, + 1620810389770625, + 866155221338671, + 1040426546798301, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 2403083624110300, + 2548561409802975, + 2492699136535911, + 2358289519456539, + 3203964320363148, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1913986535403097, + 1977163223054199, + 1972905914623196, + 1650122133472502, + 1905849310819035, + ]), + xy2d: FieldElement51::from_limbs([ + 858174816360838, + 614595356564037, + 1099584959044836, + 636998087084906, + 1070393269058348, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3666695924830668, + 3585640662737501, + 2372994528684236, + 2628565977288995, + 3482812783469694, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1994161359147952, + 2198039369802658, + 62790022842537, + 1522306785848169, + 951223194802833, + ]), + xy2d: FieldElement51::from_limbs([ + 852296621440717, + 431889737774209, + 370755457746189, + 437604073958073, + 627857326892757, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1794955764684156, + 2586904290013612, + 1322647643615887, + 856117964085888, + 2652432778663153, + ]), + y_minus_x: FieldElement51::from_limbs([ + 933592377399646, + 78031722952813, + 926049890685253, + 1471649501316246, + 33789909190376, + ]), + xy2d: FieldElement51::from_limbs([ + 1479319468832059, + 203906207621608, + 659828362330083, + 44358398435755, + 1273573524210803, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1592342143350813, + 3227219208247713, + 2345240352078765, + 2577750109932929, + 2933512841197243, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2184946892642995, + 1517382324576002, + 1557940277419806, + 2170635134813213, + 747314658627002, + ]), + xy2d: FieldElement51::from_limbs([ + 1823193620577742, + 1135817878516419, + 1731253819308581, + 1031652967267804, + 2123506616999453, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1346190246005805, + 2052692552023851, + 1718128041785940, + 2491557332978474, + 3474370880388305, + ]), + y_minus_x: FieldElement51::from_limbs([ + 424776012994573, + 281050757243423, + 626466040846420, + 990194703866532, + 38571969885982, + ]), + xy2d: FieldElement51::from_limbs([ + 192408346595466, + 1054889725292349, + 584097975693004, + 1447909807397749, + 2134645004369136, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3169895788615063, + 3503097743181446, + 601598510029975, + 1422812237223371, + 2121009661378329, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1603348391996783, + 2066143816131699, + 1789627290363958, + 2145705961178118, + 1985578641438222, + ]), + xy2d: FieldElement51::from_limbs([ + 352633958653380, + 856927627345554, + 793925083122702, + 93551575767286, + 1222010153634215, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1756866499986349, + 911731956999969, + 2707505543214075, + 4006920335263786, + 822501008147910, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1094036422864347, + 1897208881572508, + 1503607738246960, + 1901060196071406, + 294068411105729, + ]), + xy2d: FieldElement51::from_limbs([ + 587776484399576, + 1116861711228807, + 343398777436088, + 936544065763093, + 1643746750211060, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 3477749685790410, + 267997399528836, + 2953780922004404, + 3252368924080907, + 3787792887348381, + ]), + y_minus_x: FieldElement51::from_limbs([ + 2042368155872443, + 41662387210459, + 1676313264498480, + 1333968523426810, + 1765708383352310, + ]), + xy2d: FieldElement51::from_limbs([ + 1453394896690938, + 1585795827439909, + 1469309456804303, + 1294645324464404, + 2042954198665899, + ]), + }, + AffineNielsPoint { + y_plus_x: FieldElement51::from_limbs([ + 1810069207599881, + 1358344669503239, + 1989371257548167, + 2316270051121225, + 3019675451276507, + ]), + y_minus_x: FieldElement51::from_limbs([ + 1866114438287676, + 1663420339568364, + 1437691317033088, + 538298302628038, + 1212711449614363, + ]), + xy2d: FieldElement51::from_limbs([ + 1769235035677897, + 1562012115317882, + 31277513664750, + 536198657928416, + 1976134212537183, + ]), + }, + ]); diff --git a/src/backend/serial/u64/field.rs b/curve25519-dalek/src/backend/serial/u64/field.rs similarity index 82% rename from src/backend/serial/u64/field.rs rename to curve25519-dalek/src/backend/serial/u64/field.rs index a73d4b5d5..1263d23e4 100644 --- a/src/backend/serial/u64/field.rs +++ b/curve25519-dalek/src/backend/serial/u64/field.rs @@ -21,6 +21,7 @@ use core::ops::{Sub, SubAssign}; use subtle::Choice; use subtle::ConditionallySelectable; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; /// A `FieldElement51` represents an element of the field @@ -39,14 +40,15 @@ use zeroize::Zeroize; /// The backend-specific type `FieldElement51` should not be used /// outside of the `curve25519_dalek::field` module. #[derive(Copy, Clone)] -pub struct FieldElement51(pub (crate) [u64; 5]); +pub struct FieldElement51(pub(crate) [u64; 5]); impl Debug for FieldElement51 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "FieldElement51({:?})", &self.0[..]) } } +#[cfg(feature = "zeroize")] impl Zeroize for FieldElement51 { fn zeroize(&mut self) { self.0.zeroize(); @@ -108,6 +110,8 @@ impl<'b> MulAssign<&'b FieldElement51> for FieldElement51 { impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { type Output = FieldElement51; + + #[rustfmt::skip] // keep alignment of c* calculations fn mul(self, _rhs: &'b FieldElement51) -> FieldElement51 { /// Helper function to multiply two 64-bit integers with 128 /// bits of output. @@ -137,11 +141,11 @@ impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { let b4_19 = b[4] * 19; // Multiply to get 128-bit coefficients of output - let c0: u128 = m(a[0],b[0]) + m(a[4],b1_19) + m(a[3],b2_19) + m(a[2],b3_19) + m(a[1],b4_19); - let mut c1: u128 = m(a[1],b[0]) + m(a[0],b[1]) + m(a[4],b2_19) + m(a[3],b3_19) + m(a[2],b4_19); - let mut c2: u128 = m(a[2],b[0]) + m(a[1],b[1]) + m(a[0],b[2]) + m(a[4],b3_19) + m(a[3],b4_19); - let mut c3: u128 = m(a[3],b[0]) + m(a[2],b[1]) + m(a[1],b[2]) + m(a[0],b[3]) + m(a[4],b4_19); - let mut c4: u128 = m(a[4],b[0]) + m(a[3],b[1]) + m(a[2],b[2]) + m(a[1],b[3]) + m(a[0],b[4]); + let c0: u128 = m(a[0], b[0]) + m(a[4], b1_19) + m(a[3], b2_19) + m(a[2], b3_19) + m(a[1], b4_19); + let mut c1: u128 = m(a[1], b[0]) + m(a[0], b[1]) + m(a[4], b2_19) + m(a[3], b3_19) + m(a[2], b4_19); + let mut c2: u128 = m(a[2], b[0]) + m(a[1], b[1]) + m(a[0], b[2]) + m(a[4], b3_19) + m(a[3], b4_19); + let mut c3: u128 = m(a[3], b[0]) + m(a[2], b[1]) + m(a[1], b[2]) + m(a[0], b[3]) + m(a[4], b4_19); + let mut c4: u128 = m(a[4], b[0]) + m(a[3], b[1]) + m(a[2], b[2]) + m(a[1], b[3]) + m(a[0] , b[4]); // How big are the c[i]? We have // @@ -198,7 +202,7 @@ impl<'a, 'b> Mul<&'b FieldElement51> for &'a FieldElement51 { // out[0] + carry * 19 < 2^51 + 19 * 2^59.33 < 2^63.58 // // and there is no overflow. - out[0] = out[0] + carry * 19; + out[0] += carry * 19; // Now out[1] < 2^51 + 2^(64 -51) = 2^51 + 2^13 < 2^(51 + epsilon). out[1] += out[0] >> 51; @@ -251,6 +255,23 @@ impl ConditionallySelectable for FieldElement51 { } impl FieldElement51 { + pub(crate) const fn from_limbs(limbs: [u64; 5]) -> FieldElement51 { + FieldElement51(limbs) + } + + /// The scalar \\( 0 \\). + pub const ZERO: FieldElement51 = FieldElement51::from_limbs([0, 0, 0, 0, 0]); + /// The scalar \\( 1 \\). + pub const ONE: FieldElement51 = FieldElement51::from_limbs([1, 0, 0, 0, 0]); + /// The scalar \\( -1 \\). + pub const MINUS_ONE: FieldElement51 = FieldElement51::from_limbs([ + 2251799813685228, + 2251799813685247, + 2251799813685247, + 2251799813685247, + 2251799813685247, + ]); + /// Invert the sign of this field element pub fn negate(&mut self) { // See commentary in the Sub impl @@ -264,21 +285,6 @@ impl FieldElement51 { self.0 = neg.0; } - /// Construct zero. - pub fn zero() -> FieldElement51 { - FieldElement51([ 0, 0, 0, 0, 0 ]) - } - - /// Construct one. - pub fn one() -> FieldElement51 { - FieldElement51([ 1, 0, 0, 0, 0 ]) - } - - /// Construct -1. - pub fn minus_one() -> FieldElement51 { - FieldElement51([2251799813685228, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247]) - } - /// Given 64-bit input limbs, reduce to enforce the bound 2^(51 + epsilon). #[inline(always)] fn reduce(mut limbs: [u64; 5]) -> FieldElement51 { @@ -328,6 +334,7 @@ impl FieldElement51 { /// the canonical encoding, and check that the input was /// canonical. /// + #[rustfmt::skip] // keep alignment of bit shifts pub fn from_bytes(bytes: &[u8; 32]) -> FieldElement51 { let load8 = |input: &[u8]| -> u64 { (input[0] as u64) @@ -357,7 +364,8 @@ impl FieldElement51 { /// Serialize this `FieldElement51` to a 32-byte array. The /// encoding is canonical. - pub fn to_bytes(&self) -> [u8; 32] { + #[rustfmt::skip] // keep alignment of s[*] calculations + pub fn as_bytes(&self) -> [u8; 32] { // Let h = limbs[0] + limbs[1]*2^51 + ... + limbs[4]*2^204. // // Write h = pq + r with 0 <= r < p. @@ -384,56 +392,56 @@ impl FieldElement51 { // Now we can compute r as r = h - pq = r - (2^255-19)q = r + 19q - 2^255q - limbs[0] += 19*q; + limbs[0] += 19 * q; // Now carry the result to compute r + 19q ... let low_51_bit_mask = (1u64 << 51) - 1; - limbs[1] += limbs[0] >> 51; - limbs[0] = limbs[0] & low_51_bit_mask; - limbs[2] += limbs[1] >> 51; - limbs[1] = limbs[1] & low_51_bit_mask; - limbs[3] += limbs[2] >> 51; - limbs[2] = limbs[2] & low_51_bit_mask; - limbs[4] += limbs[3] >> 51; - limbs[3] = limbs[3] & low_51_bit_mask; + limbs[1] += limbs[0] >> 51; + limbs[0] &= low_51_bit_mask; + limbs[2] += limbs[1] >> 51; + limbs[1] &= low_51_bit_mask; + limbs[3] += limbs[2] >> 51; + limbs[2] &= low_51_bit_mask; + limbs[4] += limbs[3] >> 51; + limbs[3] &= low_51_bit_mask; // ... but instead of carrying (limbs[4] >> 51) = 2^255q // into another limb, discard it, subtracting the value - limbs[4] = limbs[4] & low_51_bit_mask; + limbs[4] &= low_51_bit_mask; // Now arrange the bits of the limbs. let mut s = [0u8;32]; - s[ 0] = limbs[0] as u8; - s[ 1] = (limbs[0] >> 8) as u8; - s[ 2] = (limbs[0] >> 16) as u8; - s[ 3] = (limbs[0] >> 24) as u8; - s[ 4] = (limbs[0] >> 32) as u8; - s[ 5] = (limbs[0] >> 40) as u8; + s[ 0] = limbs[0] as u8; + s[ 1] = (limbs[0] >> 8) as u8; + s[ 2] = (limbs[0] >> 16) as u8; + s[ 3] = (limbs[0] >> 24) as u8; + s[ 4] = (limbs[0] >> 32) as u8; + s[ 5] = (limbs[0] >> 40) as u8; s[ 6] = ((limbs[0] >> 48) | (limbs[1] << 3)) as u8; - s[ 7] = (limbs[1] >> 5) as u8; - s[ 8] = (limbs[1] >> 13) as u8; - s[ 9] = (limbs[1] >> 21) as u8; - s[10] = (limbs[1] >> 29) as u8; - s[11] = (limbs[1] >> 37) as u8; + s[ 7] = (limbs[1] >> 5) as u8; + s[ 8] = (limbs[1] >> 13) as u8; + s[ 9] = (limbs[1] >> 21) as u8; + s[10] = (limbs[1] >> 29) as u8; + s[11] = (limbs[1] >> 37) as u8; s[12] = ((limbs[1] >> 45) | (limbs[2] << 6)) as u8; - s[13] = (limbs[2] >> 2) as u8; - s[14] = (limbs[2] >> 10) as u8; - s[15] = (limbs[2] >> 18) as u8; - s[16] = (limbs[2] >> 26) as u8; - s[17] = (limbs[2] >> 34) as u8; - s[18] = (limbs[2] >> 42) as u8; + s[13] = (limbs[2] >> 2) as u8; + s[14] = (limbs[2] >> 10) as u8; + s[15] = (limbs[2] >> 18) as u8; + s[16] = (limbs[2] >> 26) as u8; + s[17] = (limbs[2] >> 34) as u8; + s[18] = (limbs[2] >> 42) as u8; s[19] = ((limbs[2] >> 50) | (limbs[3] << 1)) as u8; - s[20] = (limbs[3] >> 7) as u8; - s[21] = (limbs[3] >> 15) as u8; - s[22] = (limbs[3] >> 23) as u8; - s[23] = (limbs[3] >> 31) as u8; - s[24] = (limbs[3] >> 39) as u8; + s[20] = (limbs[3] >> 7) as u8; + s[21] = (limbs[3] >> 15) as u8; + s[22] = (limbs[3] >> 23) as u8; + s[23] = (limbs[3] >> 31) as u8; + s[24] = (limbs[3] >> 39) as u8; s[25] = ((limbs[3] >> 47) | (limbs[4] << 4)) as u8; - s[26] = (limbs[4] >> 4) as u8; - s[27] = (limbs[4] >> 12) as u8; - s[28] = (limbs[4] >> 20) as u8; - s[29] = (limbs[4] >> 28) as u8; - s[30] = (limbs[4] >> 36) as u8; - s[31] = (limbs[4] >> 44) as u8; + s[26] = (limbs[4] >> 4) as u8; + s[27] = (limbs[4] >> 12) as u8; + s[28] = (limbs[4] >> 20) as u8; + s[29] = (limbs[4] >> 28) as u8; + s[30] = (limbs[4] >> 36) as u8; + s[31] = (limbs[4] >> 44) as u8; // High bit should be zero. debug_assert!((s[31] & 0b1000_0000u8) == 0u8); @@ -442,13 +450,16 @@ impl FieldElement51 { } /// Given `k > 0`, return `self^(2^k)`. + #[rustfmt::skip] // keep alignment of c* calculations pub fn pow2k(&self, mut k: u32) -> FieldElement51 { debug_assert!( k > 0 ); /// Multiply two 64-bit integers with 128 bits of output. #[inline(always)] - fn m(x: u64, y: u64) -> u128 { (x as u128) * (y as u128) } + fn m(x: u64, y: u64) -> u128 { + (x as u128) * (y as u128) + } let mut a: [u64; 5] = self.0; @@ -530,7 +541,7 @@ impl FieldElement51 { // a[0] + carry * 19 < 2^51 + 19 * 2^59.33 < 2^63.58 // // and there is no overflow. - a[0] = a[0] + carry * 19; + a[0] += carry * 19; // Now a[1] < 2^51 + 2^(64 -51) = 2^51 + 2^13 < 2^(51 + epsilon). a[1] += a[0] >> 51; @@ -538,7 +549,7 @@ impl FieldElement51 { // Now all a[i] < 2^(51 + epsilon) and a = self^(2^k). - k = k - 1; + k -= 1; if k == 0 { break; } diff --git a/src/backend/serial/u64/mod.rs b/curve25519-dalek/src/backend/serial/u64/mod.rs similarity index 100% rename from src/backend/serial/u64/mod.rs rename to curve25519-dalek/src/backend/serial/u64/mod.rs diff --git a/src/backend/serial/u64/scalar.rs b/curve25519-dalek/src/backend/serial/u64/scalar.rs similarity index 63% rename from src/backend/serial/u64/scalar.rs rename to curve25519-dalek/src/backend/serial/u64/scalar.rs index cee69da0e..1cc2df4a0 100644 --- a/src/backend/serial/u64/scalar.rs +++ b/curve25519-dalek/src/backend/serial/u64/scalar.rs @@ -14,21 +14,23 @@ use core::fmt::Debug; use core::ops::{Index, IndexMut}; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; -use constants; +use crate::constants; /// The `Scalar52` struct represents an element in /// \\(\mathbb Z / \ell \mathbb Z\\) as 5 \\(52\\)-bit limbs. -#[derive(Copy,Clone)] +#[derive(Copy, Clone)] pub struct Scalar52(pub [u64; 5]); impl Debug for Scalar52 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Scalar52: {:?}", &self.0[..]) } } +#[cfg(feature = "zeroize")] impl Zeroize for Scalar52 { fn zeroize(&mut self) { self.0.zeroize(); @@ -55,12 +57,11 @@ fn m(x: u64, y: u64) -> u128 { } impl Scalar52 { - /// Return the zero scalar - pub fn zero() -> Scalar52 { - Scalar52([0,0,0,0,0]) - } + /// The scalar \\( 0 \\). + pub const ZERO: Scalar52 = Scalar52([0, 0, 0, 0, 0]); /// Unpack a 32 byte / 256 bit scalar into 5 52-bit limbs. + #[rustfmt::skip] // keep alignment of s[*] calculations pub fn from_bytes(bytes: &[u8; 32]) -> Scalar52 { let mut words = [0u64; 4]; for i in 0..4 { @@ -71,18 +72,19 @@ impl Scalar52 { let mask = (1u64 << 52) - 1; let top_mask = (1u64 << 48) - 1; - let mut s = Scalar52::zero(); + let mut s = Scalar52::ZERO; - s[ 0] = words[0] & mask; - s[ 1] = ((words[0] >> 52) | (words[1] << 12)) & mask; - s[ 2] = ((words[1] >> 40) | (words[2] << 24)) & mask; - s[ 3] = ((words[2] >> 28) | (words[3] << 36)) & mask; - s[ 4] = (words[3] >> 16) & top_mask; + s[0] = words[0] & mask; + s[1] = ((words[0] >> 52) | (words[1] << 12)) & mask; + s[2] = ((words[1] >> 40) | (words[2] << 24)) & mask; + s[3] = ((words[2] >> 28) | (words[3] << 36)) & mask; + s[4] = (words[3] >> 16) & top_mask; s } /// Reduce a 64 byte / 512 bit scalar mod l + #[rustfmt::skip] // keep alignment of lo[*] and hi[*] calculations pub fn from_bytes_wide(bytes: &[u8; 64]) -> Scalar52 { let mut words = [0u64; 8]; for i in 0..8 { @@ -92,19 +94,19 @@ impl Scalar52 { } let mask = (1u64 << 52) - 1; - let mut lo = Scalar52::zero(); - let mut hi = Scalar52::zero(); - - lo[0] = words[ 0] & mask; - lo[1] = ((words[ 0] >> 52) | (words[ 1] << 12)) & mask; - lo[2] = ((words[ 1] >> 40) | (words[ 2] << 24)) & mask; - lo[3] = ((words[ 2] >> 28) | (words[ 3] << 36)) & mask; - lo[4] = ((words[ 3] >> 16) | (words[ 4] << 48)) & mask; - hi[0] = (words[ 4] >> 4) & mask; - hi[1] = ((words[ 4] >> 56) | (words[ 5] << 8)) & mask; - hi[2] = ((words[ 5] >> 44) | (words[ 6] << 20)) & mask; - hi[3] = ((words[ 6] >> 32) | (words[ 7] << 32)) & mask; - hi[4] = words[ 7] >> 20 ; + let mut lo = Scalar52::ZERO; + let mut hi = Scalar52::ZERO; + + lo[0] = words[0] & mask; + lo[1] = ((words[0] >> 52) | (words[ 1] << 12)) & mask; + lo[2] = ((words[1] >> 40) | (words[ 2] << 24)) & mask; + lo[3] = ((words[2] >> 28) | (words[ 3] << 36)) & mask; + lo[4] = ((words[3] >> 16) | (words[ 4] << 48)) & mask; + hi[0] = (words[4] >> 4) & mask; + hi[1] = ((words[4] >> 56) | (words[ 5] << 8)) & mask; + hi[2] = ((words[5] >> 44) | (words[ 6] << 20)) & mask; + hi[3] = ((words[6] >> 32) | (words[ 7] << 32)) & mask; + hi[4] = words[7] >> 20 ; lo = Scalar52::montgomery_mul(&lo, &constants::R); // (lo * R) / R = lo hi = Scalar52::montgomery_mul(&hi, &constants::RR); // (hi * R^2) / R = hi * R @@ -113,19 +115,21 @@ impl Scalar52 { } /// Pack the limbs of this `Scalar52` into 32 bytes - pub fn to_bytes(&self) -> [u8; 32] { + #[rustfmt::skip] // keep alignment of s[*] calculations + #[allow(clippy::identity_op)] + pub fn as_bytes(&self) -> [u8; 32] { let mut s = [0u8; 32]; - s[0] = (self.0[ 0] >> 0) as u8; - s[1] = (self.0[ 0] >> 8) as u8; - s[2] = (self.0[ 0] >> 16) as u8; - s[3] = (self.0[ 0] >> 24) as u8; - s[4] = (self.0[ 0] >> 32) as u8; - s[5] = (self.0[ 0] >> 40) as u8; - s[6] = ((self.0[ 0] >> 48) | (self.0[ 1] << 4)) as u8; - s[7] = (self.0[ 1] >> 4) as u8; - s[8] = (self.0[ 1] >> 12) as u8; - s[9] = (self.0[ 1] >> 20) as u8; + s[ 0] = (self.0[ 0] >> 0) as u8; + s[ 1] = (self.0[ 0] >> 8) as u8; + s[ 2] = (self.0[ 0] >> 16) as u8; + s[ 3] = (self.0[ 0] >> 24) as u8; + s[ 4] = (self.0[ 0] >> 32) as u8; + s[ 5] = (self.0[ 0] >> 40) as u8; + s[ 6] = ((self.0[ 0] >> 48) | (self.0[ 1] << 4)) as u8; + s[ 7] = (self.0[ 1] >> 4) as u8; + s[ 8] = (self.0[ 1] >> 12) as u8; + s[ 9] = (self.0[ 1] >> 20) as u8; s[10] = (self.0[ 1] >> 28) as u8; s[11] = (self.0[ 1] >> 36) as u8; s[12] = (self.0[ 1] >> 44) as u8; @@ -154,7 +158,7 @@ impl Scalar52 { /// Compute `a + b` (mod l) pub fn add(a: &Scalar52, b: &Scalar52) -> Scalar52 { - let mut sum = Scalar52::zero(); + let mut sum = Scalar52::ZERO; let mask = (1u64 << 52) - 1; // a + b @@ -170,7 +174,7 @@ impl Scalar52 { /// Compute `a - b` (mod l) pub fn sub(a: &Scalar52, b: &Scalar52) -> Scalar52 { - let mut difference = Scalar52::zero(); + let mut difference = Scalar52::ZERO; let mask = (1u64 << 52) - 1; // a - b @@ -193,53 +197,56 @@ impl Scalar52 { /// Compute `a * b` #[inline(always)] + #[rustfmt::skip] // keep alignment of z[*] calculations pub (crate) fn mul_internal(a: &Scalar52, b: &Scalar52) -> [u128; 9] { let mut z = [0u128; 9]; - z[0] = m(a[0],b[0]); - z[1] = m(a[0],b[1]) + m(a[1],b[0]); - z[2] = m(a[0],b[2]) + m(a[1],b[1]) + m(a[2],b[0]); - z[3] = m(a[0],b[3]) + m(a[1],b[2]) + m(a[2],b[1]) + m(a[3],b[0]); - z[4] = m(a[0],b[4]) + m(a[1],b[3]) + m(a[2],b[2]) + m(a[3],b[1]) + m(a[4],b[0]); - z[5] = m(a[1],b[4]) + m(a[2],b[3]) + m(a[3],b[2]) + m(a[4],b[1]); - z[6] = m(a[2],b[4]) + m(a[3],b[3]) + m(a[4],b[2]); - z[7] = m(a[3],b[4]) + m(a[4],b[3]); - z[8] = m(a[4],b[4]); + z[0] = m(a[0], b[0]); + z[1] = m(a[0], b[1]) + m(a[1], b[0]); + z[2] = m(a[0], b[2]) + m(a[1], b[1]) + m(a[2], b[0]); + z[3] = m(a[0], b[3]) + m(a[1], b[2]) + m(a[2], b[1]) + m(a[3], b[0]); + z[4] = m(a[0], b[4]) + m(a[1], b[3]) + m(a[2], b[2]) + m(a[3], b[1]) + m(a[4], b[0]); + z[5] = m(a[1], b[4]) + m(a[2], b[3]) + m(a[3], b[2]) + m(a[4], b[1]); + z[6] = m(a[2], b[4]) + m(a[3], b[3]) + m(a[4], b[2]); + z[7] = m(a[3], b[4]) + m(a[4], b[3]); + z[8] = m(a[4], b[4]); z } /// Compute `a^2` #[inline(always)] + #[rustfmt::skip] // keep alignment of return calculations fn square_internal(a: &Scalar52) -> [u128; 9] { let aa = [ - a[0]*2, - a[1]*2, - a[2]*2, - a[3]*2, + a[0] * 2, + a[1] * 2, + a[2] * 2, + a[3] * 2, ]; [ - m( a[0],a[0]), - m(aa[0],a[1]), - m(aa[0],a[2]) + m( a[1],a[1]), - m(aa[0],a[3]) + m(aa[1],a[2]), - m(aa[0],a[4]) + m(aa[1],a[3]) + m( a[2],a[2]), - m(aa[1],a[4]) + m(aa[2],a[3]), - m(aa[2],a[4]) + m( a[3],a[3]), - m(aa[3],a[4]), - m(a[4],a[4]) + m( a[0], a[0]), + m(aa[0], a[1]), + m(aa[0], a[2]) + m( a[1], a[1]), + m(aa[0], a[3]) + m(aa[1], a[2]), + m(aa[0], a[4]) + m(aa[1], a[3]) + m( a[2], a[2]), + m(aa[1], a[4]) + m(aa[2], a[3]), + m(aa[2], a[4]) + m( a[3], a[3]), + m(aa[3], a[4]), + m(a[4], a[4]) ] } /// Compute `limbs/R` (mod l), where R is the Montgomery modulus 2^260 #[inline(always)] + #[rustfmt::skip] // keep alignment of n* and r* calculations pub (crate) fn montgomery_reduce(limbs: &[u128; 9]) -> Scalar52 { #[inline(always)] fn part1(sum: u128) -> (u128, u64) { let p = (sum as u64).wrapping_mul(constants::LFACTOR) & ((1u64 << 52) - 1); - ((sum + m(p,constants::L[0])) >> 52, p) + ((sum + m(p, constants::L[0])) >> 52, p) } #[inline(always)] @@ -253,20 +260,20 @@ impl Scalar52 { // the first half computes the Montgomery adjustment factor n, and begins adding n*l to make limbs divisible by R let (carry, n0) = part1( limbs[0]); - let (carry, n1) = part1(carry + limbs[1] + m(n0,l[1])); - let (carry, n2) = part1(carry + limbs[2] + m(n0,l[2]) + m(n1,l[1])); - let (carry, n3) = part1(carry + limbs[3] + m(n1,l[2]) + m(n2,l[1])); - let (carry, n4) = part1(carry + limbs[4] + m(n0,l[4]) + m(n2,l[2]) + m(n3,l[1])); + let (carry, n1) = part1(carry + limbs[1] + m(n0, l[1])); + let (carry, n2) = part1(carry + limbs[2] + m(n0, l[2]) + m(n1, l[1])); + let (carry, n3) = part1(carry + limbs[3] + m(n1, l[2]) + m(n2, l[1])); + let (carry, n4) = part1(carry + limbs[4] + m(n0, l[4]) + m(n2, l[2]) + m(n3, l[1])); // limbs is divisible by R now, so we can divide by R by simply storing the upper half as the result - let (carry, r0) = part2(carry + limbs[5] + m(n1,l[4]) + m(n3,l[2]) + m(n4,l[1])); - let (carry, r1) = part2(carry + limbs[6] + m(n2,l[4]) + m(n4,l[2])); - let (carry, r2) = part2(carry + limbs[7] + m(n3,l[4]) ); - let (carry, r3) = part2(carry + limbs[8] + m(n4,l[4])); + let (carry, r0) = part2(carry + limbs[5] + m(n1, l[4]) + m(n3, l[2]) + m(n4, l[1])); + let (carry, r1) = part2(carry + limbs[6] + m(n2,l[4]) + m(n4, l[2])); + let (carry, r2) = part2(carry + limbs[7] + m(n3, l[4]) ); + let (carry, r3) = part2(carry + limbs[8] + m(n4, l[4])); let r4 = carry as u64; // result may be >= l, so attempt to subtract l - Scalar52::sub(&Scalar52([r0,r1,r2,r3,r4]), l) + Scalar52::sub(&Scalar52([r0, r1, r2, r3, r4]), l) } /// Compute `a * b` (mod l) @@ -298,11 +305,12 @@ impl Scalar52 { /// Puts a Scalar52 in to Montgomery form, i.e. computes `a*R (mod l)` #[inline(never)] - pub fn to_montgomery(&self) -> Scalar52 { + pub fn as_montgomery(&self) -> Scalar52 { Scalar52::montgomery_mul(self, &constants::RR) } /// Takes a Scalar52 out of Montgomery form, i.e. computes `a/R (mod l)` + #[allow(clippy::wrong_self_convention)] #[inline(never)] pub fn from_montgomery(&self) -> Scalar52 { let mut limbs = [0u128; 9]; @@ -313,7 +321,6 @@ impl Scalar52 { } } - #[cfg(test)] mod test { use super::*; @@ -324,55 +331,95 @@ mod test { /// x = 14474011154664524427946373126085988481658748083205070504932198000989141204991 /// x = 7237005577332262213973186563042994240801631723825162898930247062703686954002 mod l /// x = 3057150787695215392275360544382990118917283750546154083604586903220563173085*R mod l in Montgomery form - pub static X: Scalar52 = Scalar52( - [0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, 0x000fffffffffffff, - 0x00001fffffffffff]); + pub static X: Scalar52 = Scalar52([ + 0x000fffffffffffff, + 0x000fffffffffffff, + 0x000fffffffffffff, + 0x000fffffffffffff, + 0x00001fffffffffff, + ]); /// x^2 = 3078544782642840487852506753550082162405942681916160040940637093560259278169 mod l - pub static XX: Scalar52 = Scalar52( - [0x0001668020217559, 0x000531640ffd0ec0, 0x00085fd6f9f38a31, 0x000c268f73bb1cf4, - 0x000006ce65046df0]); + pub static XX: Scalar52 = Scalar52([ + 0x0001668020217559, + 0x000531640ffd0ec0, + 0x00085fd6f9f38a31, + 0x000c268f73bb1cf4, + 0x000006ce65046df0, + ]); /// x^2 = 4413052134910308800482070043710297189082115023966588301924965890668401540959*R mod l in Montgomery form - pub static XX_MONT: Scalar52 = Scalar52( - [0x000c754eea569a5c, 0x00063b6ed36cb215, 0x0008ffa36bf25886, 0x000e9183614e7543, - 0x0000061db6c6f26f]); + pub static XX_MONT: Scalar52 = Scalar52([ + 0x000c754eea569a5c, + 0x00063b6ed36cb215, + 0x0008ffa36bf25886, + 0x000e9183614e7543, + 0x0000061db6c6f26f, + ]); /// y = 6145104759870991071742105800796537629880401874866217824609283457819451087098 - pub static Y: Scalar52 = Scalar52( - [0x000b75071e1458fa, 0x000bf9d75e1ecdac, 0x000433d2baf0672b, 0x0005fffcc11fad13, - 0x00000d96018bb825]); + pub static Y: Scalar52 = Scalar52([ + 0x000b75071e1458fa, + 0x000bf9d75e1ecdac, + 0x000433d2baf0672b, + 0x0005fffcc11fad13, + 0x00000d96018bb825, + ]); /// x*y = 36752150652102274958925982391442301741 mod l - pub static XY: Scalar52 = Scalar52( - [0x000ee6d76ba7632d, 0x000ed50d71d84e02, 0x00000000001ba634, 0x0000000000000000, - 0x0000000000000000]); + pub static XY: Scalar52 = Scalar52([ + 0x000ee6d76ba7632d, + 0x000ed50d71d84e02, + 0x00000000001ba634, + 0x0000000000000000, + 0x0000000000000000, + ]); /// x*y = 658448296334113745583381664921721413881518248721417041768778176391714104386*R mod l in Montgomery form - pub static XY_MONT: Scalar52 = Scalar52( - [0x0006d52bf200cfd5, 0x00033fb1d7021570, 0x000f201bc07139d8, 0x0001267e3e49169e, - 0x000007b839c00268]); + pub static XY_MONT: Scalar52 = Scalar52([ + 0x0006d52bf200cfd5, + 0x00033fb1d7021570, + 0x000f201bc07139d8, + 0x0001267e3e49169e, + 0x000007b839c00268, + ]); /// a = 2351415481556538453565687241199399922945659411799870114962672658845158063753 - pub static A: Scalar52 = Scalar52( - [0x0005236c07b3be89, 0x0001bc3d2a67c0c4, 0x000a4aa782aae3ee, 0x0006b3f6e4fec4c4, - 0x00000532da9fab8c]); + pub static A: Scalar52 = Scalar52([ + 0x0005236c07b3be89, + 0x0001bc3d2a67c0c4, + 0x000a4aa782aae3ee, + 0x0006b3f6e4fec4c4, + 0x00000532da9fab8c, + ]); /// b = 4885590095775723760407499321843594317911456947580037491039278279440296187236 - pub static B: Scalar52 = Scalar52( - [0x000d3fae55421564, 0x000c2df24f65a4bc, 0x0005b5587d69fb0b, 0x00094c091b013b3b, - 0x00000acd25605473]); + pub static B: Scalar52 = Scalar52([ + 0x000d3fae55421564, + 0x000c2df24f65a4bc, + 0x0005b5587d69fb0b, + 0x00094c091b013b3b, + 0x00000acd25605473, + ]); /// a+b = 0 /// a-b = 4702830963113076907131374482398799845891318823599740229925345317690316127506 - pub static AB: Scalar52 = Scalar52( - [0x000a46d80f677d12, 0x0003787a54cf8188, 0x0004954f0555c7dc, 0x000d67edc9fd8989, - 0x00000a65b53f5718]); + pub static AB: Scalar52 = Scalar52([ + 0x000a46d80f677d12, + 0x0003787a54cf8188, + 0x0004954f0555c7dc, + 0x000d67edc9fd8989, + 0x00000a65b53f5718, + ]); // c = (2^512 - 1) % l = 1627715501170711445284395025044413883736156588369414752970002579683115011840 - pub static C: Scalar52 = Scalar52( - [0x000611e3449c0f00, 0x000a768859347a40, 0x0007f5be65d00e1b, 0x0009a3dceec73d21, - 0x00000399411b7c30]); + pub static C: Scalar52 = Scalar52([ + 0x000611e3449c0f00, + 0x000a768859347a40, + 0x0007f5be65d00e1b, + 0x0009a3dceec73d21, + 0x00000399411b7c30, + ]); #[test] fn mul_max() { @@ -425,7 +472,7 @@ mod test { #[test] fn add() { let res = Scalar52::add(&A, &B); - let zero = Scalar52::zero(); + let zero = Scalar52::ZERO; for i in 0..5 { assert!(res[i] == zero[i]); } diff --git a/curve25519-dalek/src/backend/vector/avx2/constants.rs b/curve25519-dalek/src/backend/vector/avx2/constants.rs new file mode 100644 index 000000000..25c7bde21 --- /dev/null +++ b/curve25519-dalek/src/backend/vector/avx2/constants.rs @@ -0,0 +1,1191 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! This module contains constants used by the AVX2 backend. + +use crate::backend::vector::packed_simd::u32x8; + +use crate::backend::vector::avx2::edwards::{CachedPoint, ExtendedPoint}; +use crate::backend::vector::avx2::field::FieldElement2625x4; + +#[cfg(feature = "precomputed-tables")] +use crate::window::NafLookupTable8; + +/// The identity element as an `ExtendedPoint`. +pub(crate) static EXTENDEDPOINT_IDENTITY: ExtendedPoint = ExtendedPoint(FieldElement2625x4([ + u32x8::new_const(0, 1, 0, 0, 1, 0, 0, 0), + u32x8::splat_const::<0>(), + u32x8::splat_const::<0>(), + u32x8::splat_const::<0>(), + u32x8::splat_const::<0>(), +])); + +/// The identity element as a `CachedPoint`. +pub(crate) static CACHEDPOINT_IDENTITY: CachedPoint = CachedPoint(FieldElement2625x4([ + u32x8::new_const(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431), + u32x8::new_const(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new_const(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new_const(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), + u32x8::new_const(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), +])); + +/// The low limbs of (2p, 2p, 2p, 2p), so that +/// ```ascii,no_run +/// (2p, 2p, 2p, 2p) = [P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI] +/// ``` +pub(crate) static P_TIMES_2_LO: u32x8 = u32x8::new_const( + 67108845 << 1, + 67108845 << 1, + 33554431 << 1, + 33554431 << 1, + 67108845 << 1, + 67108845 << 1, + 33554431 << 1, + 33554431 << 1, +); + +/// The high limbs of (2p, 2p, 2p, 2p), so that +/// ```ascii,no_run +/// (2p, 2p, 2p, 2p) = [P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI] +/// ``` +pub(crate) static P_TIMES_2_HI: u32x8 = u32x8::new_const( + 67108863 << 1, + 67108863 << 1, + 33554431 << 1, + 33554431 << 1, + 67108863 << 1, + 67108863 << 1, + 33554431 << 1, + 33554431 << 1, +); + +/// The low limbs of (16p, 16p, 16p, 16p), so that +/// ```ascii,no_run +/// (16p, 16p, 16p, 16p) = [P_TIMES_16_LO, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI] +/// ``` +pub(crate) static P_TIMES_16_LO: u32x8 = u32x8::new_const( + 67108845 << 4, + 67108845 << 4, + 33554431 << 4, + 33554431 << 4, + 67108845 << 4, + 67108845 << 4, + 33554431 << 4, + 33554431 << 4, +); + +/// The high limbs of (16p, 16p, 16p, 16p), so that +/// ```ascii,no_run +/// (16p, 16p, 16p, 16p) = [P_TIMES_16_LO, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI] +/// ``` +pub(crate) static P_TIMES_16_HI: u32x8 = u32x8::new_const( + 67108863 << 4, + 67108863 << 4, + 33554431 << 4, + 33554431 << 4, + 67108863 << 4, + 67108863 << 4, + 33554431 << 4, + 33554431 << 4, +); + +/// Odd multiples of the Ed25519 basepoint: +#[cfg(feature = "precomputed-tables")] +pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 3571425, 10045002, 19036563, 1096096, 243332, 65897020, 0, 28963681, + ), + u32x8::new_const( + 30896895, 63055514, 1614915, 5095970, 0, 53791688, 0, 31258312, + ), + u32x8::new_const( + 13347627, 40339464, 2236269, 11185503, 0, 22520087, 0, 8659512, + ), + u32x8::new_const( + 11125413, 29139905, 32037254, 28360723, 0, 64556417, 0, 9635759, + ), + u32x8::new_const( + 33268144, 47262491, 4336918, 15795740, 0, 22027545, 0, 4846528, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 47099681, 31447946, 29365447, 24740513, 42991046, 18317844, 16051644, 21404226, + ), + u32x8::new_const( + 31708133, 28909527, 2366091, 13703791, 469246, 54159622, 2601402, 32988002, + ), + u32x8::new_const( + 63432457, 30251794, 15163516, 18491340, 28144087, 35605455, 13682295, 18474872, + ), + u32x8::new_const( + 12221607, 4967598, 26061980, 26008006, 20226147, 9726961, 17410, 18051083, + ), + u32x8::new_const( + 60569645, 62487085, 11911242, 21920922, 4092105, 38186967, 22431483, 31366585, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 18147205, 62587998, 2554617, 536692, 11924528, 26674131, 17645433, 24341419, + ), + u32x8::new_const( + 11573357, 27579485, 31491870, 29000885, 10800976, 51902791, 28076395, 20464029, + ), + u32x8::new_const( + 56031649, 10856669, 11791193, 26769430, 25306956, 5922200, 6630685, 9385098, + ), + u32x8::new_const( + 31319348, 23906711, 16290213, 32142166, 61106354, 17181823, 3548308, 12022566, + ), + u32x8::new_const( + 5904298, 50218605, 11826440, 5492249, 10379071, 3472255, 172742, 31948344, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 10625852, 15193821, 22918394, 23676410, 53695416, 54987793, 10067515, 11747680, + ), + u32x8::new_const( + 65013325, 1309652, 29616320, 28922974, 60360891, 19621771, 9938982, 30406429, + ), + u32x8::new_const( + 54967954, 65931918, 5595602, 25719523, 64909864, 30566415, 15945272, 8495317, + ), + u32x8::new_const( + 1167157, 55265018, 11507029, 31641054, 43497904, 2367338, 12937761, 27517066, + ), + u32x8::new_const( + 656704, 2544994, 13006713, 480979, 38471594, 62541240, 25353597, 11531760, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 22176662, 3984313, 27495285, 4110608, 2909584, 30594106, 15677919, 2549183, + ), + u32x8::new_const( + 33979105, 62269905, 2071511, 6894756, 53189950, 47232857, 6408191, 6123225, + ), + u32x8::new_const( + 32553873, 63948030, 12612401, 3633166, 24054373, 37626618, 14481327, 8520484, + ), + u32x8::new_const( + 56552486, 10749438, 12034813, 28811946, 1445640, 36755601, 12104575, 10257833, + ), + u32x8::new_const( + 22795808, 48761311, 1136056, 9380768, 1411523, 5341811, 27318329, 9686767, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 21157200, 39156966, 20473176, 4934657, 61478183, 45121537, 5429856, 13035023, + ), + u32x8::new_const( + 7954529, 58789246, 31440083, 7054221, 38438565, 36856107, 1364112, 14548122, + ), + u32x8::new_const( + 26120083, 36321360, 4919997, 31687496, 33757765, 36237559, 15243054, 32163861, + ), + u32x8::new_const( + 25878307, 46544824, 19455951, 2414935, 16844726, 56521560, 32680554, 26660660, + ), + u32x8::new_const( + 48360220, 43407178, 12187042, 24925816, 7423722, 25746484, 12814654, 17395963, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 63153652, 32195955, 4087908, 8431689, 30392384, 47203165, 8986649, 9053039, + ), + u32x8::new_const( + 63659241, 47988767, 2931872, 19953600, 11747107, 51610101, 20952181, 13364887, + ), + u32x8::new_const( + 3659197, 58790649, 5930099, 2605312, 28477896, 580728, 20579735, 2610622, + ), + u32x8::new_const( + 41781607, 17161358, 10690531, 24368015, 47027031, 36742339, 5414694, 13156365, + ), + u32x8::new_const( + 13237853, 51182423, 8954802, 29006542, 22643989, 56896541, 22830593, 10289708, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 1401265, 58846825, 30911620, 32239180, 15391552, 15200821, 6339309, 16403588, + ), + u32x8::new_const( + 55913797, 29541724, 1664461, 21709410, 38470488, 47097092, 17674945, 32666066, + ), + u32x8::new_const( + 22844482, 10797709, 27548106, 31638735, 34500968, 26611503, 19727211, 13160873, + ), + u32x8::new_const( + 31485204, 14496164, 13981208, 10276888, 5748808, 35024436, 2740987, 7479021, + ), + u32x8::new_const( + 58541207, 14866135, 32344041, 545930, 62661488, 6941250, 27940205, 11976112, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 39849808, 44781685, 15697329, 24387845, 12501486, 50260092, 23199481, 31929024, + ), + u32x8::new_const( + 24823070, 27956017, 27034296, 10316465, 47664045, 11152446, 15719183, 30181617, + ), + u32x8::new_const( + 20771189, 19969144, 31433937, 19185213, 27565920, 10384445, 2893359, 9255362, + ), + u32x8::new_const( + 42894974, 11925545, 32134441, 32738810, 55916336, 32479272, 19563550, 5511385, + ), + u32x8::new_const( + 17857161, 47809169, 14564114, 27997751, 33024640, 38669671, 31956536, 27313245, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 58237774, 15917425, 18872208, 19394230, 17374297, 6101419, 4839741, 6596900, + ), + u32x8::new_const( + 66947393, 15744215, 18368993, 17750160, 41006525, 9205497, 2629667, 32170865, + ), + u32x8::new_const( + 66481381, 1919414, 28338762, 7372967, 33819153, 4156199, 27126309, 12739816, + ), + u32x8::new_const( + 44117158, 58545296, 22521371, 11809712, 28998792, 50731010, 30215699, 25748377, + ), + u32x8::new_const( + 23561284, 4160244, 9035405, 24895184, 39761639, 59253416, 8684759, 22487864, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 12671134, 56419053, 16092401, 30038207, 4002647, 47822606, 7151311, 28430768, + ), + u32x8::new_const( + 61041684, 35765374, 30598048, 19666539, 44150175, 40140037, 290469, 28442674, + ), + u32x8::new_const( + 18847796, 1371617, 33316881, 13199936, 43646578, 17068881, 12074900, 1537415, + ), + u32x8::new_const( + 10052225, 38316070, 27469797, 5297537, 50725570, 20435349, 10339121, 2779737, + ), + u32x8::new_const( + 18372189, 15466385, 24762130, 22217964, 23503887, 47844464, 10415034, 2606889, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 55082775, 45300503, 16032654, 5964396, 17743504, 24634761, 19493066, 5184611, + ), + u32x8::new_const( + 50172633, 35093294, 10040575, 23616256, 4543900, 61852191, 4049821, 7423669, + ), + u32x8::new_const( + 20295398, 40009376, 10487190, 15670429, 51972856, 58649552, 20436392, 3432497, + ), + u32x8::new_const( + 35189420, 54117751, 12825868, 6283038, 27540739, 30648758, 22658912, 9466689, + ), + u32x8::new_const( + 51737549, 40725785, 17409814, 25201086, 21156239, 34176168, 26814520, 5956424, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 8211442, 8014184, 6260823, 22108096, 32182620, 51844847, 2466270, 28582231, + ), + u32x8::new_const( + 27199739, 3848333, 31738017, 10892045, 4963982, 65391770, 32551997, 28906469, + ), + u32x8::new_const( + 16606846, 32207068, 26404535, 7614129, 45416902, 65584718, 13821785, 2646060, + ), + u32x8::new_const( + 36090634, 57981287, 32247670, 22837502, 31003861, 55448117, 6062915, 20369975, + ), + u32x8::new_const( + 27381403, 50578107, 522631, 29521058, 31137497, 40220737, 27628049, 1824195, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 59402443, 17056879, 29262689, 6131785, 52551472, 43367471, 29423199, 18899208, + ), + u32x8::new_const( + 5749414, 43514612, 11365899, 21514624, 65591890, 60945892, 19841732, 5628567, + ), + u32x8::new_const( + 19334369, 52500268, 12307673, 5267367, 3212103, 9035822, 29142161, 30520954, + ), + u32x8::new_const( + 57261330, 6819646, 22089161, 9800373, 55155453, 62250856, 13766735, 25244545, + ), + u32x8::new_const( + 54370226, 61888301, 24496089, 2540581, 65637506, 60274355, 18154273, 11687259, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 12521903, 26014045, 13995625, 33360175, 23605474, 7376434, 27229267, 17195036, + ), + u32x8::new_const( + 59482891, 10074423, 574357, 3857753, 61377787, 50306685, 5241065, 20234396, + ), + u32x8::new_const( + 23674717, 6997172, 20771841, 16858511, 40565304, 29973136, 7049812, 14585010, + ), + u32x8::new_const( + 1427477, 13295732, 31762066, 31499740, 60419925, 54666164, 22009424, 8089609, + ), + u32x8::new_const( + 58154031, 41593020, 15342328, 957047, 38937260, 37037498, 24871992, 32973409, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 30654745, 51286025, 21206982, 2433562, 12780105, 31732574, 33087964, 33081189, + ), + u32x8::new_const( + 66640017, 42720009, 16567620, 15300745, 1530367, 33001123, 20930247, 21042661, + ), + u32x8::new_const( + 15003356, 5294119, 22985605, 18928772, 32628461, 18230172, 14773298, 27193722, + ), + u32x8::new_const( + 27555, 65346287, 17017174, 7837720, 21499787, 42855613, 22474984, 13675085, + ), + u32x8::new_const( + 24164369, 50130116, 5973149, 24152073, 1577334, 25400030, 18648484, 32228854, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 49518649, 59119280, 31670678, 20396561, 61728330, 651402, 176032, 9529498, + ), + u32x8::new_const( + 61765532, 9082232, 32794568, 15526956, 48543100, 32614212, 19001206, 25680229, + ), + u32x8::new_const( + 32086091, 10373081, 8996131, 31822823, 35788988, 49973190, 30542040, 17858455, + ), + u32x8::new_const( + 48130197, 58121889, 27753291, 29923268, 54448075, 43300790, 9336565, 15770022, + ), + u32x8::new_const( + 57725546, 20557498, 9366233, 16023566, 16189031, 2837363, 24315301, 27003505, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 28286608, 10767548, 18220739, 5413236, 48253387, 58255702, 11864864, 28527159, + ), + u32x8::new_const( + 45038176, 58655197, 25648758, 10951484, 42564382, 34542843, 23146954, 22234334, + ), + u32x8::new_const( + 14858710, 24978793, 15040559, 4379220, 47621477, 40271440, 15650420, 1998736, + ), + u32x8::new_const( + 24106391, 9626149, 344505, 25253814, 34579800, 59687089, 25718289, 25904133, + ), + u32x8::new_const( + 1981195, 37751302, 26132048, 1764722, 13288231, 28808622, 12531301, 18292949, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 13869851, 31448904, 14963539, 7581293, 20536485, 35021083, 21257574, 33356609, + ), + u32x8::new_const( + 36903364, 18429241, 11097857, 5943856, 60583077, 40015815, 30509523, 31915271, + ), + u32x8::new_const( + 49161801, 40681915, 67892, 25454357, 22779677, 25798439, 15964829, 5863227, + ), + u32x8::new_const( + 60810637, 4496471, 5217137, 14095116, 50942411, 50712663, 2507380, 26844507, + ), + u32x8::new_const( + 34579752, 53519385, 10859797, 18816024, 42552864, 39478521, 6783896, 17277037, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 43287109, 27900723, 33182187, 2766754, 17041989, 1018260, 33392790, 4830032, + ), + u32x8::new_const( + 60194178, 30788903, 24728888, 14513195, 20897010, 28843233, 20111980, 17475240, + ), + u32x8::new_const( + 46042274, 19257042, 4628173, 31649727, 27388316, 66631493, 11541886, 6408028, + ), + u32x8::new_const( + 57024680, 49536568, 32050358, 31321917, 17437691, 49672356, 2884755, 20493991, + ), + u32x8::new_const( + 59553007, 46782643, 29001173, 1814088, 21930692, 51319706, 14965872, 30748046, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 16441817, 36111849, 6900424, 602234, 46522199, 16441484, 8135070, 21726541, + ), + u32x8::new_const( + 37711225, 32701959, 11679112, 13125533, 32154135, 9407918, 26554289, 620848, + ), + u32x8::new_const( + 19233407, 30086864, 14679568, 2797374, 4892806, 7993077, 247658, 5632804, + ), + u32x8::new_const( + 37427262, 26675495, 27125659, 13496131, 50718473, 40115609, 28505351, 27837393, + ), + u32x8::new_const( + 196819, 18410429, 7070012, 21691388, 29763371, 24754123, 9727048, 10930179, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 28319289, 40734650, 16225680, 24739184, 64272368, 35356897, 7866648, 13635853, + ), + u32x8::new_const( + 34165295, 48328447, 27041670, 23643655, 48949950, 52963288, 30411133, 6045174, + ), + u32x8::new_const( + 18583559, 41649834, 9813585, 26098520, 25682734, 26733526, 19276490, 10654728, + ), + u32x8::new_const( + 34867476, 52715968, 5694571, 13380978, 15134994, 1831255, 8608001, 17266401, + ), + u32x8::new_const( + 59925903, 44282172, 27802465, 1855069, 14234749, 36635487, 11302294, 10938429, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 8373273, 49064494, 4932071, 32997499, 38472880, 29335908, 14504412, 22460029, + ), + u32x8::new_const( + 31795930, 50785923, 25835990, 25790073, 65669841, 11360450, 9969157, 9008164, + ), + u32x8::new_const( + 50262498, 45869261, 16124434, 15336007, 882762, 42522623, 11277198, 26296377, + ), + u32x8::new_const( + 42332732, 59129236, 14452816, 567985, 208061, 34722729, 32008143, 14828749, + ), + u32x8::new_const( + 17937794, 36846032, 32102665, 4442466, 19745435, 31633451, 7146411, 15812027, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 30741269, 38648744, 12562645, 30092623, 25073992, 28730659, 27911745, 30000958, + ), + u32x8::new_const( + 2859794, 25991700, 17776078, 27091930, 2328322, 60061146, 18581824, 18039008, + ), + u32x8::new_const( + 58206333, 17917354, 1972306, 11853766, 2655376, 60543390, 18416710, 13287440, + ), + u32x8::new_const( + 62746330, 61423885, 21246577, 2266675, 60099139, 14804707, 14772234, 20679434, + ), + u32x8::new_const( + 26987698, 15488817, 715616, 2339565, 51980752, 17333865, 21965103, 10839820, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 18672548, 57660959, 16042910, 19519287, 62865851, 17580961, 26628347, 23774759, + ), + u32x8::new_const( + 368070, 3464471, 25888304, 30370559, 52396053, 45426828, 28745251, 9246829, + ), + u32x8::new_const( + 29090099, 57950037, 23104657, 4903923, 10987778, 56163684, 23621539, 10332760, + ), + u32x8::new_const( + 53338235, 44851161, 21606845, 31069622, 4243630, 34464392, 11286454, 5802022, + ), + u32x8::new_const( + 46710757, 63389067, 11642865, 1980986, 12967337, 28162061, 3854192, 30432268, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 12179834, 41005450, 12809619, 33525228, 4624405, 46957889, 16968743, 11827816, + ), + u32x8::new_const( + 51521162, 12466775, 31791271, 15303651, 49798465, 62714504, 6509600, 12918560, + ), + u32x8::new_const( + 20445559, 1756449, 28848701, 7920171, 9835040, 5900071, 28757409, 12376688, + ), + u32x8::new_const( + 18259496, 14281012, 21767026, 10232236, 20000226, 12400540, 4104902, 23570543, + ), + u32x8::new_const( + 3687440, 26546648, 13328821, 26841081, 49822734, 22334054, 244496, 24862543, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 59523541, 62195428, 3853227, 13954801, 12387708, 47627615, 27221350, 17899572, + ), + u32x8::new_const( + 63193587, 36343307, 14595132, 6880795, 1364792, 37648434, 3259017, 20536046, + ), + u32x8::new_const( + 30362834, 10440372, 9574624, 11729232, 63861613, 21748389, 5530846, 2721586, + ), + u32x8::new_const( + 18339760, 1550632, 17170271, 25732971, 28459263, 63142237, 21642345, 31557672, + ), + u32x8::new_const( + 10611282, 5204623, 18049257, 214175, 19432723, 49809070, 26010406, 27449522, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 19770733, 26478685, 9464541, 29158041, 28604307, 45196604, 7586524, 6641859, + ), + u32x8::new_const( + 65654484, 52230498, 30886612, 19112823, 47271809, 38942611, 16020035, 10773481, + ), + u32x8::new_const( + 27464323, 54451016, 20646645, 17732915, 23008717, 53626684, 3253189, 15614410, + ), + u32x8::new_const( + 52381752, 40693008, 7063024, 28469981, 51159478, 44543211, 19941777, 5985451, + ), + u32x8::new_const( + 13553668, 35524849, 14788737, 1883845, 12385775, 47958835, 29135466, 1776722, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 36719806, 20827965, 23175373, 32996806, 42041892, 65708790, 5467143, 20884008, + ), + u32x8::new_const( + 43256281, 40770646, 17244063, 31959819, 64366384, 43544617, 25057754, 12628720, + ), + u32x8::new_const( + 17337782, 58472057, 27906934, 15305274, 30292418, 39284317, 16946773, 24806712, + ), + u32x8::new_const( + 6485126, 32447403, 16261486, 13561940, 49439635, 10738368, 16419889, 8897231, + ), + u32x8::new_const( + 44812203, 40122262, 25496058, 2759794, 25295304, 52178368, 24154195, 29334408, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 42307254, 57217102, 1088936, 3832827, 33905401, 23130334, 6958056, 12622851, + ), + u32x8::new_const( + 3881189, 14870059, 19712830, 6071598, 38147944, 60776394, 3427938, 13765703, + ), + u32x8::new_const( + 7666911, 24227591, 17077136, 22967588, 6874639, 30915523, 11451695, 24292224, + ), + u32x8::new_const( + 13659529, 31984463, 28764736, 20506164, 64729627, 49321636, 28284636, 25472371, + ), + u32x8::new_const( + 39360308, 42281399, 9446504, 868960, 49227724, 21351115, 30561851, 11292096, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 7071115, 46444090, 5387916, 15432877, 27226682, 41506862, 2398278, 3978240, + ), + u32x8::new_const( + 51009614, 54216973, 24368938, 31392616, 38456150, 62313644, 6729154, 99724, + ), + u32x8::new_const( + 17474332, 62857913, 2619930, 30659308, 18268181, 32809239, 22826292, 24561895, + ), + u32x8::new_const( + 38187020, 67003092, 14118280, 16500577, 18808560, 64983716, 25712929, 32518261, + ), + u32x8::new_const( + 25735813, 62284262, 10824872, 20558596, 48149681, 31162667, 22608274, 26285185, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 963440, 63742255, 10230323, 25515008, 32506414, 6105697, 25980317, 24645129, + ), + u32x8::new_const( + 7162189, 8101249, 14679265, 33443386, 2002396, 8541405, 19442276, 4795881, + ), + u32x8::new_const( + 8116694, 51463069, 4415528, 25599140, 55805721, 39582709, 6719436, 30033839, + ), + u32x8::new_const( + 14468202, 42181869, 25188826, 9639755, 47546189, 62711146, 32762447, 18338064, + ), + u32x8::new_const( + 33880058, 32810909, 8969931, 13095238, 38360605, 40138517, 9246134, 4928058, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 63655588, 17883670, 9410246, 26162761, 5000571, 7349225, 23785252, 32751089, + ), + u32x8::new_const( + 28568737, 10733123, 9342397, 21570673, 54096560, 32467591, 20494687, 21511513, + ), + u32x8::new_const( + 47675157, 47932807, 29250946, 15672208, 59760469, 9945465, 14939287, 18437405, + ), + u32x8::new_const( + 37985267, 8609815, 31573002, 3373596, 47828883, 20834216, 13248616, 24154292, + ), + u32x8::new_const( + 5543543, 29553242, 3386453, 30501150, 25058089, 15236571, 8814395, 32462955, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 39158670, 15322548, 20495103, 3312736, 14557171, 12985179, 8044741, 3176899, + ), + u32x8::new_const( + 24673290, 29693310, 21412266, 18324699, 2154518, 40329021, 17500543, 3954277, + ), + u32x8::new_const( + 36758685, 38738957, 165513, 14691866, 3070475, 10424235, 17096536, 16896898, + ), + u32x8::new_const( + 59790459, 43094586, 8720681, 10423589, 1122030, 31545615, 4463786, 31811293, + ), + u32x8::new_const( + 49778992, 60881044, 20509974, 5832494, 64155961, 31483358, 4511231, 20307815, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 2863373, 40876242, 26865913, 24067353, 15726407, 40919070, 12953902, 9931535, + ), + u32x8::new_const( + 60934877, 42512204, 21649141, 21945190, 52211954, 60984193, 7046207, 5363493, + ), + u32x8::new_const( + 4205971, 64068464, 18197273, 7327176, 51527794, 21166920, 20669933, 11828242, + ), + u32x8::new_const( + 59782815, 49617225, 15379924, 457923, 9320508, 21498914, 3242540, 31563182, + ), + u32x8::new_const( + 27714753, 8664670, 3366162, 26338598, 56775518, 25796006, 13129151, 21388876, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 59276548, 49972346, 16795002, 33455915, 48430097, 53857205, 18627071, 32474471, + ), + u32x8::new_const( + 42160315, 50705892, 13530540, 28012698, 19833221, 55886870, 20191784, 9644313, + ), + u32x8::new_const( + 20372416, 28414713, 24084234, 31804096, 33815377, 36131001, 17251241, 18291088, + ), + u32x8::new_const( + 56234667, 14920441, 2033267, 29572003, 1724043, 45519699, 17873735, 501988, + ), + u32x8::new_const( + 50031659, 31517850, 15697583, 1016845, 43104661, 54769582, 8008601, 27257051, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 52951491, 66542164, 14853573, 30444631, 12045973, 24321813, 16545674, 18160646, + ), + u32x8::new_const( + 60107911, 1126003, 5947677, 19486116, 41119984, 30860440, 7935395, 13354438, + ), + u32x8::new_const( + 17841328, 11063269, 1664538, 26687568, 6268968, 22280371, 17275484, 4523163, + ), + u32x8::new_const( + 15886041, 56799482, 15446552, 21712778, 1005290, 17827215, 4978741, 6854882, + ), + u32x8::new_const( + 34319277, 47731002, 20321804, 28544575, 29591814, 63376351, 24754545, 26001714, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 66783087, 5234346, 46102, 8566476, 19947339, 20180418, 25398238, 3726678, + ), + u32x8::new_const( + 63890180, 46380965, 20674069, 5366544, 59661487, 48406612, 31533614, 7071217, + ), + u32x8::new_const( + 13104676, 1406631, 24326736, 19854367, 61039528, 11019904, 31967425, 19219275, + ), + u32x8::new_const( + 39003597, 30143957, 15351834, 8639435, 57309582, 61436794, 15830475, 10090318, + ), + u32x8::new_const( + 45923044, 6700175, 99413, 21263025, 23762647, 53905481, 6063914, 10065424, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 42822326, 57678669, 4052879, 25452667, 54049411, 2373092, 22337016, 7701046, + ), + u32x8::new_const( + 44382355, 43307377, 16761537, 30373573, 49790216, 23230748, 25655306, 10519391, + ), + u32x8::new_const( + 919475, 59371245, 1273450, 25558666, 9724711, 8556709, 25755845, 10887647, + ), + u32x8::new_const( + 25465699, 44651158, 17658392, 11257418, 29735193, 22885150, 7094716, 26828565, + ), + u32x8::new_const( + 48237389, 47661599, 27054393, 7328070, 27280193, 65616691, 23062005, 4170709, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 26535281, 60238317, 30343788, 25790743, 37993933, 24614372, 9523840, 10401918, + ), + u32x8::new_const( + 2783987, 29468958, 4697011, 19804475, 37246678, 46797720, 10261254, 18942252, + ), + u32x8::new_const( + 58135580, 60247753, 25301938, 6844561, 20949454, 39844754, 4552026, 919057, + ), + u32x8::new_const( + 6694071, 44126261, 32285330, 31370180, 24603698, 53328179, 13971149, 5325636, + ), + u32x8::new_const( + 64879487, 582094, 17982081, 19190425, 24951286, 26923842, 29077174, 33286062, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 54863941, 67016431, 1224043, 23371240, 62940074, 52101083, 13523637, 30366406, + ), + u32x8::new_const( + 36324581, 25407485, 18258623, 4698602, 50300544, 2658516, 26300935, 2611030, + ), + u32x8::new_const( + 27183975, 21791014, 18105064, 9875199, 58118912, 54198635, 6400311, 14767984, + ), + u32x8::new_const( + 33918318, 42937962, 14809334, 22136592, 10636588, 29082337, 29829692, 28549776, + ), + u32x8::new_const( + 61080905, 854212, 12202487, 20004503, 9256495, 6903981, 20567109, 347423, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 41391822, 34336880, 22362564, 14247996, 12115604, 41583344, 7639288, 28910945, + ), + u32x8::new_const( + 62066617, 59758859, 26665947, 11614812, 65737664, 45704543, 30324810, 12868376, + ), + u32x8::new_const( + 17491771, 43589814, 9454919, 26047850, 52629282, 39304244, 3868968, 19296062, + ), + u32x8::new_const( + 17826638, 30413590, 32534225, 32741469, 15012391, 14365713, 33039233, 14791399, + ), + u32x8::new_const( + 64115596, 59197067, 32739005, 23275744, 32954320, 22241406, 20788442, 4942942, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 31956192, 59570132, 2784352, 4237732, 47222312, 4860927, 18658867, 15279314, + ), + u32x8::new_const( + 63240583, 28160478, 23524941, 13390861, 66437406, 57718120, 33345312, 28896298, + ), + u32x8::new_const( + 39026193, 46239965, 21440243, 25070488, 64012383, 60999016, 16517060, 29565907, + ), + u32x8::new_const( + 18118181, 60161496, 4212092, 23976240, 36277753, 62363144, 5816868, 16964362, + ), + u32x8::new_const( + 18196138, 62490693, 281468, 7934713, 56027312, 62015725, 4837237, 32932252, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 29885826, 51028067, 30418143, 33438769, 62542283, 39442528, 31535876, 143299, + ), + u32x8::new_const( + 17143063, 56709783, 14451852, 15782104, 32762665, 14047066, 26295037, 5432487, + ), + u32x8::new_const( + 75151, 533606, 7539077, 30926189, 38410914, 23771680, 4872443, 29199566, + ), + u32x8::new_const( + 61522396, 48934708, 16223126, 207380, 11171993, 47975147, 14164574, 352966, + ), + u32x8::new_const( + 15449006, 56530757, 26796528, 12045834, 63738697, 40667227, 33001582, 9101885, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 43331297, 18431341, 25801195, 17267698, 19365485, 57295202, 22218985, 21284590, + ), + u32x8::new_const( + 2429849, 19152559, 10762172, 22564684, 21880390, 66866426, 20357935, 22641906, + ), + u32x8::new_const( + 19771185, 31652693, 3666117, 28136958, 23624283, 55101502, 6313920, 6783662, + ), + u32x8::new_const( + 3487137, 7092443, 11001876, 26196524, 47319246, 44542068, 17594073, 15027760, + ), + u32x8::new_const( + 49563607, 32191113, 4991283, 25400512, 46539152, 4155103, 32368171, 201203, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 20548943, 14334571, 4073874, 6368588, 53208883, 56484515, 15970071, 25561889, + ), + u32x8::new_const( + 49915097, 44030795, 11202344, 29284344, 60258023, 66225712, 8075764, 12383512, + ), + u32x8::new_const( + 45248912, 4933668, 9592153, 5819559, 31030983, 38174071, 32435814, 7442522, + ), + u32x8::new_const( + 62688129, 48218381, 22089545, 12897361, 21050881, 34278889, 7569163, 3225449, + ), + u32x8::new_const( + 19050183, 51089071, 32935757, 22640195, 66122318, 47144608, 18743677, 25177079, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 41186817, 46681702, 31819867, 32997133, 38559207, 27147015, 30293819, 16762988, + ), + u32x8::new_const( + 24154689, 51762873, 23883879, 13510519, 55338250, 61224161, 11663149, 30803960, + ), + u32x8::new_const( + 18104238, 14117824, 11724021, 21362053, 65704761, 35530242, 13498058, 33522849, + ), + u32x8::new_const( + 63812888, 23995539, 28920539, 24005193, 26412223, 36582218, 4251418, 26160309, + ), + u32x8::new_const( + 16822053, 66064082, 3482145, 31979593, 45937188, 54475379, 612917, 7976478, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 46509314, 55327128, 8944536, 274914, 26432930, 53829300, 21192572, 3569894, + ), + u32x8::new_const( + 20919764, 64356651, 30642344, 17215170, 20335124, 11203745, 18663316, 19024174, + ), + u32x8::new_const( + 59297055, 53842463, 3680204, 9806710, 54004169, 51484914, 29807998, 20134199, + ), + u32x8::new_const( + 14781592, 22628010, 26877930, 25880359, 30434803, 190607, 30184292, 8991040, + ), + u32x8::new_const( + 64400983, 64591751, 854562, 28216111, 20010398, 50414793, 9803872, 22687008, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 15091184, 32550863, 8818643, 4244752, 43123513, 64565526, 408838, 13206998, + ), + u32x8::new_const( + 16405061, 60379639, 31489017, 20949281, 27568751, 38734986, 8364264, 12451020, + ), + u32x8::new_const( + 16005217, 58008076, 1406778, 26546927, 39571784, 56365493, 31274296, 8918790, + ), + u32x8::new_const( + 23271122, 19453469, 27718201, 32742670, 234332, 36785342, 22601675, 14331046, + ), + u32x8::new_const( + 40636025, 22442705, 22115403, 23745859, 41164945, 61012, 12499614, 542137, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 62776018, 32835413, 17373246, 17187309, 54469193, 21770290, 15923753, 28996575, + ), + u32x8::new_const( + 59385210, 63082298, 12568449, 8509004, 9483342, 16105238, 5756054, 26890758, + ), + u32x8::new_const( + 53987996, 38201748, 5521661, 19060159, 18663191, 9093637, 27786835, 31189196, + ), + u32x8::new_const( + 65872678, 43635130, 27903055, 25020300, 65772737, 38110437, 5213502, 21909342, + ), + u32x8::new_const( + 4438979, 9680838, 10212446, 4764184, 13235684, 58245995, 20264570, 21024049, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 60835961, 48209103, 31049052, 4688268, 12426713, 59829045, 22302488, 29008521, + ), + u32x8::new_const( + 50401667, 29716596, 23531224, 7581281, 49071895, 6952617, 14934683, 8218256, + ), + u32x8::new_const( + 1601446, 36631413, 31774811, 29625330, 56786114, 8331539, 23129509, 19783344, + ), + u32x8::new_const( + 59514327, 64513110, 1772300, 5701338, 5737511, 16147555, 9461515, 5703271, + ), + u32x8::new_const( + 33072974, 54300426, 11940114, 1308663, 15627555, 4931627, 28443714, 20924342, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 18135013, 20358426, 4922557, 10015355, 65729669, 34786528, 26248549, 29194359, + ), + u32x8::new_const( + 797666, 34997544, 24316856, 25107230, 24612576, 4761401, 15307321, 32404252, + ), + u32x8::new_const( + 16501152, 60565831, 9487105, 9316022, 24986054, 31917592, 3962024, 2501883, + ), + u32x8::new_const( + 63356796, 50432342, 18044926, 30566881, 42032028, 31415202, 13524600, 16119907, + ), + u32x8::new_const( + 3927286, 57022374, 9265437, 21620772, 19481940, 3806938, 24836192, 14572399, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 10785787, 46564798, 368445, 33181384, 5319843, 52687136, 30347110, 29837357, + ), + u32x8::new_const( + 56436732, 47859251, 24141084, 22250712, 59046084, 4963427, 33463413, 17168859, + ), + u32x8::new_const( + 15512044, 6366740, 4737504, 27644548, 30307977, 25037929, 14593903, 12836490, + ), + u32x8::new_const( + 63878897, 34013023, 5860752, 7244096, 3689461, 57012135, 18389096, 11589351, + ), + u32x8::new_const( + 4682110, 36302830, 653422, 22316819, 14081831, 5657024, 11088376, 24110612, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 39907267, 45940262, 24887471, 18342609, 878445, 40456159, 12019082, 345107, + ), + u32x8::new_const( + 12794982, 28893944, 9447505, 11387200, 16961963, 13916996, 10893728, 25898006, + ), + u32x8::new_const( + 44934162, 53465865, 3583620, 1102334, 53917811, 63478576, 2426066, 10389549, + ), + u32x8::new_const( + 45096036, 37595344, 19367718, 20257175, 10280866, 41653449, 27665642, 375926, + ), + u32x8::new_const( + 45847901, 24064074, 32494820, 32204556, 10720704, 51079060, 1297436, 29853825, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 66303987, 36060363, 16494578, 24962147, 11971403, 49538586, 25060560, 1964341, + ), + u32x8::new_const( + 25988481, 27641502, 24909517, 27237087, 66646363, 52777626, 16360849, 10459972, + ), + u32x8::new_const( + 43930529, 34374176, 31225968, 8807030, 10394758, 35904854, 25325589, 19335583, + ), + u32x8::new_const( + 25094697, 34380951, 20051185, 32287161, 11739332, 53887441, 30517319, 26601892, + ), + u32x8::new_const( + 8868546, 35635502, 32513071, 28248087, 51946989, 14222744, 19198839, 23261841, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 51218008, 5070126, 11046681, 5320810, 61212079, 34104447, 23895089, 6460727, + ), + u32x8::new_const( + 39843528, 46278671, 10426120, 25624792, 66658766, 37140083, 28933107, 12969597, + ), + u32x8::new_const( + 59635793, 40220191, 5751421, 173680, 58321825, 740337, 1412847, 7682623, + ), + u32x8::new_const( + 975962, 56440763, 20812276, 22631115, 49095824, 19883130, 2419746, 31043648, + ), + u32x8::new_const( + 66208703, 39669328, 22525915, 3748897, 65994776, 34533552, 8126286, 18326047, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 64176557, 3912400, 19351673, 30068471, 31190055, 24221683, 33142424, 28698542, + ), + u32x8::new_const( + 34784792, 4109933, 3867193, 19557314, 2112512, 32715890, 24550117, 16595976, + ), + u32x8::new_const( + 35542761, 48024875, 10925431, 31526577, 66577735, 23189821, 13375709, 1735095, + ), + u32x8::new_const( + 59699254, 43854093, 29783239, 24777271, 19600372, 39924461, 2896720, 1472185, + ), + u32x8::new_const( + 56389656, 35980854, 33172342, 1370336, 23707480, 57654949, 7850973, 12655016, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 38372660, 57101970, 7044964, 12732710, 57535705, 6043201, 30858914, 10946592, + ), + u32x8::new_const( + 21023468, 6946992, 26403324, 23901823, 35695559, 23440687, 4763891, 6514074, + ), + u32x8::new_const( + 28662273, 30933699, 9352242, 26354829, 37402243, 3145176, 8770289, 525937, + ), + u32x8::new_const( + 54933102, 36695832, 3281859, 4755022, 23043294, 32794379, 15618886, 23602412, + ), + u32x8::new_const( + 9931565, 29897140, 2480737, 24193701, 7833615, 2284939, 893926, 13421882, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 22917795, 22088359, 28978099, 19794863, 60542318, 29878494, 31053731, 9080720, + ), + u32x8::new_const( + 23679072, 52547035, 28424916, 20647332, 4008761, 28267029, 12961289, 1589095, + ), + u32x8::new_const( + 55616194, 26678929, 14998265, 23274397, 54625466, 46244264, 28627706, 33030665, + ), + u32x8::new_const( + 11527330, 6449415, 26531607, 3472938, 41541592, 62607682, 19862690, 20564723, + ), + u32x8::new_const( + 32843805, 49066843, 28425824, 19521495, 48792073, 48242878, 27392443, 13175986, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 16185025, 61537525, 2961305, 1492442, 25123147, 3095034, 31896958, 33089615, + ), + u32x8::new_const( + 64748157, 18336595, 16522231, 25426312, 65718949, 35485695, 30554083, 10205918, + ), + u32x8::new_const( + 39626934, 39271045, 16420458, 9826240, 56483981, 27128085, 3783403, 13360006, + ), + u32x8::new_const( + 30793778, 66771960, 17241420, 6564573, 61102581, 29974476, 32385512, 9011754, + ), + u32x8::new_const( + 28068166, 11862220, 14323567, 12380617, 52090465, 16029056, 24495309, 21409233, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 59411973, 57437124, 11695483, 17586857, 16108987, 43449109, 31098002, 6248476, + ), + u32x8::new_const( + 42258047, 61595931, 29308533, 11742653, 43042345, 27373650, 30165249, 21929989, + ), + u32x8::new_const( + 49907221, 9620337, 21888081, 20981082, 56288861, 61562203, 33223566, 3582446, + ), + u32x8::new_const( + 57535017, 41003416, 22080416, 14463796, 65518565, 18127889, 24370863, 33332664, + ), + u32x8::new_const( + 66655380, 6430175, 471782, 11947673, 30596400, 18898659, 15930721, 4211851, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 6757410, 65455566, 13584784, 11362173, 10797127, 24451471, 19541370, 29309435, + ), + u32x8::new_const( + 40360156, 17685025, 18326181, 3846903, 13693365, 63049479, 31900359, 23385063, + ), + u32x8::new_const( + 52455038, 57513503, 22163311, 27095042, 48610726, 66454160, 12085341, 26357004, + ), + u32x8::new_const( + 22097042, 14063840, 6705778, 14342902, 66139825, 20702105, 31279090, 7495745, + ), + u32x8::new_const( + 27360710, 49314837, 18774847, 7146436, 37066216, 42004961, 22409916, 10524446, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 1497507, 33054449, 11839906, 2960428, 40538463, 18884538, 25018820, 4073970, + ), + u32x8::new_const( + 54484385, 43640735, 2808257, 20710708, 39840730, 27222424, 21783544, 11848522, + ), + u32x8::new_const( + 45765237, 48200555, 9299019, 9393151, 34818188, 56098995, 13575233, 21012731, + ), + u32x8::new_const( + 4265428, 49627650, 24960282, 9425650, 47883651, 2797524, 11853190, 22877329, + ), + u32x8::new_const( + 25008173, 64199503, 380047, 12107343, 12329448, 11914399, 764281, 29687002, + ), + ])), + CachedPoint(FieldElement2625x4([ + u32x8::new_const( + 35889734, 23047226, 4022841, 7017445, 7274086, 53316179, 25100176, 15310676, + ), + u32x8::new_const( + 42409427, 30270106, 6823853, 31551384, 40645017, 66489807, 18021817, 32669351, + ), + u32x8::new_const( + 39827134, 43680850, 28297996, 20258133, 26058742, 52643238, 22238331, 21690533, + ), + u32x8::new_const( + 60808002, 17499995, 30042246, 29310584, 48219954, 29389518, 8680514, 17844709, + ), + u32x8::new_const( + 6452896, 50116553, 9532047, 26821214, 44524351, 50428429, 21904953, 12608048, + ), + ])), +]); diff --git a/src/backend/vector/avx2/edwards.rs b/curve25519-dalek/src/backend/vector/avx2/edwards.rs similarity index 87% rename from src/backend/vector/avx2/edwards.rs rename to curve25519-dalek/src/backend/vector/avx2/edwards.rs index 821d51613..fd70d7d2f 100644 --- a/src/backend/vector/avx2/edwards.rs +++ b/curve25519-dalek/src/backend/vector/avx2/edwards.rs @@ -35,16 +35,20 @@ #![allow(non_snake_case)] -use core::convert::From; use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; -use edwards; -use window::{LookupTable, NafLookupTable5, NafLookupTable8}; +use curve25519_dalek_derive::unsafe_target_feature; -use traits::Identity; +use crate::edwards; +use crate::window::{LookupTable, NafLookupTable5}; + +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +use crate::window::NafLookupTable8; + +use crate::traits::Identity; use super::constants; use super::field::{FieldElement2625x4, Lanes, Shuffle}; @@ -59,12 +63,14 @@ use super::field::{FieldElement2625x4, Lanes, Shuffle}; #[derive(Copy, Clone, Debug)] pub struct ExtendedPoint(pub(super) FieldElement2625x4); +#[unsafe_target_feature("avx2")] impl From for ExtendedPoint { fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { ExtendedPoint(FieldElement2625x4::new(&P.X, &P.Y, &P.Z, &P.T)) } } +#[unsafe_target_feature("avx2")] impl From for edwards::EdwardsPoint { fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { let tmp = P.0.split(); @@ -77,6 +83,7 @@ impl From for edwards::EdwardsPoint { } } +#[unsafe_target_feature("avx2")] impl ConditionallySelectable for ExtendedPoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { ExtendedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) @@ -87,18 +94,21 @@ impl ConditionallySelectable for ExtendedPoint { } } +#[unsafe_target_feature("avx2")] impl Default for ExtendedPoint { fn default() -> ExtendedPoint { ExtendedPoint::identity() } } +#[unsafe_target_feature("avx2")] impl Identity for ExtendedPoint { fn identity() -> ExtendedPoint { constants::EXTENDEDPOINT_IDENTITY } } +#[unsafe_target_feature("avx2")] impl ExtendedPoint { /// Compute the double of this point. pub fn double(&self) -> ExtendedPoint { @@ -134,7 +144,7 @@ impl ExtendedPoint { // ======================= // S5 S6 S8 S9 - let zero = FieldElement2625x4::zero(); + let zero = FieldElement2625x4::ZERO; let S_1 = tmp1.shuffle(Shuffle::AAAA); let S_2 = tmp1.shuffle(Shuffle::BBBB); @@ -184,6 +194,7 @@ impl ExtendedPoint { #[derive(Copy, Clone, Debug)] pub struct CachedPoint(pub(super) FieldElement2625x4); +#[unsafe_target_feature("avx2")] impl From for CachedPoint { fn from(P: ExtendedPoint) -> CachedPoint { let mut x = P.0; @@ -202,18 +213,21 @@ impl From for CachedPoint { } } +#[unsafe_target_feature("avx2")] impl Default for CachedPoint { fn default() -> CachedPoint { CachedPoint::identity() } } +#[unsafe_target_feature("avx2")] impl Identity for CachedPoint { fn identity() -> CachedPoint { constants::CACHEDPOINT_IDENTITY } } +#[unsafe_target_feature("avx2")] impl ConditionallySelectable for CachedPoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { CachedPoint(FieldElement2625x4::conditional_select(&a.0, &b.0, choice)) @@ -224,7 +238,8 @@ impl ConditionallySelectable for CachedPoint { } } -impl<'a> Neg for &'a CachedPoint { +#[unsafe_target_feature("avx2")] +impl Neg for &CachedPoint { type Output = CachedPoint; /// Lazily negate the point. /// @@ -238,11 +253,12 @@ impl<'a> Neg for &'a CachedPoint { } } -impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { +#[unsafe_target_feature("avx2")] +impl Add<&CachedPoint> for &ExtendedPoint { type Output = ExtendedPoint; /// Add an `ExtendedPoint` and a `CachedPoint`. - fn add(self, other: &'b CachedPoint) -> ExtendedPoint { + fn add(self, other: &CachedPoint) -> ExtendedPoint { // The coefficients of an `ExtendedPoint` are reduced after // every operation. If the `CachedPoint` was negated, its // coefficients grow by one bit. So on input, `self` is @@ -275,7 +291,8 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { } } -impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { +#[unsafe_target_feature("avx2")] +impl Sub<&CachedPoint> for &ExtendedPoint { type Output = ExtendedPoint; /// Implement subtraction by negating the point and adding. @@ -283,13 +300,14 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { /// Empirically, this seems about the same cost as a custom /// subtraction impl (maybe because the benefit is cancelled by /// increased code size?) - fn sub(self, other: &'b CachedPoint) -> ExtendedPoint { + fn sub(self, other: &CachedPoint) -> ExtendedPoint { self + &(-other) } } -impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { - fn from(point: &'a edwards::EdwardsPoint) -> Self { +#[unsafe_target_feature("avx2")] +impl From<&edwards::EdwardsPoint> for LookupTable { + fn from(point: &edwards::EdwardsPoint) -> Self { let P = ExtendedPoint::from(*point); let mut points = [CachedPoint::from(P); 8]; for i in 0..7 { @@ -299,8 +317,9 @@ impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { } } -impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { - fn from(point: &'a edwards::EdwardsPoint) -> Self { +#[unsafe_target_feature("avx2")] +impl From<&edwards::EdwardsPoint> for NafLookupTable5 { + fn from(point: &edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); let mut Ai = [CachedPoint::from(A); 8]; let A2 = A.double(); @@ -312,8 +331,10 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { } } -impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { - fn from(point: &'a edwards::EdwardsPoint) -> Self { +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +#[unsafe_target_feature("avx2")] +impl From<&edwards::EdwardsPoint> for NafLookupTable8 { + fn from(point: &edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); let mut Ai = [CachedPoint::from(A); 64]; let A2 = A.double(); @@ -325,19 +346,21 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { } } +#[cfg(target_feature = "avx2")] #[cfg(test)] mod test { use super::*; + #[rustfmt::skip] // keep alignment of some S* calculations fn serial_add(P: edwards::EdwardsPoint, Q: edwards::EdwardsPoint) -> edwards::EdwardsPoint { - use backend::serial::u64::field::FieldElement51; + use crate::backend::serial::u64::field::FieldElement51; let (X1, Y1, Z1, T1) = (P.X, P.Y, P.Z, P.T); let (X2, Y2, Z2, T2) = (Q.X, Q.Y, Q.Z, Q.T); macro_rules! print_var { ($x:ident) => { - println!("{} = {:?}", stringify!($x), $x.to_bytes()); + println!("{} = {:?}", stringify!($x), $x.as_bytes()); }; } @@ -420,8 +443,8 @@ mod test { #[test] fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; println!("Testing id +- id"); let P = edwards::EdwardsPoint::identity(); @@ -440,7 +463,7 @@ mod test { println!("Testing B +- kB"); let P = constants::ED25519_BASEPOINT_POINT; - let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + let Q = constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); addition_test_helper(P, Q); } @@ -449,7 +472,7 @@ mod test { macro_rules! print_var { ($x:ident) => { - println!("{} = {:?}", stringify!($x), $x.to_bytes()); + println!("{} = {:?}", stringify!($x), $x.as_bytes()); }; } @@ -507,8 +530,8 @@ mod test { #[test] fn vector_doubling_vs_serial_doubling_vs_edwards_extendedpoint() { - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; println!("Testing [2]id"); let P = edwards::EdwardsPoint::identity(); @@ -519,16 +542,18 @@ mod test { doubling_test_helper(P); println!("Testing [2]([k]B)"); - let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + let P = constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); doubling_test_helper(P); } + #[cfg(any(feature = "precomputed-tables", feature = "alloc"))] #[test] fn basepoint_odd_lookup_table_verify() { - use constants; - use backend::vector::avx2::constants::{BASEPOINT_ODD_LOOKUP_TABLE}; + use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; + use crate::constants; - let basepoint_odd_table = NafLookupTable8::::from(&constants::ED25519_BASEPOINT_POINT); + let basepoint_odd_table = + NafLookupTable8::::from(&constants::ED25519_BASEPOINT_POINT); println!("basepoint_odd_lookup_table = {:?}", basepoint_odd_table); let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; diff --git a/src/backend/vector/avx2/field.rs b/curve25519-dalek/src/backend/vector/avx2/field.rs similarity index 75% rename from src/backend/vector/avx2/field.rs rename to curve25519-dalek/src/backend/vector/avx2/field.rs index 94a06eebd..d6851580f 100644 --- a/src/backend/vector/avx2/field.rs +++ b/curve25519-dalek/src/backend/vector/avx2/field.rs @@ -40,11 +40,15 @@ const C_LANES64: u8 = 0b00_11_00_00; #[allow(unused)] const D_LANES64: u8 = 0b11_00_00_00; +use crate::backend::vector::packed_simd::{u32x8, u64x4}; use core::ops::{Add, Mul, Neg}; -use packed_simd::{i32x8, u32x8, u64x4, IntoBits}; -use backend::vector::avx2::constants::{P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO}; -use backend::serial::u64::field::FieldElement51; +use crate::backend::serial::u64::field::FieldElement51; +use crate::backend::vector::avx2::constants::{ + P_TIMES_16_HI, P_TIMES_16_LO, P_TIMES_2_HI, P_TIMES_2_LO, +}; + +use curve25519_dalek_derive::unsafe_target_feature; /// Unpack 32-bit lanes into 64-bit lanes: /// ```ascii,no_run @@ -55,16 +59,17 @@ use backend::serial::u64::field::FieldElement51; /// (a0, 0, b0, 0, c0, 0, d0, 0) /// (a1, 0, b1, 0, c1, 0, d1, 0) /// ``` +#[unsafe_target_feature("avx2")] #[inline(always)] fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { let a: u32x8; let b: u32x8; - let zero = i32x8::new(0, 0, 0, 0, 0, 0, 0, 0); + let zero = u32x8::splat(0); unsafe { use core::arch::x86_64::_mm256_unpackhi_epi32; use core::arch::x86_64::_mm256_unpacklo_epi32; - a = _mm256_unpacklo_epi32(src.into_bits(), zero.into_bits()).into_bits(); - b = _mm256_unpackhi_epi32(src.into_bits(), zero.into_bits()).into_bits(); + a = _mm256_unpacklo_epi32(src.into(), zero.into()).into(); + b = _mm256_unpackhi_epi32(src.into(), zero.into()).into(); } (a, b) } @@ -78,6 +83,7 @@ fn unpack_pair(src: u32x8) -> (u32x8, u32x8) { /// ```ascii,no_run /// (a0, b0, a1, b1, c0, d0, c1, d1) /// ``` +#[unsafe_target_feature("avx2")] #[inline(always)] fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { unsafe { @@ -87,13 +93,13 @@ fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { // Input: x = (a0, 0, b0, 0, c0, 0, d0, 0) // Input: y = (a1, 0, b1, 0, c1, 0, d1, 0) - let x_shuffled = _mm256_shuffle_epi32(x.into_bits(), 0b11_01_10_00); - let y_shuffled = _mm256_shuffle_epi32(y.into_bits(), 0b10_00_11_01); + let x_shuffled = _mm256_shuffle_epi32(x.into(), 0b11_01_10_00); + let y_shuffled = _mm256_shuffle_epi32(y.into(), 0b10_00_11_01); // x' = (a0, b0, 0, 0, c0, d0, 0, 0) // y' = ( 0, 0, a1, b1, 0, 0, c1, d1) - return _mm256_blend_epi32(x_shuffled, y_shuffled, 0b11001100).into_bits(); + _mm256_blend_epi32(x_shuffled, y_shuffled, 0b11001100).into() } } @@ -103,6 +109,7 @@ fn repack_pair(x: u32x8, y: u32x8) -> u32x8 { /// It's used to specify blend operations without /// having to know details about the data layout of the /// `FieldElement2625x4`. +#[allow(clippy::upper_case_acronyms)] #[derive(Copy, Clone, Debug)] pub enum Lanes { C, @@ -120,6 +127,7 @@ pub enum Lanes { /// The enum variants are named by what they do to a vector \\( /// (A,B,C,D) \\); for instance, `Shuffle::BADC` turns \\( (A, B, C, /// D) \\) into \\( (B, A, D, C) \\). +#[allow(clippy::upper_case_acronyms)] #[derive(Copy, Clone, Debug)] pub enum Shuffle { AAAA, @@ -147,6 +155,7 @@ pub struct FieldElement2625x4(pub(crate) [u32x8; 5]); use subtle::Choice; use subtle::ConditionallySelectable; +#[unsafe_target_feature("avx2")] impl ConditionallySelectable for FieldElement2625x4 { fn conditional_select( a: &FieldElement2625x4, @@ -164,11 +173,7 @@ impl ConditionallySelectable for FieldElement2625x4 { ]) } - fn conditional_assign( - &mut self, - other: &FieldElement2625x4, - choice: Choice, - ) { + fn conditional_assign(&mut self, other: &FieldElement2625x4, choice: Choice) { let mask = (-(choice.unwrap_u8() as i32)) as u32; let mask_vec = u32x8::splat(mask); self.0[0] ^= mask_vec & (self.0[0] ^ other.0[0]); @@ -179,20 +184,24 @@ impl ConditionallySelectable for FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl FieldElement2625x4 { + pub const ZERO: FieldElement2625x4 = FieldElement2625x4([u32x8::splat_const::<0>(); 5]); + /// Split this vector into an array of four (serial) field /// elements. + #[rustfmt::skip] // keep alignment of extracted lanes pub fn split(&self) -> [FieldElement51; 4] { - let mut out = [FieldElement51::zero(); 4]; + let mut out = [FieldElement51::ZERO; 4]; for i in 0..5 { - let a_2i = self.0[i].extract(0) as u64; // - let b_2i = self.0[i].extract(1) as u64; // - let a_2i_1 = self.0[i].extract(2) as u64; // `. - let b_2i_1 = self.0[i].extract(3) as u64; // | pre-swapped to avoid - let c_2i = self.0[i].extract(4) as u64; // | a cross lane shuffle - let d_2i = self.0[i].extract(5) as u64; // .' - let c_2i_1 = self.0[i].extract(6) as u64; // - let d_2i_1 = self.0[i].extract(7) as u64; // + let a_2i = self.0[i].extract::<0>() as u64; // + let b_2i = self.0[i].extract::<1>() as u64; // + let a_2i_1 = self.0[i].extract::<2>() as u64; // `. + let b_2i_1 = self.0[i].extract::<3>() as u64; // | pre-swapped to avoid + let c_2i = self.0[i].extract::<4>() as u64; // | a cross lane shuffle + let d_2i = self.0[i].extract::<5>() as u64; // .' + let c_2i_1 = self.0[i].extract::<6>() as u64; // + let d_2i_1 = self.0[i].extract::<7>() as u64; // out[0].0[i] = a_2i + (a_2i_1 << 26); out[1].0[i] = b_2i + (b_2i_1 << 26); @@ -230,7 +239,7 @@ impl FieldElement2625x4 { // Note that this gets turned into a generic LLVM // shuffle-by-constants, which can be lowered to a simpler // instruction than a generic permute. - _mm256_permutevar8x32_epi32(x.into_bits(), c.into_bits()).into_bits() + _mm256_permutevar8x32_epi32(x.into(), c.into()).into() } } @@ -276,37 +285,29 @@ impl FieldElement2625x4 { // which does not require a shuffle immediate but *is* lowered // to immediate shuffles anyways). match control { - Lanes::C => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), C_LANES as i32).into_bits() - } - Lanes::D => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), D_LANES as i32).into_bits() - } + Lanes::C => _mm256_blend_epi32(x.into(), y.into(), C_LANES as i32).into(), + Lanes::D => _mm256_blend_epi32(x.into(), y.into(), D_LANES as i32).into(), Lanes::AD => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | D_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (A_LANES | D_LANES) as i32).into() } Lanes::AB => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | B_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (A_LANES | B_LANES) as i32).into() } Lanes::AC => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (A_LANES | C_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (A_LANES | C_LANES) as i32).into() } Lanes::CD => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (C_LANES | D_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (C_LANES | D_LANES) as i32).into() } Lanes::BC => { - _mm256_blend_epi32(x.into_bits(), y.into_bits(), (B_LANES | C_LANES) as i32) - .into_bits() + _mm256_blend_epi32(x.into(), y.into(), (B_LANES | C_LANES) as i32).into() } Lanes::ABCD => _mm256_blend_epi32( - x.into_bits(), - y.into_bits(), + x.into(), + y.into(), (A_LANES | B_LANES | C_LANES | D_LANES) as i32, - ).into_bits(), + ) + .into(), } } } @@ -320,11 +321,6 @@ impl FieldElement2625x4 { ]) } - /// Construct a vector of zeros. - pub fn zero() -> FieldElement2625x4 { - FieldElement2625x4([u32x8::splat(0); 5]) - } - /// Convenience wrapper around `new(x,x,x,x)`. pub fn splat(x: &FieldElement51) -> FieldElement2625x4 { FieldElement2625x4::new(x, x, x, x) @@ -335,6 +331,7 @@ impl FieldElement2625x4 { /// # Postconditions /// /// The resulting `FieldElement2625x4` is bounded with \\( b < 0.0002 \\). + #[rustfmt::skip] // keep alignment of computed lanes pub fn new( x0: &FieldElement51, x1: &FieldElement51, @@ -343,6 +340,7 @@ impl FieldElement2625x4 { ) -> FieldElement2625x4 { let mut buf = [u32x8::splat(0); 5]; let low_26_bits = (1 << 26) - 1; + #[allow(clippy::needless_range_loop)] for i in 0..5 { let a_2i = (x0.0[i] & low_26_bits) as u32; let a_2i_1 = (x0.0[i] >> 26) as u32; @@ -412,7 +410,7 @@ impl FieldElement2625x4 { /// The coefficients of the result are bounded with \\( b < 0.0002 \\). #[inline] pub fn reduce(&self) -> FieldElement2625x4 { - let shifts = i32x8::new(26, 26, 25, 25, 26, 26, 25, 25); + let shifts = u32x8::new(26, 26, 25, 25, 26, 26, 25, 25); let masks = u32x8::new( (1 << 26) - 1, (1 << 26) - 1, @@ -432,11 +430,11 @@ impl FieldElement2625x4 { // The carryouts are bounded by 2^(32 - 25) = 2^7. let rotated_carryout = |v: u32x8| -> u32x8 { unsafe { - use core::arch::x86_64::_mm256_srlv_epi32; use core::arch::x86_64::_mm256_shuffle_epi32; + use core::arch::x86_64::_mm256_srlv_epi32; - let c = _mm256_srlv_epi32(v.into_bits(), shifts.into_bits()); - _mm256_shuffle_epi32(c, 0b01_00_11_10).into_bits() + let c = _mm256_srlv_epi32(v.into(), shifts.into()); + _mm256_shuffle_epi32(c, 0b01_00_11_10).into() } }; @@ -457,7 +455,7 @@ impl FieldElement2625x4 { let combine = |v_lo: u32x8, v_hi: u32x8| -> u32x8 { unsafe { use core::arch::x86_64::_mm256_blend_epi32; - _mm256_blend_epi32(v_lo.into_bits(), v_hi.into_bits(), 0b11_00_11_00).into_bits() + _mm256_blend_epi32(v_lo.into(), v_hi.into(), 0b11_00_11_00).into() } }; @@ -487,21 +485,21 @@ impl FieldElement2625x4 { // // c98 = (c(x9), c(y9), c(x8), c(y8), c(z9), c(w9), c(z8), c(w8)); // c9_spread = (c(x9), c(x8), c(y9), c(y8), c(z9), c(z8), c(w9), c(w8)). - let c9_spread = _mm256_shuffle_epi32(c98.into_bits(), 0b11_01_10_00); + let c9_spread = _mm256_shuffle_epi32(c98.into(), 0b11_01_10_00); // Since the carryouts are bounded by 2^7, their products with 19 // are bounded by 2^11.25. This means that // // c9_19_spread = (19*c(x9), 0, 19*c(y9), 0, 19*c(z9), 0, 19*c(w9), 0). - let c9_19_spread = _mm256_mul_epu32(c9_spread, u64x4::splat(19).into_bits()); + let c9_19_spread = _mm256_mul_epu32(c9_spread, u64x4::splat(19).into()); // Unshuffle: // c9_19 = (19*c(x9), 19*c(y9), 0, 0, 19*c(z9), 19*c(w9), 0, 0). - _mm256_shuffle_epi32(c9_19_spread, 0b11_01_10_00).into_bits() + _mm256_shuffle_epi32(c9_19_spread, 0b11_01_10_00).into() }; // Add the final carryin. - v[0] = v[0] + c9_19; + v[0] += c9_19; // Each output coefficient has exactly one carryin, which is // bounded by 2^11.25, so they are bounded as @@ -519,6 +517,7 @@ impl FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). #[inline] + #[rustfmt::skip] // keep alignment of carry chain fn reduce64(mut z: [u64x4; 10]) -> FieldElement2625x4 { // These aren't const because splat isn't a const fn let LOW_25_BITS: u64x4 = u64x4::splat((1 << 25) - 1); @@ -529,12 +528,12 @@ impl FieldElement2625x4 { debug_assert!(i < 9); if i % 2 == 0 { // Even limbs have 26 bits - z[i + 1] = z[i + 1] + (z[i] >> 26); - z[i] = z[i] & LOW_26_BITS; + z[i + 1] += z[i].shr::<26>(); + z[i] &= LOW_26_BITS; } else { // Odd limbs have 25 bits - z[i + 1] = z[i + 1] + (z[i] >> 25); - z[i] = z[i] & LOW_25_BITS; + z[i + 1] += z[i].shr::<25>(); + z[i] &= LOW_25_BITS; } }; @@ -556,20 +555,17 @@ impl FieldElement2625x4 { // big. To ensure c < 2^32, we would need z[9] < 2^57. // Instead, we split the carry in two, with c = c_0 + c_1*2^26. - let c = z[9] >> 25; - z[9] = z[9] & LOW_25_BITS; + let c = z[9].shr::<25>(); + z[9] &= LOW_25_BITS; let mut c0: u64x4 = c & LOW_26_BITS; // c0 < 2^26; - let mut c1: u64x4 = c >> 26; // c1 < 2^(39-26) = 2^13; + let mut c1: u64x4 = c.shr::<26>(); // c1 < 2^(39-26) = 2^13; - unsafe { - use core::arch::x86_64::_mm256_mul_epu32; - let x19 = u64x4::splat(19); - c0 = _mm256_mul_epu32(c0.into_bits(), x19.into_bits()).into_bits(); // c0 < 2^30.25 - c1 = _mm256_mul_epu32(c1.into_bits(), x19.into_bits()).into_bits(); // c1 < 2^17.25 - } + let x19 = u64x4::splat(19); + c0 = u32x8::from(c0).mul32(u32x8::from(x19)); + c1 = u32x8::from(c1).mul32(u32x8::from(x19)); - z[0] = z[0] + c0; // z0 < 2^26 + 2^30.25 < 2^30.33 - z[1] = z[1] + c1; // z1 < 2^25 + 2^17.25 < 2^25.0067 + z[0] += c0; // z0 < 2^26 + 2^30.25 < 2^30.33 + z[1] += c1; // z1 < 2^25 + 2^17.25 < 2^25.0067 carry(&mut z, 0); // z0 < 2^26, z1 < 2^25.0067 + 2^4.33 = 2^25.007 // The output coefficients are bounded with @@ -580,11 +576,11 @@ impl FieldElement2625x4 { // // So the packed result is bounded with b = 0.007. FieldElement2625x4([ - repack_pair(z[0].into_bits(), z[1].into_bits()), - repack_pair(z[2].into_bits(), z[3].into_bits()), - repack_pair(z[4].into_bits(), z[5].into_bits()), - repack_pair(z[6].into_bits(), z[7].into_bits()), - repack_pair(z[8].into_bits(), z[9].into_bits()), + repack_pair(z[0].into(), z[1].into()), + repack_pair(z[2].into(), z[3].into()), + repack_pair(z[4].into(), z[5].into()), + repack_pair(z[6].into(), z[7].into()), + repack_pair(z[8].into(), z[9].into()), ]) } @@ -597,17 +593,16 @@ impl FieldElement2625x4 { /// # Postconditions /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). + #[rustfmt::skip] // keep alignment of z* calculations pub fn square_and_negate_D(&self) -> FieldElement2625x4 { #[inline(always)] fn m(x: u32x8, y: u32x8) -> u64x4 { - use core::arch::x86_64::_mm256_mul_epu32; - unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + x.mul32(y) } #[inline(always)] fn m_lo(x: u32x8, y: u32x8) -> u32x8 { - use core::arch::x86_64::_mm256_mul_epu32; - unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + x.mul32(y).into() } let v19 = u32x8::new(19, 0, 19, 0, 19, 0, 19, 0); @@ -618,31 +613,31 @@ impl FieldElement2625x4 { let (x6, x7) = unpack_pair(self.0[3]); let (x8, x9) = unpack_pair(self.0[4]); - let x0_2 = x0 << 1; - let x1_2 = x1 << 1; - let x2_2 = x2 << 1; - let x3_2 = x3 << 1; - let x4_2 = x4 << 1; - let x5_2 = x5 << 1; - let x6_2 = x6 << 1; - let x7_2 = x7 << 1; - - let x5_19 = m_lo(v19, x5); - let x6_19 = m_lo(v19, x6); - let x7_19 = m_lo(v19, x7); - let x8_19 = m_lo(v19, x8); - let x9_19 = m_lo(v19, x9); - - let mut z0 = m(x0, x0) + m(x2_2,x8_19) + m(x4_2,x6_19) + ((m(x1_2,x9_19) + m(x3_2,x7_19) + m(x5,x5_19)) << 1); - let mut z1 = m(x0_2,x1) + m(x3_2,x8_19) + m(x5_2,x6_19) + ((m(x2,x9_19) + m(x4,x7_19)) << 1); - let mut z2 = m(x0_2,x2) + m(x1_2,x1) + m(x4_2,x8_19) + m(x6,x6_19) + ((m(x3_2,x9_19) + m(x5_2,x7_19)) << 1); - let mut z3 = m(x0_2,x3) + m(x1_2,x2) + m(x5_2,x8_19) + ((m(x4,x9_19) + m(x6,x7_19)) << 1); - let mut z4 = m(x0_2,x4) + m(x1_2,x3_2) + m(x2, x2) + m(x6_2,x8_19) + ((m(x5_2,x9_19) + m(x7,x7_19)) << 1); - let mut z5 = m(x0_2,x5) + m(x1_2,x4) + m(x2_2,x3) + m(x7_2,x8_19) + ((m(x6,x9_19)) << 1); - let mut z6 = m(x0_2,x6) + m(x1_2,x5_2) + m(x2_2,x4) + m(x3_2,x3) + m(x8,x8_19) + ((m(x7_2,x9_19)) << 1); - let mut z7 = m(x0_2,x7) + m(x1_2,x6) + m(x2_2,x5) + m(x3_2,x4) + ((m(x8,x9_19)) << 1); - let mut z8 = m(x0_2,x8) + m(x1_2,x7_2) + m(x2_2,x6) + m(x3_2,x5_2) + m(x4,x4) + ((m(x9,x9_19)) << 1); - let mut z9 = m(x0_2,x9) + m(x1_2,x8) + m(x2_2,x7) + m(x3_2,x6) + m(x4_2,x5); + let x0_2 = x0.shl::<1>(); + let x1_2 = x1.shl::<1>(); + let x2_2 = x2.shl::<1>(); + let x3_2 = x3.shl::<1>(); + let x4_2 = x4.shl::<1>(); + let x5_2 = x5.shl::<1>(); + let x6_2 = x6.shl::<1>(); + let x7_2 = x7.shl::<1>(); + + let x5_19 = m_lo(v19, x5); + let x6_19 = m_lo(v19, x6); + let x7_19 = m_lo(v19, x7); + let x8_19 = m_lo(v19, x8); + let x9_19 = m_lo(v19, x9); + + let mut z0 = m(x0, x0) + m(x2_2, x8_19) + m(x4_2, x6_19) + ((m(x1_2, x9_19) + m(x3_2, x7_19) + m(x5, x5_19)).shl::<1>()); + let mut z1 = m(x0_2, x1) + m(x3_2, x8_19) + m(x5_2, x6_19) + ((m(x2, x9_19) + m(x4, x7_19)).shl::<1>()); + let mut z2 = m(x0_2, x2) + m(x1_2, x1) + m(x4_2, x8_19) + m(x6, x6_19) + ((m(x3_2, x9_19) + m(x5_2, x7_19)).shl::<1>()); + let mut z3 = m(x0_2, x3) + m(x1_2, x2) + m(x5_2, x8_19) + ((m(x4, x9_19) + m(x6, x7_19)).shl::<1>()); + let mut z4 = m(x0_2, x4) + m(x1_2, x3_2) + m(x2, x2) + m(x6_2, x8_19) + ((m(x5_2, x9_19) + m(x7, x7_19)).shl::<1>()); + let mut z5 = m(x0_2, x5) + m(x1_2, x4) + m(x2_2, x3) + m(x7_2, x8_19) + ((m(x6, x9_19)).shl::<1>()); + let mut z6 = m(x0_2, x6) + m(x1_2, x5_2) + m(x2_2, x4) + m(x3_2, x3) + m(x8, x8_19) + ((m(x7_2, x9_19)).shl::<1>()); + let mut z7 = m(x0_2, x7) + m(x1_2, x6) + m(x2_2, x5) + m(x3_2, x4) + ((m(x8, x9_19)).shl::<1>()); + let mut z8 = m(x0_2, x8) + m(x1_2, x7_2) + m(x2_2, x6) + m(x3_2, x5_2) + m(x4, x4) + ((m(x9, x9_19)).shl::<1>()); + let mut z9 = m(x0_2, x9) + m(x1_2, x8) + m(x2_2, x7) + m(x3_2, x6) + m(x4_2, x5) ; // The biggest z_i is bounded as z_i < 249*2^(51 + 2*b); // if b < 1.5 we get z_i < 4485585228861014016. @@ -667,7 +662,7 @@ impl FieldElement2625x4 { let negate_D = |x: u64x4, p: u64x4| -> u64x4 { unsafe { use core::arch::x86_64::_mm256_blend_epi32; - _mm256_blend_epi32(x.into_bits(), (p - x).into_bits(), D_LANES64 as i32).into_bits() + _mm256_blend_epi32(x.into(), (p - x).into(), D_LANES64 as i32).into() } }; @@ -686,6 +681,7 @@ impl FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl Neg for FieldElement2625x4 { type Output = FieldElement2625x4; @@ -709,10 +705,12 @@ impl Neg for FieldElement2625x4 { P_TIMES_16_HI - self.0[2], P_TIMES_16_HI - self.0[3], P_TIMES_16_HI - self.0[4], - ]).reduce() + ]) + .reduce() } } +#[unsafe_target_feature("avx2")] impl Add for FieldElement2625x4 { type Output = FieldElement2625x4; /// Add two `FieldElement2625x4`s, without performing a reduction. @@ -728,6 +726,7 @@ impl Add for FieldElement2625x4 { } } +#[unsafe_target_feature("avx2")] impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { type Output = FieldElement2625x4; /// Perform a multiplication by a vector of small constants. @@ -737,34 +736,31 @@ impl Mul<(u32, u32, u32, u32)> for FieldElement2625x4 { /// The coefficients of the result are bounded with \\( b < 0.007 \\). #[inline] fn mul(self, scalars: (u32, u32, u32, u32)) -> FieldElement2625x4 { - unsafe { - use core::arch::x86_64::_mm256_mul_epu32; - - let consts = u32x8::new(scalars.0, 0, scalars.1, 0, scalars.2, 0, scalars.3, 0); - - let (b0, b1) = unpack_pair(self.0[0]); - let (b2, b3) = unpack_pair(self.0[1]); - let (b4, b5) = unpack_pair(self.0[2]); - let (b6, b7) = unpack_pair(self.0[3]); - let (b8, b9) = unpack_pair(self.0[4]); - - FieldElement2625x4::reduce64([ - _mm256_mul_epu32(b0.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b1.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b2.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b3.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b4.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b5.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b6.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b7.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b8.into_bits(), consts.into_bits()).into_bits(), - _mm256_mul_epu32(b9.into_bits(), consts.into_bits()).into_bits(), - ]) - } + let consts = u32x8::new(scalars.0, 0, scalars.1, 0, scalars.2, 0, scalars.3, 0); + + let (b0, b1) = unpack_pair(self.0[0]); + let (b2, b3) = unpack_pair(self.0[1]); + let (b4, b5) = unpack_pair(self.0[2]); + let (b6, b7) = unpack_pair(self.0[3]); + let (b8, b9) = unpack_pair(self.0[4]); + + FieldElement2625x4::reduce64([ + b0.mul32(consts), + b1.mul32(consts), + b2.mul32(consts), + b3.mul32(consts), + b4.mul32(consts), + b5.mul32(consts), + b6.mul32(consts), + b7.mul32(consts), + b8.mul32(consts), + b9.mul32(consts), + ]) } } -impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { +#[unsafe_target_feature("avx2")] +impl Mul<&FieldElement2625x4> for &FieldElement2625x4 { type Output = FieldElement2625x4; /// Multiply `self` by `rhs`. /// @@ -778,17 +774,17 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { /// /// The coefficients of the result are bounded with \\( b < 0.007 \\). /// - fn mul(self, rhs: &'b FieldElement2625x4) -> FieldElement2625x4 { + #[rustfmt::skip] // keep alignment of z* calculations + #[inline] + fn mul(self, rhs: &FieldElement2625x4) -> FieldElement2625x4 { #[inline(always)] fn m(x: u32x8, y: u32x8) -> u64x4 { - use core::arch::x86_64::_mm256_mul_epu32; - unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + x.mul32(y) } #[inline(always)] fn m_lo(x: u32x8, y: u32x8) -> u32x8 { - use core::arch::x86_64::_mm256_mul_epu32; - unsafe { _mm256_mul_epu32(x.into_bits(), y.into_bits()).into_bits() } + x.mul32(y).into() } let (x0, x1) = unpack_pair(self.0[0]); @@ -821,16 +817,16 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { let x7_2 = x7 + x7; let x9_2 = x9 + x9; - let z0 = m(x0,y0) + m(x1_2,y9_19) + m(x2,y8_19) + m(x3_2,y7_19) + m(x4,y6_19) + m(x5_2,y5_19) + m(x6,y4_19) + m(x7_2,y3_19) + m(x8,y2_19) + m(x9_2,y1_19); - let z1 = m(x0,y1) + m(x1,y0) + m(x2,y9_19) + m(x3,y8_19) + m(x4,y7_19) + m(x5,y6_19) + m(x6,y5_19) + m(x7,y4_19) + m(x8,y3_19) + m(x9,y2_19); - let z2 = m(x0,y2) + m(x1_2,y1) + m(x2,y0) + m(x3_2,y9_19) + m(x4,y8_19) + m(x5_2,y7_19) + m(x6,y6_19) + m(x7_2,y5_19) + m(x8,y4_19) + m(x9_2,y3_19); - let z3 = m(x0,y3) + m(x1,y2) + m(x2,y1) + m(x3,y0) + m(x4,y9_19) + m(x5,y8_19) + m(x6,y7_19) + m(x7,y6_19) + m(x8,y5_19) + m(x9,y4_19); - let z4 = m(x0,y4) + m(x1_2,y3) + m(x2,y2) + m(x3_2,y1) + m(x4,y0) + m(x5_2,y9_19) + m(x6,y8_19) + m(x7_2,y7_19) + m(x8,y6_19) + m(x9_2,y5_19); - let z5 = m(x0,y5) + m(x1,y4) + m(x2,y3) + m(x3,y2) + m(x4,y1) + m(x5,y0) + m(x6,y9_19) + m(x7,y8_19) + m(x8,y7_19) + m(x9,y6_19); - let z6 = m(x0,y6) + m(x1_2,y5) + m(x2,y4) + m(x3_2,y3) + m(x4,y2) + m(x5_2,y1) + m(x6,y0) + m(x7_2,y9_19) + m(x8,y8_19) + m(x9_2,y7_19); - let z7 = m(x0,y7) + m(x1,y6) + m(x2,y5) + m(x3,y4) + m(x4,y3) + m(x5,y2) + m(x6,y1) + m(x7,y0) + m(x8,y9_19) + m(x9,y8_19); - let z8 = m(x0,y8) + m(x1_2,y7) + m(x2,y6) + m(x3_2,y5) + m(x4,y4) + m(x5_2,y3) + m(x6,y2) + m(x7_2,y1) + m(x8,y0) + m(x9_2,y9_19); - let z9 = m(x0,y9) + m(x1,y8) + m(x2,y7) + m(x3,y6) + m(x4,y5) + m(x5,y4) + m(x6,y3) + m(x7,y2) + m(x8,y1) + m(x9,y0); + let z0 = m(x0, y0) + m(x1_2, y9_19) + m(x2, y8_19) + m(x3_2, y7_19) + m(x4, y6_19) + m(x5_2, y5_19) + m(x6, y4_19) + m(x7_2, y3_19) + m(x8, y2_19) + m(x9_2, y1_19); + let z1 = m(x0, y1) + m(x1, y0) + m(x2, y9_19) + m(x3, y8_19) + m(x4, y7_19) + m(x5, y6_19) + m(x6, y5_19) + m(x7, y4_19) + m(x8, y3_19) + m(x9, y2_19); + let z2 = m(x0, y2) + m(x1_2, y1) + m(x2, y0) + m(x3_2, y9_19) + m(x4, y8_19) + m(x5_2, y7_19) + m(x6, y6_19) + m(x7_2, y5_19) + m(x8, y4_19) + m(x9_2, y3_19); + let z3 = m(x0, y3) + m(x1, y2) + m(x2, y1) + m(x3, y0) + m(x4, y9_19) + m(x5, y8_19) + m(x6, y7_19) + m(x7, y6_19) + m(x8, y5_19) + m(x9, y4_19); + let z4 = m(x0, y4) + m(x1_2, y3) + m(x2, y2) + m(x3_2, y1) + m(x4, y0) + m(x5_2, y9_19) + m(x6, y8_19) + m(x7_2, y7_19) + m(x8, y6_19) + m(x9_2, y5_19); + let z5 = m(x0, y5) + m(x1, y4) + m(x2, y3) + m(x3, y2) + m(x4, y1) + m(x5, y0) + m(x6, y9_19) + m(x7, y8_19) + m(x8, y7_19) + m(x9, y6_19); + let z6 = m(x0, y6) + m(x1_2, y5) + m(x2, y4) + m(x3_2, y3) + m(x4, y2) + m(x5_2, y1) + m(x6, y0) + m(x7_2, y9_19) + m(x8, y8_19) + m(x9_2, y7_19); + let z7 = m(x0, y7) + m(x1, y6) + m(x2, y5) + m(x3, y4) + m(x4, y3) + m(x5, y2) + m(x6, y1) + m(x7, y0) + m(x8, y9_19) + m(x9, y8_19); + let z8 = m(x0, y8) + m(x1_2, y7) + m(x2, y6) + m(x3_2, y5) + m(x4, y4) + m(x5_2, y3) + m(x6, y2) + m(x7_2, y1) + m(x8, y0) + m(x9_2, y9_19); + let z9 = m(x0, y9) + m(x1, y8) + m(x2, y7) + m(x3, y6) + m(x4, y5) + m(x5, y4) + m(x6, y3) + m(x7, y2) + m(x8, y1) + m(x9, y0); // The bounds on z[i] are the same as in the serial 32-bit code // and the comment below is copied from there: @@ -874,15 +870,16 @@ impl<'a, 'b> Mul<&'b FieldElement2625x4> for &'a FieldElement2625x4 { } } +#[cfg(target_feature = "avx2")] #[cfg(test)] mod test { use super::*; #[test] fn scale_by_curve_constants() { - let mut x = FieldElement2625x4::splat(&FieldElement51::one()); + let mut x = FieldElement2625x4::splat(&FieldElement51::ONE); - x = x * (121666, 121666, 2*121666, 2*121665); + x = x * (121666, 121666, 2 * 121666, 2 * 121665); let xs = x.split(); assert_eq!(xs[0], FieldElement51([121666, 0, 0, 0, 0])); diff --git a/src/backend/vector/avx2/mod.rs b/curve25519-dalek/src/backend/vector/avx2/mod.rs similarity index 76% rename from src/backend/vector/avx2/mod.rs rename to curve25519-dalek/src/backend/vector/avx2/mod.rs index 527fdc125..fba39f05c 100644 --- a/src/backend/vector/avx2/mod.rs +++ b/curve25519-dalek/src/backend/vector/avx2/mod.rs @@ -9,13 +9,12 @@ // - isis agora lovecruft // - Henry de Valence -#![cfg_attr( - feature = "nightly", - doc(include = "../../../../docs/avx2-notes.md") -)] +#![doc = include_str!("../../../../docs/avx2-notes.md")] pub(crate) mod field; pub(crate) mod edwards; pub(crate) mod constants; + +pub(crate) use self::edwards::{CachedPoint, ExtendedPoint}; diff --git a/src/backend/vector/ifma/constants.rs b/curve25519-dalek/src/backend/vector/ifma/constants.rs similarity index 82% rename from src/backend/vector/ifma/constants.rs rename to curve25519-dalek/src/backend/vector/ifma/constants.rs index fd89058d6..66ace9643 100644 --- a/src/backend/vector/ifma/constants.rs +++ b/curve25519-dalek/src/backend/vector/ifma/constants.rs @@ -9,66 +9,68 @@ //! This module contains constants used by the IFMA backend. -use packed_simd::u64x4; +use crate::backend::vector::packed_simd::u64x4; -use window::NafLookupTable8; +#[cfg(feature = "precomputed-tables")] +use crate::window::NafLookupTable8; use super::edwards::{CachedPoint, ExtendedPoint}; use super::field::{F51x4Reduced, F51x4Unreduced}; /// The identity element as an `ExtendedPoint`. pub(crate) static EXTENDEDPOINT_IDENTITY: ExtendedPoint = ExtendedPoint(F51x4Unreduced([ - u64x4::new(0, 1, 1, 0), - u64x4::new(0, 0, 0, 0), - u64x4::new(0, 0, 0, 0), - u64x4::new(0, 0, 0, 0), - u64x4::new(0, 0, 0, 0), + u64x4::new_const(0, 1, 1, 0), + u64x4::new_const(0, 0, 0, 0), + u64x4::new_const(0, 0, 0, 0), + u64x4::new_const(0, 0, 0, 0), + u64x4::new_const(0, 0, 0, 0), ])); /// The identity element as a `CachedPoint`. pub(crate) static CACHEDPOINT_IDENTITY: CachedPoint = CachedPoint(F51x4Reduced([ - u64x4::new(121647, 121666, 243332, 2251799813685229), - u64x4::new(2251799813685248, 0, 0, 2251799813685247), - u64x4::new(2251799813685247, 0, 0, 2251799813685247), - u64x4::new(2251799813685247, 0, 0, 2251799813685247), - u64x4::new(2251799813685247, 0, 0, 2251799813685247), + u64x4::new_const(121647, 121666, 243332, 2251799813685229), + u64x4::new_const(2251799813685248, 0, 0, 2251799813685247), + u64x4::new_const(2251799813685247, 0, 0, 2251799813685247), + u64x4::new_const(2251799813685247, 0, 0, 2251799813685247), + u64x4::new_const(2251799813685247, 0, 0, 2251799813685247), ])); /// Odd multiples of the Ed25519 basepoint: +#[cfg(feature = "precomputed-tables")] pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ CachedPoint(F51x4Reduced([ - u64x4::new(1277522120965857, 73557767439946, 243332, 1943719795065404), - u64x4::new(108375142003455, 341984820733594, 0, 2097709862669256), - u64x4::new(150073485536043, 750646439938056, 0, 581130035634455), - u64x4::new(2149983732744869, 1903255931888577, 0, 646644904824193), - u64x4::new(291045673509296, 1060034214701851, 0, 325245010451737), + u64x4::new_const(1277522120965857, 73557767439946, 243332, 1943719795065404), + u64x4::new_const(108375142003455, 341984820733594, 0, 2097709862669256), + u64x4::new_const(150073485536043, 750646439938056, 0, 581130035634455), + u64x4::new_const(2149983732744869, 1903255931888577, 0, 646644904824193), + u64x4::new_const(291045673509296, 1060034214701851, 0, 325245010451737), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1970681836121889, 1660307753655178, 1077207637163462, 1436413309977108, ), - u64x4::new( + u64x4::new_const( 158785710838757, 919645875412951, 174577133496574, 2213787394009350, ), - u64x4::new( + u64x4::new_const( 1017606396438281, 1240932851489554, 918203302506967, 1239827708070863, ), - u64x4::new( + u64x4::new_const( 1748989883612327, 1745367742532782, 1168385548387, 1211387683826673, ), - u64x4::new( + u64x4::new_const( 799349980018733, 1471088235739693, 1505351346057417, @@ -76,31 +78,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 171437462972293, 36016853025886, 1184164975342640, 1633525003912147, ), - u64x4::new( + u64x4::new_const( 2113383632509037, 1946216474924125, 1884174984466256, 1373317790955847, ), - u64x4::new( + u64x4::new_const( 791293623466401, 1796466048084189, 444977763198796, 629823271230872, ), - u64x4::new( + u64x4::new_const( 1093217720067380, 2157024270666135, 238122980108466, 806820763806847, ), - u64x4::new( + u64x4::new_const( 793658959468458, 368578641413741, 11592529764159, @@ -108,31 +110,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1538027396670268, 1588896993892061, 675619548648376, 788373514423313, ), - u64x4::new( + u64x4::new_const( 1987517656073805, 1940987929951188, 666993851697339, 2040540928108427, ), - u64x4::new( + u64x4::new_const( 375514548584082, 1726008037083790, 1070069155000872, 570111103756303, ), - u64x4::new( + u64x4::new_const( 772223645372213, 2123395244967674, 868238486911408, 1846639042240362, ), - u64x4::new( + u64x4::new_const( 872865734460736, 32277956842850, 1701451131455402, @@ -140,31 +142,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1845177363882902, 275858237213625, 1052127336883600, 171072805852218, ), - u64x4::new( + u64x4::new_const( 139016783952609, 462699304987089, 430046471494974, 410922720999257, ), - u64x4::new( + u64x4::new_const( 846403935976337, 243817706931454, 971825428236901, 571800039596794, ), - u64x4::new( + u64x4::new_const( 807642685434918, 1933536976438782, 812324278898440, 688391556487313, ), - u64x4::new( + u64x4::new_const( 76239450396192, 629532732688863, 1833302026979779, @@ -172,31 +174,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1373931604989264, 331159264656614, 364391529321767, 874765630865409, ), - u64x4::new( + u64x4::new_const( 2109908262150241, 473400816504190, 91544045127333, 976307977609515, ), - u64x4::new( + u64x4::new_const( 330175435673491, 2126511895885904, 1022944071588421, 2158480209801463, ), - u64x4::new( + u64x4::new_const( 1305666795527971, 162063591028664, 2193154870675382, 1789166662611800, ), - u64x4::new( + u64x4::new_const( 817858592500508, 1672743239440202, 859976879916778, @@ -204,31 +206,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 274334925170164, 565841102587251, 603083835949120, 607539210240861, ), - u64x4::new( + u64x4::new_const( 196754662972649, 1339063476699167, 1406077076979491, 896902435668469, ), - u64x4::new( + u64x4::new_const( 397962210956733, 174839587476217, 1381082665748936, 175195877334136, ), - u64x4::new( + u64x4::new_const( 717429432748391, 1635309821746318, 363374010274647, 882908746261699, ), - u64x4::new( + u64x4::new_const( 600946602802781, 1946596133370711, 1532135183320341, @@ -236,31 +238,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2074443704000945, 2163534804938345, 425423840926528, 1100826171404853, ), - u64x4::new( + u64x4::new_const( 111700142796101, 1456893872751964, 1186145518682968, 2192182627706116, ), - u64x4::new( + u64x4::new_const( 1848722121856066, 2123239575044749, 1323870754599272, 883211262889775, ), - u64x4::new( + u64x4::new_const( 938263017712916, 689670293631396, 183944529557576, 501908638166580, ), - u64x4::new( + u64x4::new_const( 2170571907220631, 36636756989655, 1875035480138608, @@ -268,31 +270,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1053429956874064, 1636640618139765, 1556890827801070, 2142720579528828, ), - u64x4::new( + u64x4::new_const( 1814240918422814, 692326274601777, 1054896561802157, 2025454041705534, ), - u64x4::new( + u64x4::new_const( 2109495823888757, 1287497869997176, 194170063200096, 621116840113213, ), - u64x4::new( + u64x4::new_const( 2156505873679998, 2197064359737385, 1312887672223536, 369862818895912, ), - u64x4::new( + u64x4::new_const( 977381163563657, 1878897311974033, 2144566861359744, @@ -300,31 +302,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1266492498289486, 1301524759372145, 324789537938521, 442710471023019, ), - u64x4::new( + u64x4::new_const( 1232722320001345, 1191193089162455, 176474006074813, 2158950213252857, ), - u64x4::new( + u64x4::new_const( 1901782191467749, 494791441598902, 1820415815322129, 854954583485223, ), - u64x4::new( + u64x4::new_const( 1511383667649702, 792536415032464, 2027741263854728, 1727944381044738, ), - u64x4::new( + u64x4::new_const( 606355788891204, 1670687521471220, 582824350365415, @@ -332,31 +334,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1079942762813598, 2015830004785901, 479916361323351, 1907956590950158, ), - u64x4::new( + u64x4::new_const( 2053400302939156, 1319799126867070, 19493088767391, 1908755581402373, ), - u64x4::new( + u64x4::new_const( 2235858054780980, 885832711204321, 810332865560178, 103174191215441, ), - u64x4::new( + u64x4::new_const( 1843466881032833, 355511728384038, 693846715794114, 186545012724117, ), - u64x4::new( + u64x4::new_const( 1661758432892509, 1491022339899281, 698941123765263, @@ -364,31 +366,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1075933251927831, 400263885306647, 1308157532880528, 347933379126665, ), - u64x4::new( + u64x4::new_const( 673811632329433, 1584860147186478, 271778891257244, 498194055154207, ), - u64x4::new( + u64x4::new_const( 703783427747558, 1051624728592032, 1371463103351544, 230351033002960, ), - u64x4::new( + u64x4::new_const( 860729466483372, 421647596766583, 1520613871336707, 635298775280054, ), - u64x4::new( + u64x4::new_const( 1168352891728845, 1691216293752089, 1799491997061519, @@ -396,31 +398,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 420156727446514, 1483649215777128, 165508610199900, 1918121104840431, ), - u64x4::new( + u64x4::new_const( 2129902293682427, 730952770435213, 2184527544565390, 1939880362232986, ), - u64x4::new( + u64x4::new_const( 1771978364905086, 510975579746524, 927564335219142, 177574146260558, ), - u64x4::new( + u64x4::new_const( 2164104536437514, 1532598873799015, 406875369182421, 1367005937406517, ), - u64x4::new( + u64x4::new_const( 35073200082587, 1981124717036219, 1854087014063833, @@ -428,31 +430,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1963785875777739, 411497142699119, 1974557512687408, 1268304422747183, ), - u64x4::new( + u64x4::new_const( 762752575978150, 1443822019541748, 1331556159904338, 377726798263780, ), - u64x4::new( + u64x4::new_const( 825953972847841, 353487068141356, 1955697322427207, 2048226560172078, ), - u64x4::new( + u64x4::new_const( 1482378558684434, 657691905625918, 923870001994493, 1694132799397736, ), - u64x4::new( + u64x4::new_const( 1643904759603122, 170495566698285, 1218312703413378, @@ -460,31 +462,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 939230507241903, 2238763473105245, 1827325199528162, 1153939339775538, ), - u64x4::new( + u64x4::new_const( 38544505283339, 258889431497015, 351721979677947, 1357907379592829, ), - u64x4::new( + u64x4::new_const( 1393974676373341, 1131355528938676, 473104915298872, 978783482501776, ), - u64x4::new( + u64x4::new_const( 2131516168980501, 2113911780991092, 1477027502354261, 542884524860340, ), - u64x4::new( + u64x4::new_const( 1029606261349423, 64226378557628, 1669131167474348, @@ -492,31 +494,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1423176501543193, 163313632579593, 2220495688893001, 2220041045291870, ), - u64x4::new( + u64x4::new_const( 1111834224023697, 1026815658023689, 1404605100939775, 1412149108248227, ), - u64x4::new( + u64x4::new_const( 1542537854906076, 1270288391129127, 991419278941933, 1824939809581980, ), - u64x4::new( + u64x4::new_const( 1142003215657891, 525980550896367, 1508270666157963, 917719462309053, ), - u64x4::new( + u64x4::new_const( 400851268057105, 1620818232405188, 1251478578139510, @@ -524,31 +526,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2125383272208441, 1368790097335984, 11813369275978, 639513785921674, ), - u64x4::new( + u64x4::new_const( 2200806265616284, 1041996387620216, 1275149397833084, 1723371028064068, ), - u64x4::new( + u64x4::new_const( 603720163891275, 2135593511176153, 2049641644431548, 1198460677818310, ), - u64x4::new( + u64x4::new_const( 1862491879401621, 2008116580769441, 626566325260235, 1058308304975798, ), - u64x4::new( + u64x4::new_const( 628557314314858, 1075323332046522, 1631772244117095, @@ -556,31 +558,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1222773123817104, 363276129291452, 796237592807883, 1914425291893078, ), - u64x4::new( + u64x4::new_const( 1721259057429088, 734941709009373, 1553365830564638, 1492120931079419, ), - u64x4::new( + u64x4::new_const( 1009354843273686, 293884504384873, 1050281954944357, 134132942667344, ), - u64x4::new( + u64x4::new_const( 23119363298711, 1694754778833445, 1725925193393496, 1738396998222001, ), - u64x4::new( + u64x4::new_const( 1753692057254667, 118428526447110, 840961387840295, @@ -588,31 +590,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1004186117579547, 508771992330056, 1426571663072421, 2238524171903259, ), - u64x4::new( + u64x4::new_const( 744764613007812, 398885442368825, 2047459490294949, 2141797621077959, ), - u64x4::new( + u64x4::new_const( 4556204156489, 1708213022802363, 1071381560923933, 393474529142567, ), - u64x4::new( + u64x4::new_const( 350116198213005, 945907227204695, 168267474358731, 1801504420122711, ), - u64x4::new( + u64x4::new_const( 728788674520360, 1262722049156121, 455259596607008, @@ -620,31 +622,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2226818917892677, 185673745808179, 2240952219732549, 324137961621908, ), - u64x4::new( + u64x4::new_const( 1659527641857410, 973964060249383, 1349692151487730, 1172743533370593, ), - u64x4::new( + u64x4::new_const( 310591478467746, 2123977244137170, 774562885265820, 430035546191685, ), - u64x4::new( + u64x4::new_const( 2150863173197992, 2101978317708856, 193592648406011, 1375328504508580, ), - u64x4::new( + u64x4::new_const( 1946235834250479, 121741431658675, 1004342690620100, @@ -652,31 +654,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 463079632200153, 40415275714025, 545935352782679, 1458043501600908, ), - u64x4::new( + u64x4::new_const( 783771976559993, 880839641726471, 1782028201271831, 41664413404590, ), - u64x4::new( + u64x4::new_const( 985129151724159, 187728621410000, 16620051933318, 378011085567733, ), - u64x4::new( + u64x4::new_const( 1820372198168638, 905710046480679, 1912961774249737, 1868135861067161, ), - u64x4::new( + u64x4::new_const( 474460473983187, 1455684425673661, 652771171116843, @@ -684,31 +686,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1088886980746809, 1660218575261626, 527921875040240, 915086639857889, ), - u64x4::new( + u64x4::new_const( 1814735788528175, 1586698876186367, 2040856637532862, 405684812785624, ), - u64x4::new( + u64x4::new_const( 658578559700999, 1751442070931114, 1293623371490094, 715026719042518, ), - u64x4::new( + u64x4::new_const( 382156225644820, 897982285504960, 577673183555858, 1158728558309719, ), - u64x4::new( + u64x4::new_const( 1865791902475663, 124491617513788, 758484125168765, @@ -716,31 +718,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 330985690350617, 2214424721795630, 973374650780848, 1507267060932964, ), - u64x4::new( + u64x4::new_const( 1733823971011290, 1730742552292995, 669018866977489, 604527664126146, ), - u64x4::new( + u64x4::new_const( 1082092498645474, 1029182053935309, 756799947765834, 1764720030308351, ), - u64x4::new( + u64x4::new_const( 969912105693756, 38116887248276, 2148030115687613, 995140534653865, ), - u64x4::new( + u64x4::new_const( 2154373397460354, 298128883464656, 479587543632539, @@ -748,31 +750,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 843064865526549, 2019481782959016, 1873125524281672, 2013330239022371, ), - u64x4::new( + u64x4::new_const( 1192932403815186, 1818108671859220, 1247005102016258, 1210577394628058, ), - u64x4::new( + u64x4::new_const( 132359273326717, 795492788299178, 1235924489372816, 891705064411550, ), - u64x4::new( + u64x4::new_const( 1425833709104858, 152114045731085, 991347902581315, 1387773338707683, ), - u64x4::new( + u64x4::new_const( 48024203807922, 157005564892977, 1474053161953744, @@ -780,31 +782,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1076621484026788, 1309917234320927, 1786998180233659, 1595497085944737, ), - u64x4::new( + u64x4::new_const( 1737334672694726, 2038133716999447, 1929061192400917, 620544235219084, ), - u64x4::new( + u64x4::new_const( 1550527313469747, 329096759623509, 1585214659209474, 693419841748324, ), - u64x4::new( + u64x4::new_const( 1450010875912315, 2085047082180569, 757421110771886, 389367139787400, ), - u64x4::new( + u64x4::new_const( 781339490566117, 132941783448971, 258650459725225, @@ -812,31 +814,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 859638991542650, 2249840007426442, 1138753070862357, 793751342318913, ), - u64x4::new( + u64x4::new_const( 2133476133447306, 1027010646129239, 436851910892865, 866949948830344, ), - u64x4::new( + u64x4::new_const( 1936003572431223, 531513680252193, 1929877059408416, 830585477662503, ), - u64x4::new( + u64x4::new_const( 1460760405777960, 686673748420916, 275475330051554, 1581792376993692, ), - u64x4::new( + u64x4::new_const( 894482039456784, 1801274480988632, 16407898635278, @@ -844,31 +846,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 258585746227669, 936490904651492, 1826793887434108, 1201219990633823, ), - u64x4::new( + u64x4::new_const( 979462791643635, 461762372210187, 218708929991480, 1378150755760178, ), - u64x4::new( + u64x4::new_const( 642542170229970, 787135445552820, 371168855880557, 182642566486693, ), - u64x4::new( + u64x4::new_const( 1152277399721904, 1726910452705576, 1452393215705343, 2117799581546845, ), - u64x4::new( + u64x4::new_const( 1211265143925330, 14373046151823, 1745528818271507, @@ -876,31 +878,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 635154614562157, 1956763034454109, 509123035953043, 445727657534780, ), - u64x4::new( + u64x4::new_const( 2072765509783252, 1282639891593570, 1075086397362049, 722996110178195, ), - u64x4::new( + u64x4::new_const( 1385572918825603, 1190035835509576, 218317841176013, 1047865370756924, ), - u64x4::new( + u64x4::new_const( 473991569426488, 1910588123704592, 1338270051770806, 401676861680875, ), - u64x4::new( + u64x4::new_const( 992455353618436, 126422733426929, 1955248037756399, @@ -908,31 +910,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1555272991526078, 2214378187116349, 366893798097444, 1401502118355702, ), - u64x4::new( + u64x4::new_const( 1157229521930713, 2144787187506262, 1681597469697840, 847499096518697, ), - u64x4::new( + u64x4::new_const( 1872802655800758, 1027119609820793, 1137278714788290, 1664750301179485, ), - u64x4::new( + u64x4::new_const( 1091289858897030, 910126419483563, 1101920147235731, 597083075893952, ), - u64x4::new( + u64x4::new_const( 1711011533670315, 185206680336278, 1620960612579784, @@ -940,31 +942,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 73077300235958, 257216723095630, 466947267713785, 847105214181598, ), - u64x4::new( + u64x4::new_const( 1322905631406309, 407458059314731, 230045063190376, 923800751267786, ), - u64x4::new( + u64x4::new_const( 1146027205000415, 1541328763727623, 768510249199119, 1630223587589059, ), - u64x4::new( + u64x4::new_const( 1930368769879433, 1376145403022159, 1898149855343131, 1709421930518180, ), - u64x4::new( + u64x4::new_const( 633944191571764, 58314960742839, 2050971151574988, @@ -972,31 +974,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 361576929158539, 1035682890165818, 160945739362874, 266975208626222, ), - u64x4::new( + u64x4::new_const( 1635371797076046, 2106722851965197, 451585919077206, 6692426667180, ), - u64x4::new( + u64x4::new_const( 175820543533852, 2057511393764025, 1531846543720469, 1648320903946519, ), - u64x4::new( + u64x4::new_const( 947461770620940, 1107335044817620, 1725565474111216, 2182263619949220, ), - u64x4::new( + u64x4::new_const( 726444888601221, 1379664085279206, 1517215633290417, @@ -1004,31 +1006,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 686545355846512, 1712283265573167, 1743509592736302, 1653906616429153, ), - u64x4::new( + u64x4::new_const( 985108805667149, 2244347650874753, 1304749057936860, 321846134330589, ), - u64x4::new( + u64x4::new_const( 296321076156886, 1717929256240029, 450933772486425, 2015536856431605, ), - u64x4::new( + u64x4::new_const( 1690393512821866, 646913049470189, 2198650647576397, 1230646705710442, ), - u64x4::new( + u64x4::new_const( 601961913448442, 878806578800541, 620497587492381, @@ -1036,31 +1038,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 631510982676132, 1755753187697174, 1596201246674299, 2197888384902121, ), - u64x4::new( + u64x4::new_const( 626957678275745, 1447583371478595, 1375375216702128, 1443613232818823, ), - u64x4::new( + u64x4::new_const( 1962997804660501, 1051744123184519, 1002558639300437, 1237313314603385, ), - u64x4::new( + u64x4::new_const( 2118828335274995, 226398203764759, 889099617161107, 1620967117678504, ), - u64x4::new( + u64x4::new_const( 227261019362935, 2046897556746842, 591524060355369, @@ -1068,31 +1070,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1375403119051662, 222313965014452, 539873444241395, 213198095917915, ), - u64x4::new( + u64x4::new_const( 1436952871599114, 1229749762725246, 1174441562267670, 265367077740349, ), - u64x4::new( + u64x4::new_const( 11107426165917, 985954476039181, 1147329112365579, 1133931640328107, ), - u64x4::new( + u64x4::new_const( 585235055006843, 699515259687482, 299559608721134, 2134819767146767, ), - u64x4::new( + u64x4::new_const( 1376401105588528, 391412107507860, 302743651807545, @@ -1100,31 +1102,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1802940904616205, 1615132760193234, 869321663313735, 666494072545310, ), - u64x4::new( + u64x4::new_const( 1452849320020701, 1472716813676364, 472862999490802, 359937983286145, ), - u64x4::new( + u64x4::new_const( 1221198323133843, 491718521756528, 1387135774113906, 793779904904008, ), - u64x4::new( + u64x4::new_const( 1032129287829151, 30730741946697, 217603185195068, 2118169309744162, ), - u64x4::new( + u64x4::new_const( 225899335574721, 1767553399797342, 881082465669982, @@ -1132,31 +1134,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1127093564374276, 2245188499702906, 1250041622887441, 2179324911668149, ), - u64x4::new( + u64x4::new_const( 908019210866875, 1879900391060964, 1355047706206597, 647218945377302, ), - u64x4::new( + u64x4::new_const( 1616265604422592, 2134336781521657, 1157711219915601, 1227494173135033, ), - u64x4::new( + u64x4::new_const( 136450294813355, 1984543542455033, 1199486053011083, 33687889941331, ), - u64x4::new( + u64x4::new_const( 1053447012707371, 68239344331930, 537448158443925, @@ -1164,31 +1166,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 996806463322563, 2043104667851348, 1110361398300309, 1218740346887957, ), - u64x4::new( + u64x4::new_const( 399141907016839, 1307691109658227, 532535384961264, 896201194398872, ), - u64x4::new( + u64x4::new_const( 111705272106160, 1790972382466021, 1159338112559144, 303544352897203, ), - u64x4::new( + u64x4::new_const( 1036600573322969, 1457119922663674, 334117653665514, 460023361701263, ), - u64x4::new( + u64x4::new_const( 1363773215189933, 1915594049343802, 1661249423378694, @@ -1196,31 +1198,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 3093919631215, 574886478077610, 1704446919728971, 250093147254210, ), - u64x4::new( + u64x4::new_const( 1387413348737796, 360142717826981, 2116185073015983, 474541388374100, ), - u64x4::new( + u64x4::new_const( 1632539630892580, 1332404016215719, 2145297637794728, 1289783723173504, ), - u64x4::new( + u64x4::new_const( 1030244179060173, 579782698595797, 1062365251139982, 677149839815546, ), - u64x4::new( + u64x4::new_const( 6671539419876, 1426937459653775, 406942403696343, @@ -1228,31 +1230,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 271984148441782, 1708099625818957, 1499011822959235, 516808451044836, ), - u64x4::new( + u64x4::new_const( 1124847751346323, 2038336022958449, 1721698491022600, 705944403212572, ), - u64x4::new( + u64x4::new_const( 85459783780275, 1715213099986669, 1728445509034791, 730657630359717, ), - u64x4::new( + u64x4::new_const( 1185034652652387, 755472578204310, 476118360897817, 1800434542785310, ), - u64x4::new( + u64x4::new_const( 1815589628676941, 491778500674079, 1547664984392513, @@ -1260,31 +1262,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2036337168672113, 1730787524684269, 639134121311693, 698060925015524, ), - u64x4::new( + u64x4::new_const( 315211075189491, 1329055848835358, 688621136402134, 1271193060119448, ), - u64x4::new( + u64x4::new_const( 1697984374314012, 459330773536457, 305481314707918, 61676911066002, ), - u64x4::new( + u64x4::new_const( 2166631826859191, 2105217187401781, 937587962768434, 357397435365683, ), - u64x4::new( + u64x4::new_const( 1206757093145471, 1287847622009294, 1951336140421622, @@ -1292,31 +1294,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 82144190081093, 1568417433687791, 907555979158442, 2037855062523867, ), - u64x4::new( + u64x4::new_const( 1225315484058853, 315317868015613, 1765025920288384, 175223259828436, ), - u64x4::new( + u64x4::new_const( 1215010304871271, 662713408454950, 429517658575616, 991062684008811, ), - u64x4::new( + u64x4::new_const( 993837615254894, 1485561584889450, 2001836754226476, 1915943063896801, ), - u64x4::new( + u64x4::new_const( 818895101625673, 1342479472068804, 1380235330010671, @@ -1324,31 +1326,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1500726307559118, 956166860173424, 512663951564436, 1940180717699824, ), - u64x4::new( + u64x4::new_const( 1789521472720825, 779456898652427, 2035063615853504, 863582140589407, ), - u64x4::new( + u64x4::new_const( 634508890793787, 1748041666732214, 259642099961634, 1294936839797812, ), - u64x4::new( + u64x4::new_const( 2183334898697038, 2197242820694806, 2217225409073703, 992633998226449, ), - u64x4::new( + u64x4::new_const( 2197077498155916, 1562008797791883, 1395088759904208, @@ -1356,31 +1358,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 186854731652320, 284389440026580, 1252175415119400, 1025377410100223, ), - u64x4::new( + u64x4::new_const( 1578732129417607, 898645497852382, 2237766074482974, 1939197790303592, ), - u64x4::new( + u64x4::new_const( 1438830390640145, 1682452015845597, 1108441197232223, 1984134492898664, ), - u64x4::new( + u64x4::new_const( 282668727301669, 1609018289552856, 390363439795705, 1138459124667912, ), - u64x4::new( + u64x4::new_const( 18889015928490, 532489638086725, 324621535996080, @@ -1388,31 +1390,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2041327051605378, 2244037852176483, 2116336876147147, 9616672544864, ), - u64x4::new( + u64x4::new_const( 969847387559191, 1059119127679639, 1764630094670633, 364568045311834, ), - u64x4::new( + u64x4::new_const( 505938893153679, 2075421412172902, 326984153045666, 1959549727324704, ), - u64x4::new( + u64x4::new_const( 1088715617911260, 13917085151028, 950568481355929, 23687195265771, ), - u64x4::new( + u64x4::new_const( 1798284568673198, 808382292203333, 2214698741961545, @@ -1420,31 +1422,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1731488929623777, 1158815615106413, 1491090861948525, 1428384712900962, ), - u64x4::new( + u64x4::new_const( 722237139522457, 1514290328911535, 1366197913116230, 1519472657321210, ), - u64x4::new( + u64x4::new_const( 246028966932273, 1888239319448405, 423720022211163, 455243905681470, ), - u64x4::new( + u64x4::new_const( 738323403716001, 1758018973481179, 1180718299482318, 1008495946606708, ), - u64x4::new( + u64x4::new_const( 334959381596119, 1704599537529481, 2172191232106896, @@ -1452,31 +1454,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 273393076768079, 427388720298603, 1071733376018227, 1715429388968611, ), - u64x4::new( + u64x4::new_const( 751776629892313, 1965239102856011, 541955408230119, 831043488876080, ), - u64x4::new( + u64x4::new_const( 643718536393104, 390543998404644, 2176730661486279, 499459234889079, ), - u64x4::new( + u64x4::new_const( 1482404333915009, 865527293526285, 507957951411713, 216456252558825, ), - u64x4::new( + u64x4::new_const( 2210281256300231, 1519357818277551, 1257866936775246, @@ -1484,31 +1486,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2135395168187905, 2214400157568614, 2032983817870823, 1124945109072647, ), - u64x4::new( + u64x4::new_const( 1602820011758145, 906675633903289, 782700735390986, 2067218823525601, ), - u64x4::new( + u64x4::new_const( 786785748926382, 1433583123655616, 905839404290873, 2249680349963778, ), - u64x4::new( + u64x4::new_const( 1940824582370584, 1610961256326291, 285307858781375, 1755588655461194, ), - u64x4::new( + u64x4::new_const( 233682812055333, 2146114223476434, 41132209533476, @@ -1516,31 +1518,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 600257696476418, 18449221564824, 1422209458591138, 239571584769716, ), - u64x4::new( + u64x4::new_const( 2056372917056980, 1155290566623531, 1252473955568148, 1276690716882081, ), - u64x4::new( + u64x4::new_const( 246974369025311, 658117221519903, 2000380937898441, 1351183273924850, ), - u64x4::new( + u64x4::new_const( 1803747363753112, 1736801515030186, 2025633577199091, 603378480769167, ), - u64x4::new( + u64x4::new_const( 57348749438551, 1893551220299655, 657926732731806, @@ -1548,31 +1550,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 591809128842736, 284860517232591, 27436696863545, 886306697195798, ), - u64x4::new( + u64x4::new_const( 2113192175751749, 1405882509906423, 561316282804847, 835573846576266, ), - u64x4::new( + u64x4::new_const( 94407289485409, 1781534171669004, 2098782516531528, 598529921520053, ), - u64x4::new( + u64x4::new_const( 1860137004504786, 2197323407480349, 1516772733981532, 961740253777086, ), - u64x4::new( + u64x4::new_const( 1484139612868217, 1593557644636881, 838834937143441, @@ -1580,31 +1582,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1165898865828562, 1153420815042389, 1068625028915785, 1945927229911090, ), - u64x4::new( + u64x4::new_const( 843454394017146, 571029655293754, 386282254545998, 1804608237584150, ), - u64x4::new( + u64x4::new_const( 370552451091100, 1279105656351124, 1864742949668631, 2093071521726981, ), - u64x4::new( + u64x4::new_const( 1872542389052198, 1679083953574330, 349872262454465, 1470311090717925, ), - u64x4::new( + u64x4::new_const( 685345654160323, 319718985807814, 1359932285384164, @@ -1612,31 +1614,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 2083666668832889, 314624387816655, 1496694646480345, 1946728950459189, ), - u64x4::new( + u64x4::new_const( 1579153761571203, 508771185291380, 1002249659402007, 551517831173801, ), - u64x4::new( + u64x4::new_const( 2132371471626150, 1988122278556533, 1552195130653890, 1327637750292755, ), - u64x4::new( + u64x4::new_const( 118937099181527, 382610380973142, 634951529106471, 382740054041699, ), - u64x4::new( + u64x4::new_const( 801287519643470, 87822941589258, 1908825350108451, @@ -1644,31 +1646,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 330347226380261, 672119116965146, 1761510370768005, 1959200302484704, ), - u64x4::new( + u64x4::new_const( 1631876583009250, 1684917718484264, 1027256947805920, 2174612545251129, ), - u64x4::new( + u64x4::new_const( 636668855699872, 625187713984839, 265886954766790, 167898557908504, ), - u64x4::new( + u64x4::new_const( 1210974548180860, 2051308710365526, 907620584086428, 1081788677970850, ), - u64x4::new( + u64x4::new_const( 621792955460854, 1450945504745382, 1666728650687828, @@ -1676,31 +1678,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 24725936182267, 2226765032752574, 2036560083102883, 2002351185719584, ), - u64x4::new( + u64x4::new_const( 1620080779405308, 1493220053370419, 2245691691038916, 1152182628629603, ), - u64x4::new( + u64x4::new_const( 317928527147500, 1855194218440212, 979380281964169, 861442286685289, ), - u64x4::new( + u64x4::new_const( 393308472784625, 486143087279967, 1234071346236405, 777748237119399, ), - u64x4::new( + u64x4::new_const( 43850412814718, 1497656407486446, 744128331046695, @@ -1708,31 +1710,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1670169946550211, 1230951698726438, 806586940221293, 23159779184607, ), - u64x4::new( + u64x4::new_const( 634011340979302, 764182085034744, 731065727766955, 1737985776442180, ), - u64x4::new( + u64x4::new_const( 240492712141842, 73976435954441, 162810587166835, 697230894340912, ), - u64x4::new( + u64x4::new_const( 1299745598348388, 1359436039694544, 1856609816731554, 25228008461513, ), - u64x4::new( + u64x4::new_const( 2180690501932381, 2161211192848458, 87069466793408, @@ -1740,31 +1742,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1106932458043379, 1675181364231371, 1681785724775243, 131824742557210, ), - u64x4::new( + u64x4::new_const( 1671649414647169, 1827849994880670, 1097958057111899, 701956891169434, ), - u64x4::new( + u64x4::new_const( 2095539283710881, 591029812888096, 1699571518315654, 1297589045812566, ), - u64x4::new( + u64x4::new_const( 1345612272298537, 2166754730876055, 2047982622154948, 1785222806258129, ), - u64x4::new( + u64x4::new_const( 2181915268829890, 1895697064378670, 1288412327355885, @@ -1772,31 +1774,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 741330264098392, 357073519729966, 1603572339180975, 433572083688575, ), - u64x4::new( + u64x4::new_const( 699685108971208, 1719650727634959, 1941668009419214, 870374958347891, ), - u64x4::new( + u64x4::new_const( 385971389331537, 11655507719711, 94814615497633, 515572102810609, ), - u64x4::new( + u64x4::new_const( 1396688200590426, 1518748475144123, 162386454324368, 2083303971579002, ), - u64x4::new( + u64x4::new_const( 1511688632419263, 251584258592336, 545345887993880, @@ -1804,31 +1806,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1298668855706029, 2017860934939344, 2224150456036391, 1925926576297971, ), - u64x4::new( + u64x4::new_const( 259522963883544, 1312469129541229, 1647530465049600, 1113737129047154, ), - u64x4::new( + u64x4::new_const( 733193298663145, 2115712816303403, 897628702762311, 116440277571901, ), - u64x4::new( + u64x4::new_const( 1998719395229750, 1662774553684237, 194395608126452, 98796702872301, ), - u64x4::new( + u64x4::new_const( 2226158244229144, 91961728239158, 526869903032152, @@ -1836,31 +1838,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 472779569333556, 854477760843410, 2070906720349401, 734613359834689, ), - u64x4::new( + u64x4::new_const( 1771897100487404, 1604024196006064, 319699348925383, 437152129592623, ), - u64x4::new( + u64x4::new_const( 627618365135361, 1768642666037955, 588564169143939, 35295037750744, ), - u64x4::new( + u64x4::new_const( 220241884231278, 319104161410840, 1048165719448798, 1583931089774347, ), - u64x4::new( + u64x4::new_const( 166479451884333, 1623611819962804, 59990366193679, @@ -1868,31 +1870,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 1944687327687331, 1328410791053991, 2083980670913902, 609396833380574, ), - u64x4::new( + u64x4::new_const( 1907563845734496, 1385619047697883, 869817384774457, 106642388505109, ), - u64x4::new( + u64x4::new_const( 1006516581737154, 1561918369633937, 1921172883211450, 2216650451558824, ), - u64x4::new( + u64x4::new_const( 1780506017391778, 233064930371847, 1332962603425752, 1380075261612354, ), - u64x4::new( + u64x4::new_const( 1907624789747741, 1310065402098523, 1838275780706825, @@ -1900,31 +1902,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 198729830692545, 100156148743413, 2140568641558859, 2220606475942394, ), - u64x4::new( + u64x4::new_const( 1108788217903741, 1706330932366163, 2050449866410661, 684907598542847, ), - u64x4::new( + u64x4::new_const( 1101958322366646, 659427843062405, 253899933868173, 896574852821269, ), - u64x4::new( + u64x4::new_const( 1157052140740658, 440541103447032, 2173354981480949, 604768603561932, ), - u64x4::new( + u64x4::new_const( 961238337866054, 830849154351308, 1643852412409441, @@ -1932,31 +1934,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 784870637473285, 1180234052037572, 2086951602998715, 419328169540373, ), - u64x4::new( + u64x4::new_const( 1966862397394559, 788036164772123, 2024355635709481, 1471696676696146, ), - u64x4::new( + u64x4::new_const( 1468884300957205, 1408016588131185, 2229595828577885, 240413942963547, ), - u64x4::new( + u64x4::new_const( 1481791691942441, 970648959691160, 1635500996148197, 2236917233261585, ), - u64x4::new( + u64x4::new_const( 31660820731028, 801794768903647, 1069092619607344, @@ -1964,31 +1966,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 911659428682786, 762502588057038, 1311399152500807, 1966922911783311, ), - u64x4::new( + u64x4::new_const( 1229849228728540, 258161307933217, 2140796867375541, 1569345075547911, ), - u64x4::new( + u64x4::new_const( 1487354676143742, 1818317546165791, 811033554173350, 1768788663337616, ), - u64x4::new( + u64x4::new_const( 450017165913234, 962535873747168, 2099104262993585, 503030952485785, ), - u64x4::new( + u64x4::new_const( 1259958681304518, 479589250923541, 1503904042161640, @@ -1996,31 +1998,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 794562643024291, 198670993088241, 1678984629358943, 273399517554618, ), - u64x4::new( + u64x4::new_const( 188458991574433, 1389872130156447, 1461868931574746, 795140878721432, ), - u64x4::new( + u64x4::new_const( 624046647169653, 630363741191019, 911018499983500, 1410140563046579, ), - u64x4::new( + u64x4::new_const( 1675056174405076, 632544713589250, 795454163559811, 1535271563341780, ), - u64x4::new( + u64x4::new_const( 25504547444781, 812510098987855, 51290042016232, @@ -2028,31 +2030,31 @@ pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = Naf ), ])), CachedPoint(F51x4Reduced([ - u64x4::new( + u64x4::new_const( 269968325452358, 470932785179706, 1684444304834150, 1027482126748243, ), - u64x4::new( + u64x4::new_const( 457941065342419, 2117377568137882, 1209423706730905, 2192403099717071, ), - u64x4::new( + u64x4::new_const( 1899046404863678, 1359500336071762, 1492389156724726, 1455627081827750, ), - u64x4::new( + u64x4::new_const( 2016101061876546, 1967000012916571, 582539481696050, 1197538178790094, ), - u64x4::new( + u64x4::new_const( 639684852217504, 1799941252757449, 1470016556327743, diff --git a/src/backend/vector/ifma/edwards.rs b/curve25519-dalek/src/backend/vector/ifma/edwards.rs similarity index 86% rename from src/backend/vector/ifma/edwards.rs rename to curve25519-dalek/src/backend/vector/ifma/edwards.rs index 5c8d81961..f8605fe52 100644 --- a/src/backend/vector/ifma/edwards.rs +++ b/curve25519-dalek/src/backend/vector/ifma/edwards.rs @@ -9,15 +9,20 @@ #![allow(non_snake_case)] -use traits::Identity; +use crate::traits::Identity; -use std::ops::{Add, Neg, Sub}; +use core::ops::{Add, Neg, Sub}; use subtle::Choice; use subtle::ConditionallySelectable; -use edwards; -use window::{LookupTable, NafLookupTable5, NafLookupTable8}; +use curve25519_dalek_derive::unsafe_target_feature; + +use crate::edwards; +use crate::window::{LookupTable, NafLookupTable5}; + +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +use crate::window::NafLookupTable8; use super::constants; use super::field::{F51x4Reduced, F51x4Unreduced, Lanes, Shuffle}; @@ -28,12 +33,14 @@ pub struct ExtendedPoint(pub(super) F51x4Unreduced); #[derive(Copy, Clone, Debug)] pub struct CachedPoint(pub(super) F51x4Reduced); +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for ExtendedPoint { fn from(P: edwards::EdwardsPoint) -> ExtendedPoint { ExtendedPoint(F51x4Unreduced::new(&P.X, &P.Y, &P.Z, &P.T)) } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for edwards::EdwardsPoint { fn from(P: ExtendedPoint) -> edwards::EdwardsPoint { let reduced = F51x4Reduced::from(P.0); @@ -47,6 +54,7 @@ impl From for edwards::EdwardsPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for CachedPoint { fn from(P: ExtendedPoint) -> CachedPoint { let mut x = P.0; @@ -59,24 +67,27 @@ impl From for CachedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Default for ExtendedPoint { fn default() -> ExtendedPoint { ExtendedPoint::identity() } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Identity for ExtendedPoint { fn identity() -> ExtendedPoint { constants::EXTENDEDPOINT_IDENTITY } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl ExtendedPoint { pub fn double(&self) -> ExtendedPoint { // (Y1 X1 T1 Z1) -- uses vpshufd (1c latency @ 1/c) let mut tmp0 = self.0.shuffle(Shuffle::BADC); - // (X1+Y1 X1+Y1 X1+Y1 X1+Y1) -- can use vpinserti128 + // (X1+Y1 X1+Y1 X1+Y1 X1+Y1) -- can use vpinserti128 let mut tmp1 = (self.0 + tmp0).shuffle(Shuffle::ABAB); // (X1 Y1 Z1 X1+Y1) @@ -97,7 +108,7 @@ impl ExtendedPoint { // ======================= // S5 S6 S8 S9 - let zero = F51x4Unreduced::zero(); + let zero = F51x4Unreduced::ZERO; let S1_S1_S1_S1 = tmp1.shuffle(Shuffle::AAAA); let S2_S2_S2_S2 = tmp1.shuffle(Shuffle::BBBB); @@ -122,6 +133,7 @@ impl ExtendedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; @@ -151,18 +163,21 @@ impl<'a, 'b> Add<&'b CachedPoint> for &'a ExtendedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Default for CachedPoint { fn default() -> CachedPoint { CachedPoint::identity() } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Identity for CachedPoint { fn identity() -> CachedPoint { constants::CACHEDPOINT_IDENTITY } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl ConditionallySelectable for CachedPoint { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { CachedPoint(F51x4Reduced::conditional_select(&a.0, &b.0, choice)) @@ -173,6 +188,7 @@ impl ConditionallySelectable for CachedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> Neg for &'a CachedPoint { type Output = CachedPoint; @@ -182,6 +198,7 @@ impl<'a> Neg for &'a CachedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { type Output = ExtendedPoint; @@ -191,6 +208,7 @@ impl<'a, 'b> Sub<&'b CachedPoint> for &'a ExtendedPoint { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { fn from(point: &'a edwards::EdwardsPoint) -> Self { let P = ExtendedPoint::from(*point); @@ -202,6 +220,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for LookupTable { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { fn from(point: &'a edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); @@ -215,6 +234,8 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable5 { } } +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { fn from(point: &'a edwards::EdwardsPoint) -> Self { let A = ExtendedPoint::from(*point); @@ -228,6 +249,7 @@ impl<'a> From<&'a edwards::EdwardsPoint> for NafLookupTable8 { } } +#[cfg(target_feature = "avx512ifma,avx512vl")] #[cfg(test)] mod test { use super::*; @@ -258,8 +280,8 @@ mod test { #[test] fn vector_addition_vs_serial_addition_vs_edwards_extendedpoint() { - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; println!("Testing id +- id"); let P = edwards::EdwardsPoint::identity(); @@ -278,7 +300,7 @@ mod test { println!("Testing B +- kB"); let P = constants::ED25519_BASEPOINT_POINT; - let Q = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + let Q = constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); addition_test_helper(P, Q); } @@ -297,8 +319,8 @@ mod test { #[test] fn vector_doubling_vs_serial_doubling_vs_edwards_extendedpoint() { - use constants; - use scalar::Scalar; + use crate::constants; + use crate::scalar::Scalar; println!("Testing [2]id"); let P = edwards::EdwardsPoint::identity(); @@ -309,7 +331,7 @@ mod test { doubling_test_helper(P); println!("Testing [2]([k]B)"); - let P = &constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); + let P = constants::ED25519_BASEPOINT_TABLE * &Scalar::from(8475983829u64); doubling_test_helper(P); } } diff --git a/src/backend/vector/ifma/field.rs b/curve25519-dalek/src/backend/vector/ifma/field.rs similarity index 84% rename from src/backend/vector/ifma/field.rs rename to curve25519-dalek/src/backend/vector/ifma/field.rs index a393b22fd..fa8ce2dd9 100644 --- a/src/backend/vector/ifma/field.rs +++ b/curve25519-dalek/src/backend/vector/ifma/field.rs @@ -11,23 +11,27 @@ #![allow(non_snake_case)] +use crate::backend::vector::packed_simd::u64x4; use core::ops::{Add, Mul, Neg}; -use packed_simd::{u64x4, IntoBits}; -use backend::serial::u64::field::FieldElement51; +use crate::backend::serial::u64::field::FieldElement51; + +use curve25519_dalek_derive::unsafe_target_feature; /// A wrapper around `vpmadd52luq` that works on `u64x4`. -#[inline(always)] +#[unsafe_target_feature("avx512ifma,avx512vl")] +#[inline] unsafe fn madd52lo(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { use core::arch::x86_64::_mm256_madd52lo_epu64; - _mm256_madd52lo_epu64(z.into_bits(), x.into_bits(), y.into_bits()).into_bits() + _mm256_madd52lo_epu64(z.into(), x.into(), y.into()).into() } /// A wrapper around `vpmadd52huq` that works on `u64x4`. -#[inline(always)] +#[unsafe_target_feature("avx512ifma,avx512vl")] +#[inline] unsafe fn madd52hi(z: u64x4, x: u64x4, y: u64x4) -> u64x4 { use core::arch::x86_64::_mm256_madd52hi_epu64; - _mm256_madd52hi_epu64(z.into_bits(), x.into_bits(), y.into_bits()).into_bits() + _mm256_madd52hi_epu64(z.into(), x.into(), y.into()).into() } /// A vector of four field elements in radix 2^51, with unreduced coefficients. @@ -38,6 +42,7 @@ pub struct F51x4Unreduced(pub(crate) [u64x4; 5]); #[derive(Copy, Clone, Debug)] pub struct F51x4Reduced(pub(crate) [u64x4; 5]); +#[allow(clippy::upper_case_acronyms)] #[derive(Copy, Clone)] pub enum Shuffle { AAAA, @@ -52,26 +57,28 @@ pub enum Shuffle { CACA, } +#[unsafe_target_feature("avx512ifma,avx512vl")] #[inline(always)] fn shuffle_lanes(x: u64x4, control: Shuffle) -> u64x4 { unsafe { use core::arch::x86_64::_mm256_permute4x64_epi64 as perm; match control { - Shuffle::AAAA => perm(x.into_bits(), 0b00_00_00_00).into_bits(), - Shuffle::BBBB => perm(x.into_bits(), 0b01_01_01_01).into_bits(), - Shuffle::BADC => perm(x.into_bits(), 0b10_11_00_01).into_bits(), - Shuffle::BACD => perm(x.into_bits(), 0b11_10_00_01).into_bits(), - Shuffle::ADDA => perm(x.into_bits(), 0b00_11_11_00).into_bits(), - Shuffle::CBCB => perm(x.into_bits(), 0b01_10_01_10).into_bits(), - Shuffle::ABDC => perm(x.into_bits(), 0b10_11_01_00).into_bits(), - Shuffle::ABAB => perm(x.into_bits(), 0b01_00_01_00).into_bits(), - Shuffle::DBBD => perm(x.into_bits(), 0b11_01_01_11).into_bits(), - Shuffle::CACA => perm(x.into_bits(), 0b00_10_00_10).into_bits(), + Shuffle::AAAA => perm(x.into(), 0b00_00_00_00).into(), + Shuffle::BBBB => perm(x.into(), 0b01_01_01_01).into(), + Shuffle::BADC => perm(x.into(), 0b10_11_00_01).into(), + Shuffle::BACD => perm(x.into(), 0b11_10_00_01).into(), + Shuffle::ADDA => perm(x.into(), 0b00_11_11_00).into(), + Shuffle::CBCB => perm(x.into(), 0b01_10_01_10).into(), + Shuffle::ABDC => perm(x.into(), 0b10_11_01_00).into(), + Shuffle::ABAB => perm(x.into(), 0b01_00_01_00).into(), + Shuffle::DBBD => perm(x.into(), 0b11_01_01_11).into(), + Shuffle::CACA => perm(x.into(), 0b00_10_00_10).into(), } } } +#[allow(clippy::upper_case_acronyms)] #[derive(Copy, Clone)] pub enum Lanes { D, @@ -82,26 +89,26 @@ pub enum Lanes { BCD, } +#[unsafe_target_feature("avx512ifma,avx512vl")] #[inline] fn blend_lanes(x: u64x4, y: u64x4, control: Lanes) -> u64x4 { unsafe { use core::arch::x86_64::_mm256_blend_epi32 as blend; match control { - Lanes::D => blend(x.into_bits(), y.into_bits(), 0b11_00_00_00).into_bits(), - Lanes::C => blend(x.into_bits(), y.into_bits(), 0b00_11_00_00).into_bits(), - Lanes::AB => blend(x.into_bits(), y.into_bits(), 0b00_00_11_11).into_bits(), - Lanes::AC => blend(x.into_bits(), y.into_bits(), 0b00_11_00_11).into_bits(), - Lanes::AD => blend(x.into_bits(), y.into_bits(), 0b11_00_00_11).into_bits(), - Lanes::BCD => blend(x.into_bits(), y.into_bits(), 0b11_11_11_00).into_bits(), + Lanes::D => blend(x.into(), y.into(), 0b11_00_00_00).into(), + Lanes::C => blend(x.into(), y.into(), 0b00_11_00_00).into(), + Lanes::AB => blend(x.into(), y.into(), 0b00_00_11_11).into(), + Lanes::AC => blend(x.into(), y.into(), 0b00_11_00_11).into(), + Lanes::AD => blend(x.into(), y.into(), 0b11_00_00_11).into(), + Lanes::BCD => blend(x.into(), y.into(), 0b11_11_11_00).into(), } } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl F51x4Unreduced { - pub fn zero() -> F51x4Unreduced { - F51x4Unreduced([u64x4::splat(0); 5]) - } + pub const ZERO: F51x4Unreduced = F51x4Unreduced([u64x4::splat_const::<0>(); 5]); pub fn new( x0: &FieldElement51, @@ -122,32 +129,32 @@ impl F51x4Unreduced { let x = &self.0; [ FieldElement51([ - x[0].extract(0), - x[1].extract(0), - x[2].extract(0), - x[3].extract(0), - x[4].extract(0), + x[0].extract::<0>(), + x[1].extract::<0>(), + x[2].extract::<0>(), + x[3].extract::<0>(), + x[4].extract::<0>(), ]), FieldElement51([ - x[0].extract(1), - x[1].extract(1), - x[2].extract(1), - x[3].extract(1), - x[4].extract(1), + x[0].extract::<1>(), + x[1].extract::<1>(), + x[2].extract::<1>(), + x[3].extract::<1>(), + x[4].extract::<1>(), ]), FieldElement51([ - x[0].extract(2), - x[1].extract(2), - x[2].extract(2), - x[3].extract(2), - x[4].extract(2), + x[0].extract::<2>(), + x[1].extract::<2>(), + x[2].extract::<2>(), + x[3].extract::<2>(), + x[4].extract::<2>(), ]), FieldElement51([ - x[0].extract(3), - x[1].extract(3), - x[2].extract(3), - x[3].extract(3), - x[4].extract(3), + x[0].extract::<3>(), + x[1].extract::<3>(), + x[2].extract::<3>(), + x[3].extract::<3>(), + x[4].extract::<3>(), ]), ] } @@ -198,6 +205,7 @@ impl F51x4Unreduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Neg for F51x4Reduced { type Output = F51x4Reduced; @@ -209,6 +217,7 @@ impl Neg for F51x4Reduced { use subtle::Choice; use subtle::ConditionallySelectable; +#[unsafe_target_feature("avx512ifma,avx512vl")] impl ConditionallySelectable for F51x4Reduced { #[inline] fn conditional_select(a: &F51x4Reduced, b: &F51x4Reduced, choice: Choice) -> F51x4Reduced { @@ -235,6 +244,7 @@ impl ConditionallySelectable for F51x4Reduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl F51x4Reduced { #[inline] pub fn shuffle(&self, control: Shuffle) -> F51x4Reduced { @@ -291,64 +301,64 @@ impl F51x4Reduced { z1_2 = madd52hi(z1_2, x[0], x[0]); z2_4 = madd52hi(z2_4, x[0], x[1]); - let mut z2_1 = z2_4 << 2; + let mut z2_1 = z2_4.shl::<2>(); z2_2 = madd52lo(z2_2, x[0], x[2]); z2_1 = madd52lo(z2_1, x[1], x[1]); z3_4 = madd52hi(z3_4, x[0], x[2]); - let mut z3_1 = z3_4 << 2; + let mut z3_1 = z3_4.shl::<2>(); z3_2 = madd52lo(z3_2, x[1], x[2]); z3_2 = madd52lo(z3_2, x[0], x[3]); z3_2 = madd52hi(z3_2, x[1], x[1]); z4_4 = madd52hi(z4_4, x[1], x[2]); z4_4 = madd52hi(z4_4, x[0], x[3]); - let mut z4_1 = z4_4 << 2; + let mut z4_1 = z4_4.shl::<2>(); z4_2 = madd52lo(z4_2, x[1], x[3]); z4_2 = madd52lo(z4_2, x[0], x[4]); z4_1 = madd52lo(z4_1, x[2], x[2]); z5_4 = madd52hi(z5_4, x[1], x[3]); z5_4 = madd52hi(z5_4, x[0], x[4]); - let mut z5_1 = z5_4 << 2; + let mut z5_1 = z5_4.shl::<2>(); z5_2 = madd52lo(z5_2, x[2], x[3]); z5_2 = madd52lo(z5_2, x[1], x[4]); z5_2 = madd52hi(z5_2, x[2], x[2]); z6_4 = madd52hi(z6_4, x[2], x[3]); z6_4 = madd52hi(z6_4, x[1], x[4]); - let mut z6_1 = z6_4 << 2; + let mut z6_1 = z6_4.shl::<2>(); z6_2 = madd52lo(z6_2, x[2], x[4]); z6_1 = madd52lo(z6_1, x[3], x[3]); z7_4 = madd52hi(z7_4, x[2], x[4]); - let mut z7_1 = z7_4 << 2; + let mut z7_1 = z7_4.shl::<2>(); z7_2 = madd52lo(z7_2, x[3], x[4]); z7_2 = madd52hi(z7_2, x[3], x[3]); z8_4 = madd52hi(z8_4, x[3], x[4]); - let mut z8_1 = z8_4 << 2; + let mut z8_1 = z8_4.shl::<2>(); z8_1 = madd52lo(z8_1, x[4], x[4]); let mut z9_1 = u64x4::splat(0); z9_2 = madd52hi(z9_2, x[4], x[4]); - z5_1 += z5_2 << 1; - z6_1 += z6_2 << 1; - z7_1 += z7_2 << 1; - z9_1 += z9_2 << 1; + z5_1 += z5_2.shl::<1>(); + z6_1 += z6_2.shl::<1>(); + z7_1 += z7_2.shl::<1>(); + z9_1 += z9_2.shl::<1>(); let mut t0 = u64x4::splat(0); let mut t1 = u64x4::splat(0); let r19 = u64x4::splat(19); t0 = madd52hi(t0, r19, z9_1); - t1 = madd52lo(t1, r19, z9_1 >> 52); + t1 = madd52lo(t1, r19, z9_1.shr::<52>()); - z4_2 = madd52lo(z4_2, r19, z8_1 >> 52); - z3_2 = madd52lo(z3_2, r19, z7_1 >> 52); - z2_2 = madd52lo(z2_2, r19, z6_1 >> 52); - z1_2 = madd52lo(z1_2, r19, z5_1 >> 52); + z4_2 = madd52lo(z4_2, r19, z8_1.shr::<52>()); + z3_2 = madd52lo(z3_2, r19, z7_1.shr::<52>()); + z2_2 = madd52lo(z2_2, r19, z6_1.shr::<52>()); + z1_2 = madd52lo(z1_2, r19, z5_1.shr::<52>()); z0_2 = madd52lo(z0_2, r19, t0 + t1); z1_2 = madd52hi(z1_2, r19, z5_1); @@ -373,6 +383,7 @@ impl F51x4Reduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for F51x4Unreduced { #[inline] fn from(x: F51x4Reduced) -> F51x4Unreduced { @@ -380,6 +391,7 @@ impl From for F51x4Unreduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl From for F51x4Reduced { #[inline] fn from(x: F51x4Unreduced) -> F51x4Reduced { @@ -387,11 +399,11 @@ impl From for F51x4Reduced { let r19 = u64x4::splat(19); // Compute carryouts in parallel - let c0 = x.0[0] >> 51; - let c1 = x.0[1] >> 51; - let c2 = x.0[2] >> 51; - let c3 = x.0[3] >> 51; - let c4 = x.0[4] >> 51; + let c0 = x.0[0].shr::<51>(); + let c1 = x.0[1].shr::<51>(); + let c2 = x.0[2].shr::<51>(); + let c3 = x.0[3].shr::<51>(); + let c4 = x.0[4].shr::<51>(); unsafe { F51x4Reduced([ @@ -405,6 +417,7 @@ impl From for F51x4Reduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl Add for F51x4Unreduced { type Output = F51x4Unreduced; #[inline] @@ -419,6 +432,7 @@ impl Add for F51x4Unreduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced { type Output = F51x4Unreduced; #[inline] @@ -470,6 +484,7 @@ impl<'a> Mul<(u32, u32, u32, u32)> for &'a F51x4Reduced { } } +#[unsafe_target_feature("avx512ifma,avx512vl")] impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { type Output = F51x4Unreduced; #[inline] @@ -581,12 +596,12 @@ impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { // Wave 6 t0 = madd52hi(t0, r19, z9); - t1 = madd52lo(t1, r19, z9 >> 52); + t1 = madd52lo(t1, r19, z9.shr::<52>()); z3_1 = madd52lo(z3_1, x[0], y[3]); z4_2 = madd52hi(z4_2, x[0], y[3]); - z1_2 = madd52lo(z1_2, r19, z5 >> 52); - z2_2 = madd52lo(z2_2, r19, z6 >> 52); - z3_2 = madd52lo(z3_2, r19, z7 >> 52); + z1_2 = madd52lo(z1_2, r19, z5.shr::<52>()); + z2_2 = madd52lo(z2_2, r19, z6.shr::<52>()); + z3_2 = madd52lo(z3_2, r19, z7.shr::<52>()); z0_1 = madd52lo(z0_1, r19, z5); // Wave 7 @@ -601,7 +616,7 @@ impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { // Wave 8 z3_1 = madd52lo(z3_1, r19, z8); - z4_2 = madd52lo(z4_2, r19, z8 >> 52); + z4_2 = madd52lo(z4_2, r19, z8.shr::<52>()); F51x4Unreduced([ z0_1 + z0_2 + z0_2, @@ -614,6 +629,7 @@ impl<'a, 'b> Mul<&'b F51x4Reduced> for &'a F51x4Reduced { } } +#[cfg(target_feature = "avx512ifma,avx512vl")] #[cfg(test)] mod test { use super::*; diff --git a/src/backend/vector/ifma/mod.rs b/curve25519-dalek/src/backend/vector/ifma/mod.rs similarity index 62% rename from src/backend/vector/ifma/mod.rs rename to curve25519-dalek/src/backend/vector/ifma/mod.rs index 6191ecc0c..f48748d21 100644 --- a/src/backend/vector/ifma/mod.rs +++ b/curve25519-dalek/src/backend/vector/ifma/mod.rs @@ -7,13 +7,14 @@ // Authors: // - Henry de Valence -#![cfg_attr( - feature = "nightly", - doc(include = "../../../../docs/ifma-notes.md") -)] +#![doc = include_str!("../../../../docs/ifma-notes.md")] +#[allow(missing_docs)] pub mod field; +#[allow(missing_docs)] pub mod edwards; pub mod constants; + +pub(crate) use self::edwards::{CachedPoint, ExtendedPoint}; diff --git a/src/prelude.rs b/curve25519-dalek/src/backend/vector/mod.rs similarity index 58% rename from src/prelude.rs rename to curve25519-dalek/src/backend/vector/mod.rs index 5c0a611a3..2839dca45 100644 --- a/src/prelude.rs +++ b/curve25519-dalek/src/backend/vector/mod.rs @@ -9,11 +9,14 @@ // - isis agora lovecruft // - Henry de Valence -//! Crate-local prelude (for alloc-dependent features like `Vec`) +#![doc = include_str!("../../../docs/parallel-formulas.md")] -// TODO: switch to alloc::prelude -#[cfg(all(feature = "alloc", not(feature = "std")))] -pub use alloc::vec::Vec; +#[allow(missing_docs)] +pub mod packed_simd; -#[cfg(feature = "std")] -pub use std::vec::Vec; +pub mod avx2; + +#[cfg(nightly)] +pub mod ifma; + +pub mod scalar_mul; diff --git a/curve25519-dalek/src/backend/vector/packed_simd.rs b/curve25519-dalek/src/backend/vector/packed_simd.rs new file mode 100644 index 000000000..fe83b1865 --- /dev/null +++ b/curve25519-dalek/src/backend/vector/packed_simd.rs @@ -0,0 +1,337 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// See LICENSE for licensing information. + +//! This module defines wrappers over platform-specific SIMD types to make them +//! more convenient to use. +//! +//! UNSAFETY: Everything in this module assumes that we're running on hardware +//! which supports at least AVX2. This invariant *must* be enforced +//! by the callers of this code. +use core::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitXor, BitXorAssign, Sub}; + +use curve25519_dalek_derive::unsafe_target_feature; + +macro_rules! impl_shared { + ( + $ty:ident, + $lane_ty:ident, + $add_intrinsic:ident, + $sub_intrinsic:ident, + $shl_intrinsic:ident, + $shr_intrinsic:ident, + $extract_intrinsic:ident + ) => { + #[allow(non_camel_case_types)] + #[derive(Copy, Clone, Debug)] + #[repr(transparent)] + pub struct $ty(core::arch::x86_64::__m256i); + + #[unsafe_target_feature("avx2")] + impl From<$ty> for core::arch::x86_64::__m256i { + #[inline] + fn from(value: $ty) -> core::arch::x86_64::__m256i { + value.0 + } + } + + #[unsafe_target_feature("avx2")] + impl From for $ty { + #[inline] + fn from(value: core::arch::x86_64::__m256i) -> $ty { + $ty(value) + } + } + + #[unsafe_target_feature("avx2")] + impl PartialEq for $ty { + #[inline] + fn eq(&self, rhs: &$ty) -> bool { + unsafe { + // This compares each pair of 8-bit packed integers and returns either 0xFF or + // 0x00 depending on whether they're equal. + // + // So the values are equal if (and only if) this returns a value that's filled + // with only 0xFF. + // + // Pseudocode of what this does: + // self.0 + // .bytes() + // .zip(rhs.0.bytes()) + // .map(|a, b| if a == b { 0xFF } else { 0x00 }) + // .join(); + let m = core::arch::x86_64::_mm256_cmpeq_epi8(self.0, rhs.0); + + // Now we need to reduce the 256-bit value to something on which we can branch. + // + // This will just take the most significant bit of every 8-bit packed integer + // and build an `i32` out of it. If the values we previously compared were + // equal then all off the most significant bits will be equal to 1, which means + // that this will return 0xFFFFFFFF, which is equal to -1 when represented as + // an `i32`. + core::arch::x86_64::_mm256_movemask_epi8(m) == -1 + } + } + } + + impl Eq for $ty {} + + #[unsafe_target_feature("avx2")] + impl Add for $ty { + type Output = Self; + + #[inline] + fn add(self, rhs: $ty) -> Self { + unsafe { core::arch::x86_64::$add_intrinsic(self.0, rhs.0).into() } + } + } + + #[allow(clippy::assign_op_pattern)] + #[unsafe_target_feature("avx2")] + impl AddAssign for $ty { + #[inline] + fn add_assign(&mut self, rhs: $ty) { + *self = *self + rhs + } + } + + #[unsafe_target_feature("avx2")] + impl Sub for $ty { + type Output = Self; + + #[inline] + fn sub(self, rhs: $ty) -> Self { + unsafe { core::arch::x86_64::$sub_intrinsic(self.0, rhs.0).into() } + } + } + + #[unsafe_target_feature("avx2")] + impl BitAnd for $ty { + type Output = Self; + + #[inline] + fn bitand(self, rhs: $ty) -> Self { + unsafe { core::arch::x86_64::_mm256_and_si256(self.0, rhs.0).into() } + } + } + + #[unsafe_target_feature("avx2")] + impl BitXor for $ty { + type Output = Self; + + #[inline] + fn bitxor(self, rhs: $ty) -> Self { + unsafe { core::arch::x86_64::_mm256_xor_si256(self.0, rhs.0).into() } + } + } + + #[allow(clippy::assign_op_pattern)] + #[unsafe_target_feature("avx2")] + impl BitAndAssign for $ty { + #[inline] + fn bitand_assign(&mut self, rhs: $ty) { + *self = *self & rhs; + } + } + + #[allow(clippy::assign_op_pattern)] + #[unsafe_target_feature("avx2")] + impl BitXorAssign for $ty { + #[inline] + fn bitxor_assign(&mut self, rhs: $ty) { + *self = *self ^ rhs; + } + } + + #[unsafe_target_feature("avx2")] + #[allow(dead_code)] + impl $ty { + #[inline] + pub fn shl(self) -> Self { + unsafe { core::arch::x86_64::$shl_intrinsic(self.0, N).into() } + } + + #[inline] + pub fn shr(self) -> Self { + unsafe { core::arch::x86_64::$shr_intrinsic(self.0, N).into() } + } + + #[inline] + pub fn extract(self) -> $lane_ty { + unsafe { core::arch::x86_64::$extract_intrinsic(self.0, N) as $lane_ty } + } + } + }; +} + +macro_rules! impl_conv { + ($src:ident => $($dst:ident),+) => { + $( + #[unsafe_target_feature("avx2")] + impl From<$src> for $dst { + #[inline] + fn from(value: $src) -> $dst { + $dst(value.0) + } + } + )+ + } +} + +// We define SIMD functionality over packed unsigned integer types. However, all the integer +// intrinsics deal with signed integers. So we cast unsigned to signed, pack it into SIMD, do +// add/sub/shl/shr arithmetic, and finally cast back to unsigned at the end. Why is this equivalent +// to doing the same thing on unsigned integers? Shl/shr is clear, because casting does not change +// the bits of the integer. But what about add/sub? This is due to the following: +// +// 1) Rust uses two's complement to represent signed integers. So we're assured that the values +// we cast into SIMD and extract out at the end are two's complement. +// +// https://doc.rust-lang.org/reference/types/numeric.html +// +// 2) Wrapping add/sub is compatible between two's complement signed and unsigned integers. +// That is, for all x,y: u64 (or any unsigned integer type), +// +// x.wrapping_add(y) == (x as i64).wrapping_add(y as i64) as u64, and +// x.wrapping_sub(y) == (x as i64).wrapping_sub(y as i64) as u64 +// +// https://julesjacobs.com/2019/03/20/why-twos-complement-works.html +// +// 3) The add/sub functions we use for SIMD are indeed wrapping. The docs indicate that +// __mm256_add/sub compile to vpaddX/vpsubX instructions where X = w, d, or q depending on +// the bitwidth. From x86 docs: +// +// When an individual result is too large to be represented in X bits (overflow), the +// result is wrapped around and the low X bits are written to the destination operand +// (that is, the carry is ignored). +// +// https://www.felixcloutier.com/x86/paddb:paddw:paddd:paddq +// https://www.felixcloutier.com/x86/psubb:psubw:psubd +// https://www.felixcloutier.com/x86/psubq + +impl_shared!( + u64x4, + u64, + _mm256_add_epi64, + _mm256_sub_epi64, + _mm256_slli_epi64, + _mm256_srli_epi64, + _mm256_extract_epi64 +); +impl_shared!( + u32x8, + u32, + _mm256_add_epi32, + _mm256_sub_epi32, + _mm256_slli_epi32, + _mm256_srli_epi32, + _mm256_extract_epi32 +); + +impl_conv!(u64x4 => u32x8); + +#[allow(dead_code)] +impl u64x4 { + /// A constified variant of `new`. + /// + /// Should only be called from `const` contexts. At runtime `new` is going to be faster. + #[inline] + pub const fn new_const(x0: u64, x1: u64, x2: u64, x3: u64) -> Self { + // SAFETY: Transmuting between an array and a SIMD type is safe + // https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html + unsafe { Self(core::mem::transmute([x0, x1, x2, x3])) } + } + + /// A constified variant of `splat`. + /// + /// Should only be called from `const` contexts. At runtime `splat` is going to be faster. + #[inline] + pub const fn splat_const() -> Self { + Self::new_const(N, N, N, N) + } + + /// Constructs a new instance. + #[unsafe_target_feature("avx2")] + #[inline] + pub fn new(x0: u64, x1: u64, x2: u64, x3: u64) -> u64x4 { + unsafe { + // _mm256_set_epi64 sets the underlying vector in reverse order of the args + u64x4(core::arch::x86_64::_mm256_set_epi64x( + x3 as i64, x2 as i64, x1 as i64, x0 as i64, + )) + } + } + + /// Constructs a new instance with all of the elements initialized to the given value. + #[unsafe_target_feature("avx2")] + #[inline] + pub fn splat(x: u64) -> u64x4 { + unsafe { u64x4(core::arch::x86_64::_mm256_set1_epi64x(x as i64)) } + } +} + +#[allow(dead_code)] +impl u32x8 { + /// A constified variant of `new`. + /// + /// Should only be called from `const` contexts. At runtime `new` is going to be faster. + #[allow(clippy::too_many_arguments)] + #[inline] + pub const fn new_const( + x0: u32, + x1: u32, + x2: u32, + x3: u32, + x4: u32, + x5: u32, + x6: u32, + x7: u32, + ) -> Self { + // SAFETY: Transmuting between an array and a SIMD type is safe + // https://rust-lang.github.io/unsafe-code-guidelines/layout/packed-simd-vectors.html + unsafe { Self(core::mem::transmute([x0, x1, x2, x3, x4, x5, x6, x7])) } + } + + /// A constified variant of `splat`. + /// + /// Should only be called from `const` contexts. At runtime `splat` is going to be faster. + #[inline] + pub const fn splat_const() -> Self { + Self::new_const(N, N, N, N, N, N, N, N) + } + + /// Constructs a new instance. + #[allow(clippy::too_many_arguments)] + #[unsafe_target_feature("avx2")] + #[inline] + pub fn new(x0: u32, x1: u32, x2: u32, x3: u32, x4: u32, x5: u32, x6: u32, x7: u32) -> u32x8 { + unsafe { + // _mm256_set_epi32 sets the underlying vector in reverse order of the args + u32x8(core::arch::x86_64::_mm256_set_epi32( + x7 as i32, x6 as i32, x5 as i32, x4 as i32, x3 as i32, x2 as i32, x1 as i32, + x0 as i32, + )) + } + } + + /// Constructs a new instance with all of the elements initialized to the given value. + #[unsafe_target_feature("avx2")] + #[inline] + pub fn splat(x: u32) -> u32x8 { + unsafe { u32x8(core::arch::x86_64::_mm256_set1_epi32(x as i32)) } + } +} + +#[unsafe_target_feature("avx2")] +impl u32x8 { + /// Multiplies the low unsigned 32-bits from each packed 64-bit element + /// and returns the unsigned 64-bit results. + /// + /// (This ignores the upper 32-bits from each packed 64-bits!) + #[inline] + pub fn mul32(self, rhs: u32x8) -> u64x4 { + // NOTE: This ignores the upper 32-bits from each packed 64-bits. + unsafe { core::arch::x86_64::_mm256_mul_epu32(self.0, rhs.0).into() } + } +} diff --git a/src/backend/vector/scalar_mul/mod.rs b/curve25519-dalek/src/backend/vector/scalar_mul/mod.rs similarity index 72% rename from src/backend/vector/scalar_mul/mod.rs rename to curve25519-dalek/src/backend/vector/scalar_mul/mod.rs index 36a7047a2..fed3470e7 100644 --- a/src/backend/vector/scalar_mul/mod.rs +++ b/curve25519-dalek/src/backend/vector/scalar_mul/mod.rs @@ -9,15 +9,22 @@ // - isis agora lovecruft // - Henry de Valence +//! Implementations of various multiplication algorithms for the SIMD backends. + +#[allow(missing_docs)] pub mod variable_base; +#[allow(missing_docs)] pub mod vartime_double_base; +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub mod straus; +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub mod precomputed_straus; +#[allow(missing_docs)] #[cfg(feature = "alloc")] pub mod pippenger; diff --git a/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs b/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs new file mode 100644 index 000000000..1376c4eab --- /dev/null +++ b/curve25519-dalek/src/backend/vector/scalar_mul/pippenger.rs @@ -0,0 +1,176 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Oleg Andreev +// See LICENSE for licensing information. +// +// Authors: +// - Oleg Andreev + +#![allow(non_snake_case)] + +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) +)] +pub mod spec { + + use alloc::vec::Vec; + + use core::borrow::Borrow; + use core::cmp::Ordering; + + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::{Identity, VartimeMultiscalarMul}; + + /// Implements a version of Pippenger's algorithm. + /// + /// See the documentation in the serial `scalar_mul::pippenger` module for details. + pub struct Pippenger; + + impl VartimeMultiscalarMul for Pippenger { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + let mut scalars = scalars.into_iter(); + let size = scalars.by_ref().size_hint().0; + let w = if size < 500 { + 6 + } else if size < 800 { + 7 + } else { + 8 + }; + + let max_digit: usize = 1 << w; + let digits_count: usize = Scalar::to_radix_2w_size_hint(w); + let buckets_count: usize = max_digit / 2; // digits are signed+centered hence 2^w/2, excluding 0-th bucket + + // Collect optimized scalars and points in a buffer for repeated access + // (scanning the whole collection per each digit position). + let scalars = scalars.map(|s| s.borrow().as_radix_2w(w)); + + let points = points + .into_iter() + .map(|p| p.map(|P| CachedPoint::from(ExtendedPoint::from(P)))); + + let scalars_points = scalars + .zip(points) + .map(|(s, maybe_p)| maybe_p.map(|p| (s, p))) + .collect::>>()?; + + // Prepare 2^w/2 buckets. + // buckets[i] corresponds to a multiplication factor (i+1). + let mut buckets: Vec = (0..buckets_count) + .map(|_| ExtendedPoint::identity()) + .collect(); + + let mut columns = (0..digits_count).rev().map(|digit_index| { + // Clear the buckets when processing another digit. + for bucket in &mut buckets { + *bucket = ExtendedPoint::identity(); + } + + // Iterate over pairs of (point, scalar) + // and add/sub the point to the corresponding bucket. + // Note: if we add support for precomputed lookup tables, + // we'll be adding/subtractiong point premultiplied by `digits[i]` to buckets[0]. + for (digits, pt) in scalars_points.iter() { + // Widen digit so that we don't run into edge cases when w=8. + let digit = digits[digit_index] as i16; + match digit.cmp(&0) { + Ordering::Greater => { + let b = (digit - 1) as usize; + buckets[b] = &buckets[b] + pt; + } + Ordering::Less => { + let b = (-digit - 1) as usize; + buckets[b] = &buckets[b] - pt; + } + Ordering::Equal => {} + } + } + + // Add the buckets applying the multiplication factor to each bucket. + // The most efficient way to do that is to have a single sum with two running sums: + // an intermediate sum from last bucket to the first, and a sum of intermediate sums. + // + // For example, to add buckets 1*A, 2*B, 3*C we need to add these points: + // C + // C B + // C B A Sum = C + (C+B) + (C+B+A) + let mut buckets_intermediate_sum = buckets[buckets_count - 1]; + let mut buckets_sum = buckets[buckets_count - 1]; + for i in (0..(buckets_count - 1)).rev() { + buckets_intermediate_sum = + &buckets_intermediate_sum + &CachedPoint::from(buckets[i]); + buckets_sum = &buckets_sum + &CachedPoint::from(buckets_intermediate_sum); + } + + buckets_sum + }); + + // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. + let hi_column = columns.next().expect("should have more than zero digits"); + + Some( + columns + .fold(hi_column, |total, p| { + &total.mul_by_pow_2(w as u32) + &CachedPoint::from(p) + }) + .into(), + ) + } + } + + #[cfg(test)] + mod test { + #[test] + fn test_vartime_pippenger() { + use super::*; + use crate::constants; + use crate::scalar::Scalar; + + // Reuse points across different tests + let mut n = 512; + let x = Scalar::from(2128506u64).invert(); + let y = Scalar::from(4443282u64).invert(); + let points: Vec<_> = (0..n) + .map(|i| constants::ED25519_BASEPOINT_POINT * Scalar::from(1 + i as u64)) + .collect(); + let scalars: Vec<_> = (0..n) + .map(|i| x + (Scalar::from(i as u64) * y)) // fast way to make ~random but deterministic scalars + .collect(); + + let premultiplied: Vec = scalars + .iter() + .zip(points.iter()) + .map(|(sc, pt)| sc * pt) + .collect(); + + while n > 0 { + let scalars = &scalars[0..n].to_vec(); + let points = &points[0..n].to_vec(); + let control: EdwardsPoint = premultiplied[0..n].iter().sum(); + + let subject = Pippenger::vartime_multiscalar_mul(scalars.clone(), points.clone()); + + assert_eq!(subject.compress(), control.compress()); + + n = n / 2; + } + } + } +} diff --git a/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs b/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs new file mode 100644 index 000000000..515b4040c --- /dev/null +++ b/curve25519-dalek/src/backend/vector/scalar_mul/precomputed_straus.rs @@ -0,0 +1,127 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2019 Henry de Valence. +// See LICENSE for licensing information. +// +// Authors: +// - Henry de Valence + +//! Precomputation for Straus's method. + +#![allow(non_snake_case)] + +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) +)] +pub mod spec { + + use alloc::vec::Vec; + + use core::borrow::Borrow; + use core::cmp::Ordering; + + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::Identity; + use crate::traits::VartimePrecomputedMultiscalarMul; + use crate::window::{NafLookupTable5, NafLookupTable8}; + + pub struct VartimePrecomputedStraus { + static_lookup_tables: Vec>, + } + + impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { + type Point = EdwardsPoint; + + fn new(static_points: I) -> Self + where + I: IntoIterator, + I::Item: Borrow, + { + Self { + static_lookup_tables: static_points + .into_iter() + .map(|P| NafLookupTable8::::from(P.borrow())) + .collect(), + } + } + + fn optional_mixed_multiscalar_mul( + &self, + static_scalars: I, + dynamic_scalars: J, + dynamic_points: K, + ) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + K: IntoIterator>, + { + let static_nafs = static_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + let dynamic_nafs: Vec<_> = dynamic_scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect::>(); + + let dynamic_lookup_tables = dynamic_points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let sp = self.static_lookup_tables.len(); + let dp = dynamic_lookup_tables.len(); + assert_eq!(sp, static_nafs.len()); + assert_eq!(dp, dynamic_nafs.len()); + + // We could save some doublings by looking for the highest + // nonzero NAF coefficient, but since we might have a lot of + // them to search, it's not clear it's worthwhile to check. + let mut R = ExtendedPoint::identity(); + for j in (0..256).rev() { + R = R.double(); + + for i in 0..dp { + let t_ij = dynamic_nafs[i][j]; + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R + &dynamic_lookup_tables[i].select(t_ij as usize); + } + Ordering::Less => { + R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize); + } + Ordering::Equal => {} + } + } + + #[allow(clippy::needless_range_loop)] + for i in 0..sp { + let t_ij = static_nafs[i][j]; + match t_ij.cmp(&0) { + Ordering::Greater => { + R = &R + &self.static_lookup_tables[i].select(t_ij as usize); + } + Ordering::Less => { + R = &R - &self.static_lookup_tables[i].select(-t_ij as usize); + } + Ordering::Equal => {} + } + } + } + + Some(R.into()) + } + } +} diff --git a/curve25519-dalek/src/backend/vector/scalar_mul/straus.rs b/curve25519-dalek/src/backend/vector/scalar_mul/straus.rs new file mode 100644 index 000000000..413e6fd9a --- /dev/null +++ b/curve25519-dalek/src/backend/vector/scalar_mul/straus.rs @@ -0,0 +1,126 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +#![allow(non_snake_case)] + +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) +)] +pub mod spec { + + use alloc::vec::Vec; + + use core::borrow::Borrow; + use core::cmp::Ordering; + + #[cfg(feature = "zeroize")] + use zeroize::Zeroizing; + + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; + use crate::window::{LookupTable, NafLookupTable5}; + + /// Multiscalar multiplication using interleaved window / Straus' + /// method. See the `Straus` struct in the serial backend for more + /// details. + /// + /// This exists as a seperate implementation from that one because the + /// AVX2 code uses different curve models (it does not pass between + /// multiple models during scalar mul), and it has to convert the + /// point representation on the fly. + pub struct Straus {} + + impl MultiscalarMul for Straus { + type Point = EdwardsPoint; + + fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator, + J::Item: Borrow, + { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + // for each input point P + let lookup_tables: Vec<_> = points + .into_iter() + .map(|point| LookupTable::::from(point.borrow())) + .collect(); + + let scalar_digits_vec: Vec<_> = scalars + .into_iter() + .map(|s| s.borrow().as_radix_16()) + .collect(); + // Pass ownership to a `Zeroizing` wrapper + #[cfg(feature = "zeroize")] + let scalar_digits_vec = Zeroizing::new(scalar_digits_vec); + + let mut Q = ExtendedPoint::identity(); + for j in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + let it = scalar_digits_vec.iter().zip(lookup_tables.iter()); + for (s_i, lookup_table_i) in it { + // Q = Q + s_{i,j} * P_i + Q = &Q + &lookup_table_i.select(s_i[j]); + } + } + Q.into() + } + } + + impl VartimeMultiscalarMul for Straus { + type Point = EdwardsPoint; + + fn optional_multiscalar_mul(scalars: I, points: J) -> Option + where + I: IntoIterator, + I::Item: Borrow, + J: IntoIterator>, + { + let nafs: Vec<_> = scalars + .into_iter() + .map(|c| c.borrow().non_adjacent_form(5)) + .collect(); + let lookup_tables: Vec<_> = points + .into_iter() + .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) + .collect::>>()?; + + let mut Q = ExtendedPoint::identity(); + + for i in (0..256).rev() { + Q = Q.double(); + + for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { + match naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &lookup_table.select(naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &lookup_table.select(-naf[i] as usize); + } + Ordering::Equal => {} + } + } + } + + Some(Q.into()) + } + } +} diff --git a/curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs b/curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs new file mode 100644 index 000000000..9f924f286 --- /dev/null +++ b/curve25519-dalek/src/backend/vector/scalar_mul/variable_base.rs @@ -0,0 +1,44 @@ +#![allow(non_snake_case)] + +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) +)] +pub mod spec { + + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::Identity; + use crate::window::LookupTable; + + /// Perform constant-time, variable-base scalar multiplication. + pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { + // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] + let lookup_table = LookupTable::::from(point); + // Setting s = scalar, compute + // + // s = s_0 + s_1*16^1 + ... + s_63*16^63, + // + // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. + let scalar_digits = scalar.as_radix_16(); + // Compute s*P as + // + // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) + // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 + // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) + // + // We sum right-to-left. + let mut Q = ExtendedPoint::identity(); + for i in (0..64).rev() { + Q = Q.mul_by_pow_2(4); + Q = &Q + &lookup_table.select(scalar_digits[i]); + } + Q.into() + } +} diff --git a/curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs b/curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs new file mode 100644 index 000000000..ea2af8ad4 --- /dev/null +++ b/curve25519-dalek/src/backend/vector/scalar_mul/vartime_double_base.rs @@ -0,0 +1,101 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +#![allow(non_snake_case)] + +#[curve25519_dalek_derive::unsafe_target_feature_specialize( + "avx2", + conditional("avx512ifma,avx512vl", nightly) +)] +pub mod spec { + + use core::cmp::Ordering; + + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::{CachedPoint, ExtendedPoint}; + + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::{CachedPoint, ExtendedPoint}; + + #[cfg(feature = "precomputed-tables")] + #[for_target_feature("avx2")] + use crate::backend::vector::avx2::constants::BASEPOINT_ODD_LOOKUP_TABLE; + + #[cfg(feature = "precomputed-tables")] + #[for_target_feature("avx512ifma")] + use crate::backend::vector::ifma::constants::BASEPOINT_ODD_LOOKUP_TABLE; + + use crate::edwards::EdwardsPoint; + use crate::scalar::Scalar; + use crate::traits::Identity; + use crate::window::NafLookupTable5; + + /// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. + pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { + let a_naf = a.non_adjacent_form(5); + + #[cfg(feature = "precomputed-tables")] + let b_naf = b.non_adjacent_form(8); + #[cfg(not(feature = "precomputed-tables"))] + let b_naf = b.non_adjacent_form(5); + + // Find starting index + let mut i: usize = 255; + for j in (0..256).rev() { + i = j; + if a_naf[i] != 0 || b_naf[i] != 0 { + break; + } + } + + let table_A = NafLookupTable5::::from(A); + + #[cfg(feature = "precomputed-tables")] + let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; + + #[cfg(not(feature = "precomputed-tables"))] + let table_B = + &NafLookupTable5::::from(&crate::constants::ED25519_BASEPOINT_POINT); + + let mut Q = ExtendedPoint::identity(); + + loop { + Q = Q.double(); + + match a_naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &table_A.select(a_naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &table_A.select(-a_naf[i] as usize); + } + Ordering::Equal => {} + } + + match b_naf[i].cmp(&0) { + Ordering::Greater => { + Q = &Q + &table_B.select(b_naf[i] as usize); + } + Ordering::Less => { + Q = &Q - &table_B.select(-b_naf[i] as usize); + } + Ordering::Equal => {} + } + + if i == 0 { + break; + } + i -= 1; + } + + Q.into() + } +} diff --git a/curve25519-dalek/src/constants.rs b/curve25519-dalek/src/constants.rs new file mode 100644 index 000000000..a22ac65c4 --- /dev/null +++ b/curve25519-dalek/src/constants.rs @@ -0,0 +1,180 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence +//! Various constants, such as the Ristretto and Ed25519 basepoints. + +#![allow(non_snake_case)] + +use cfg_if::cfg_if; + +use crate::edwards::CompressedEdwardsY; +use crate::montgomery::MontgomeryPoint; +use crate::ristretto::{CompressedRistretto, RistrettoPoint}; +use crate::scalar::Scalar; + +#[cfg(feature = "precomputed-tables")] +use crate::edwards::EdwardsBasepointTable; + +cfg_if! { + if #[cfg(curve25519_dalek_backend = "u32e_backend")]{ + pub use crate::backend::serial::u32e::constants::*; + } else if #[cfg(curve25519_dalek_backend = "fiat")] { + #[cfg(curve25519_dalek_bits = "32")] + pub use crate::backend::serial::fiat_u32::constants::*; + #[cfg(curve25519_dalek_bits = "64")] + pub use crate::backend::serial::fiat_u64::constants::*; + } else { + #[cfg(curve25519_dalek_bits = "32")] + pub use crate::backend::serial::u32::constants::*; + #[cfg(curve25519_dalek_bits = "64")] + pub use crate::backend::serial::u64::constants::*; + } +} + +/// The Ed25519 basepoint, in `CompressedEdwardsY` format. +/// +/// This is the little-endian byte encoding of \\( 4/5 \pmod p \\), +/// which is the \\(y\\)-coordinate of the Ed25519 basepoint. +/// +/// The sign bit is 0 since the basepoint has \\(x\\) chosen to be positive. +pub const ED25519_BASEPOINT_COMPRESSED: CompressedEdwardsY = CompressedEdwardsY([ + 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, + 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, +]); + +/// The X25519 basepoint, in `MontgomeryPoint` format. +pub const X25519_BASEPOINT: MontgomeryPoint = MontgomeryPoint([ + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +]); + +/// The Ristretto basepoint, in `CompressedRistretto` format. +pub const RISTRETTO_BASEPOINT_COMPRESSED: CompressedRistretto = CompressedRistretto([ + 0xe2, 0xf2, 0xae, 0x0a, 0x6a, 0xbc, 0x4e, 0x71, 0xa8, 0x84, 0xa9, 0x61, 0xc5, 0x00, 0x51, 0x5f, + 0x58, 0xe3, 0x0b, 0x6a, 0xa5, 0x82, 0xdd, 0x8d, 0xb6, 0xa6, 0x59, 0x45, 0xe0, 0x8d, 0x2d, 0x76, +]); + +/// The Ristretto basepoint, as a `RistrettoPoint`. +/// +/// This is called `_POINT` to distinguish it from `_TABLE`, which +/// provides fast scalar multiplication. +pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BASEPOINT_POINT); + +/// `BASEPOINT_ORDER` is the order of the Ristretto group and of the Ed25519 basepoint, i.e., +/// $$ +/// \ell = 2^\{252\} + 27742317777372353535851937790883648493. +/// $$ +#[deprecated(since = "4.1.1", note = "Should not have been in public API")] +pub const BASEPOINT_ORDER: Scalar = BASEPOINT_ORDER_PRIVATE; + +pub(crate) const BASEPOINT_ORDER_PRIVATE: Scalar = Scalar { + bytes: [ + 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x10, + ], +}; + +#[cfg(feature = "precomputed-tables")] +use crate::ristretto::RistrettoBasepointTable; + +/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. +#[cfg(feature = "precomputed-tables")] +pub static RISTRETTO_BASEPOINT_TABLE: &RistrettoBasepointTable = unsafe { + // SAFETY: `RistrettoBasepointTable` is a `#[repr(transparent)]` newtype of + // `EdwardsBasepointTable` + &*(ED25519_BASEPOINT_TABLE as *const EdwardsBasepointTable as *const RistrettoBasepointTable) +}; + +#[cfg(test)] +mod test { + use crate::constants; + use crate::field::FieldElement; + use crate::traits::{IsIdentity, ValidityCheck}; + + #[test] + fn test_eight_torsion() { + for i in 0..8 { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(3); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + #[test] + fn test_four_torsion() { + for i in (0..8).filter(|i| i % 2 == 0) { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(2); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + #[test] + fn test_two_torsion() { + for i in (0..8).filter(|i| i % 4 == 0) { + let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(1); + assert!(Q.is_valid()); + assert!(Q.is_identity()); + } + } + + /// Test that SQRT_M1 is the positive square root of -1 + #[test] + fn test_sqrt_minus_one() { + let minus_one = FieldElement::MINUS_ONE; + let sqrt_m1_sq = &constants::SQRT_M1 * &constants::SQRT_M1; + assert_eq!(minus_one, sqrt_m1_sq); + assert!(bool::from(!constants::SQRT_M1.is_negative())); + } + + #[test] + fn test_sqrt_constants_sign() { + let minus_one = FieldElement::MINUS_ONE; + let (was_nonzero_square, invsqrt_m1) = minus_one.invsqrt(); + assert!(bool::from(was_nonzero_square)); + let sign_test_sqrt = &invsqrt_m1 * &constants::SQRT_M1; + assert_eq!(sign_test_sqrt, minus_one); + } + + /// Test that d = -121665/121666 + #[test] + #[cfg(all(curve25519_dalek_bits = "32", not(curve25519_dalek_backend = "fiat"), not(curve25519_dalek_backend = "u32e_backend")))] + fn test_d_vs_ratio() { + use crate::backend::serial::u32::field::FieldElement2625; + let a = -&FieldElement2625([121665, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + let b = FieldElement2625([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); + let d = &a * &b.invert(); + let d2 = &d + &d; + assert_eq!(d, constants::EDWARDS_D); + assert_eq!(d2, constants::EDWARDS_D2); + } + + /// Test that d = -121665/121666 + #[test] + #[cfg(all(curve25519_dalek_bits = "64", not(curve25519_dalek_backend = "fiat")))] + fn test_d_vs_ratio() { + use crate::backend::serial::u64::field::FieldElement51; + let a = -&FieldElement51([121665, 0, 0, 0, 0]); + let b = FieldElement51([121666, 0, 0, 0, 0]); + let d = &a * &b.invert(); + let d2 = &d + &d; + assert_eq!(d, constants::EDWARDS_D); + assert_eq!(d2, constants::EDWARDS_D2); + } + + #[test] + fn test_sqrt_ad_minus_one() { + let a = FieldElement::MINUS_ONE; + let ad_minus_one = &(&a * &constants::EDWARDS_D) + &a; + let should_be_ad_minus_one = constants::SQRT_AD_MINUS_ONE.square(); + assert_eq!(should_be_ad_minus_one, ad_minus_one); + } +} diff --git a/curve25519-dalek/src/diagnostics.rs b/curve25519-dalek/src/diagnostics.rs new file mode 100644 index 000000000..d5becef67 --- /dev/null +++ b/curve25519-dalek/src/diagnostics.rs @@ -0,0 +1,25 @@ +//! Build time diagnostics + +// auto is assumed or selected +#[cfg(curve25519_dalek_backend = "auto")] +compile_error!("curve25519_dalek_backend is 'auto'"); + +// fiat was overriden +#[cfg(curve25519_dalek_backend = "fiat")] +compile_error!("curve25519_dalek_backend is 'fiat'"); + +// serial was assumed or overriden +#[cfg(curve25519_dalek_backend = "serial")] +compile_error!("curve25519_dalek_backend is 'serial'"); + +// simd was assumed over overriden +#[cfg(curve25519_dalek_backend = "simd")] +compile_error!("curve25519_dalek_backend is 'simd'"); + +// 32 bits target_pointer_width was assumed or overriden +#[cfg(curve25519_dalek_bits = "32")] +compile_error!("curve25519_dalek_bits is '32'"); + +// 64 bits target_pointer_width was assumed or overriden +#[cfg(curve25519_dalek_bits = "64")] +compile_error!("curve25519_dalek_bits is '64'"); diff --git a/src/edwards.rs b/curve25519-dalek/src/edwards.rs similarity index 53% rename from src/edwards.rs rename to curve25519-dalek/src/edwards.rs index f33df9532..856fac12f 100644 --- a/src/edwards.rs +++ b/curve25519-dalek/src/edwards.rs @@ -18,7 +18,7 @@ //! //! ## Equality Testing //! -//! The `EdwardsPoint` struct implements the `subtle::ConstantTimeEq` +//! The `EdwardsPoint` struct implements the [`subtle::ConstantTimeEq`] //! trait for constant-time equality checking, and the Rust `Eq` trait //! for variable-time equality checking. //! @@ -26,26 +26,26 @@ //! //! The order of the group of points on the curve \\(\mathcal E\\) //! is \\(|\mathcal E| = 8\ell \\), so its structure is \\( \mathcal -//! E = \mathcal E[8] \times \mathcal E[\ell]\\). The torsion -//! subgroup \\( \mathcal E[8] \\) consists of eight points of small +//! E = \mathcal E\[8\] \times \mathcal E[\ell]\\). The torsion +//! subgroup \\( \mathcal E\[8\] \\) consists of eight points of small //! order. Technically, all of \\(\mathcal E\\) is torsion, but we -//! use the word only to refer to the small \\(\mathcal E[8]\\) part, not +//! use the word only to refer to the small \\(\mathcal E\[8\]\\) part, not //! the large prime-order \\(\mathcal E[\ell]\\) part. //! -//! To test if a point is in \\( \mathcal E[8] \\), use -//! `EdwardsPoint::is_small_order()`. +//! To test if a point is in \\( \mathcal E\[8\] \\), use +//! [`EdwardsPoint::is_small_order`]. //! //! To test if a point is in \\( \mathcal E[\ell] \\), use -//! `EdwardsPoint::is_torsion_free()`. +//! [`EdwardsPoint::is_torsion_free`]. //! -//! To multiply by the cofactor, use `EdwardsPoint::mul_by_cofactor()`. +//! To multiply by the cofactor, use [`EdwardsPoint::mul_by_cofactor`]. //! //! To avoid dealing with cofactors entirely, consider using Ristretto. //! //! ## Scalars //! -//! Scalars are represented by the `Scalar` struct. To construct a scalar with a specific bit -//! pattern, see `Scalar::from_bits()`. +//! Scalars are represented by the [`Scalar`] struct. To construct a scalar, see +//! [`Scalar::from_canonical_bytes`] or [`Scalar::from_bytes_mod_order_wide`]. //! //! ## Scalar Multiplication //! @@ -85,7 +85,7 @@ //! successful decompression of a compressed point, or else by //! operations on other (valid) `EdwardsPoint`s. //! -//! [curve_models]: https://doc-internal.dalek.rs/curve25519_dalek/backend/serial/curve_models/index.html +//! [curve_models]: https://docs.rs/curve25519-dalek/latest/curve25519-dalek/backend/serial/curve_models/index.html // We allow non snake_case names because coordinates in projective space are // traditionally denoted by the capitalisation of their respective @@ -93,63 +93,64 @@ // affine and projective cakes and eat both of them too. #![allow(non_snake_case)] +use core::array::TryFromSliceError; use core::borrow::Borrow; use core::fmt::Debug; -use core::iter::Iterator; use core::iter::Sum; use core::ops::{Add, Neg, Sub}; use core::ops::{AddAssign, SubAssign}; use core::ops::{Mul, MulAssign}; +use cfg_if::cfg_if; + +#[cfg(feature = "digest")] use digest::{generic_array::typenum::U64, Digest}; + +#[cfg(feature = "group")] +use { + group::{cofactor::CofactorGroup, prime::PrimeGroup, GroupEncoding}, + subtle::CtOption, +}; + +#[cfg(feature = "group")] +use rand_core::RngCore; + use subtle::Choice; use subtle::ConditionallyNegatable; use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; -use constants; - -use field::FieldElement; -use scalar::Scalar; +use crate::constants; -use montgomery::MontgomeryPoint; +use crate::field::FieldElement; +use crate::scalar::{clamp_integer, Scalar}; -use backend::serial::curve_models::AffineNielsPoint; -use backend::serial::curve_models::CompletedPoint; -use backend::serial::curve_models::ProjectiveNielsPoint; -use backend::serial::curve_models::ProjectivePoint; +use crate::montgomery::MontgomeryPoint; -use window::LookupTable; -use window::LookupTableRadix16; -use window::LookupTableRadix32; -use window::LookupTableRadix64; -use window::LookupTableRadix128; -use window::LookupTableRadix256; +use crate::backend::serial::curve_models::AffineNielsPoint; +use crate::backend::serial::curve_models::CompletedPoint; +use crate::backend::serial::curve_models::ProjectiveNielsPoint; +use crate::backend::serial::curve_models::ProjectivePoint; -#[allow(unused_imports)] -use prelude::*; +#[cfg(feature = "precomputed-tables")] +use crate::window::{ + LookupTableRadix128, LookupTableRadix16, LookupTableRadix256, LookupTableRadix32, + LookupTableRadix64, +}; -use traits::BasepointTable; -use traits::ValidityCheck; -use traits::{Identity, IsIdentity}; +#[cfg(feature = "precomputed-tables")] +use crate::traits::BasepointTable; -#[cfg(any(feature = "alloc", feature = "std"))] -use traits::MultiscalarMul; -#[cfg(any(feature = "alloc", feature = "std"))] -use traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; +use crate::traits::ValidityCheck; +use crate::traits::{Identity, IsIdentity}; -#[cfg(not(all( - feature = "simd_backend", - any(target_feature = "avx2", target_feature = "avx512ifma") -)))] -use backend::serial::scalar_mul; -#[cfg(all( - feature = "simd_backend", - any(target_feature = "avx2", target_feature = "avx512ifma") -))] -use backend::vector::scalar_mul; +#[cfg(feature = "alloc")] +use crate::traits::MultiscalarMul; +#[cfg(feature = "alloc")] +use crate::traits::{VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; // ------------------------------------------------------------------------ // Compressed points @@ -170,19 +171,19 @@ impl ConstantTimeEq for CompressedEdwardsY { } impl Debug for CompressedEdwardsY { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "CompressedEdwardsY: {:?}", self.as_bytes()) } } impl CompressedEdwardsY { /// View this `CompressedEdwardsY` as an array of bytes. - pub fn as_bytes(&self) -> &[u8; 32] { + pub const fn as_bytes(&self) -> &[u8; 32] { &self.0 } /// Copy this `CompressedEdwardsY` to an array of bytes. - pub fn to_bytes(&self) -> [u8; 32] { + pub const fn to_bytes(&self) -> [u8; 32] { self.0 } @@ -191,21 +192,59 @@ impl CompressedEdwardsY { /// Returns `None` if the input is not the \\(y\\)-coordinate of a /// curve point. pub fn decompress(&self) -> Option { - let Y = FieldElement::from_bytes(self.as_bytes()); - let Z = FieldElement::one(); + let (is_valid_y_coord, X, Y, Z) = decompress::step_1(self); + + if is_valid_y_coord.into() { + Some(decompress::step_2(self, X, Y, Z)) + } else { + None + } + } +} + +mod decompress { + use super::*; + + #[rustfmt::skip] // keep alignment of explanatory comments + pub(super) fn step_1( + repr: &CompressedEdwardsY, + ) -> (Choice, FieldElement, FieldElement, FieldElement) { + let Y = FieldElement::from_bytes(repr.as_bytes()); + let Z = FieldElement::ONE; let YY = Y.square(); let u = &YY - &Z; // u = y²-1 let v = &(&YY * &constants::EDWARDS_D) + &Z; // v = dy²+1 - let (is_valid_y_coord, mut X) = FieldElement::sqrt_ratio_i(&u, &v); + let (is_valid_y_coord, X) = FieldElement::sqrt_ratio_i(&u, &v); - if is_valid_y_coord.unwrap_u8() != 1u8 { return None; } + (is_valid_y_coord, X, Y, Z) + } + #[rustfmt::skip] + pub(super) fn step_2( + repr: &CompressedEdwardsY, + mut X: FieldElement, + Y: FieldElement, + Z: FieldElement, + ) -> EdwardsPoint { // FieldElement::sqrt_ratio_i always returns the nonnegative square root, // so we negate according to the supplied sign bit. - let compressed_sign_bit = Choice::from(self.as_bytes()[31] >> 7); + let compressed_sign_bit = Choice::from(repr.as_bytes()[31] >> 7); X.conditional_negate(compressed_sign_bit); - Some(EdwardsPoint{ X, Y, Z, T: &X * &Y }) + EdwardsPoint { + X, + Y, + Z, + T: &X * &Y, + } + } +} + +impl TryFrom<&[u8]> for CompressedEdwardsY { + type Error = TryFromSliceError; + + fn try_from(slice: &[u8]) -> Result { + Self::from_slice(slice) } } @@ -217,15 +256,16 @@ impl CompressedEdwardsY { // structs containing `EdwardsPoint`s and use Serde's derived // serializers to serialize those structures. -#[cfg(feature = "serde")] -use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for EdwardsPoint { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -239,7 +279,8 @@ impl Serialize for EdwardsPoint { #[cfg(feature = "serde")] impl Serialize for CompressedEdwardsY { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -253,28 +294,32 @@ impl Serialize for CompressedEdwardsY { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for EdwardsPoint { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct EdwardsPointVisitor; impl<'de> Visitor<'de> for EdwardsPointVisitor { type Value = EdwardsPoint; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a valid point in Edwards y + sign format") } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { - bytes[i] = seq.next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + bytes[i] = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } CompressedEdwardsY(bytes) .decompress() - .ok_or(serde::de::Error::custom("decompression failed")) + .ok_or_else(|| serde::de::Error::custom("decompression failed")) } } @@ -285,24 +330,28 @@ impl<'de> Deserialize<'de> for EdwardsPoint { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for CompressedEdwardsY { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct CompressedEdwardsYVisitor; impl<'de> Visitor<'de> for CompressedEdwardsYVisitor { type Value = CompressedEdwardsY; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("32 bytes of data") } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { - bytes[i] = seq.next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + bytes[i] = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } Ok(CompressedEdwardsY(bytes)) } @@ -332,10 +381,10 @@ pub struct EdwardsPoint { impl Identity for CompressedEdwardsY { fn identity() -> CompressedEdwardsY { - CompressedEdwardsY([1, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0]) + CompressedEdwardsY([ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ]) } } @@ -348,25 +397,22 @@ impl Default for CompressedEdwardsY { impl CompressedEdwardsY { /// Construct a `CompressedEdwardsY` from a slice of bytes. /// - /// # Panics + /// # Errors /// - /// If the input `bytes` slice does not have a length of 32. - pub fn from_slice(bytes: &[u8]) -> CompressedEdwardsY { - let mut tmp = [0u8; 32]; - - tmp.copy_from_slice(bytes); - - CompressedEdwardsY(tmp) + /// Returns [`TryFromSliceError`] if the input `bytes` slice does not have + /// a length of 32. + pub fn from_slice(bytes: &[u8]) -> Result { + bytes.try_into().map(CompressedEdwardsY) } } impl Identity for EdwardsPoint { fn identity() -> EdwardsPoint { EdwardsPoint { - X: FieldElement::zero(), - Y: FieldElement::one(), - Z: FieldElement::one(), - T: FieldElement::zero(), + X: FieldElement::ZERO, + Y: FieldElement::ONE, + Z: FieldElement::ONE, + T: FieldElement::ZERO, } } } @@ -381,6 +427,7 @@ impl Default for EdwardsPoint { // Zeroize implementations for wiping points from memory // ------------------------------------------------------------------------ +#[cfg(feature = "zeroize")] impl Zeroize for CompressedEdwardsY { /// Reset this `CompressedEdwardsY` to the compressed form of the identity element. fn zeroize(&mut self) { @@ -389,12 +436,13 @@ impl Zeroize for CompressedEdwardsY { } } +#[cfg(feature = "zeroize")] impl Zeroize for EdwardsPoint { /// Reset this `CompressedEdwardsPoint` to the identity element. fn zeroize(&mut self) { self.X.zeroize(); - self.Y = FieldElement::one(); - self.Z = FieldElement::one(); + self.Y = FieldElement::ONE; + self.Z = FieldElement::ONE; self.T.zeroize(); } } @@ -405,7 +453,7 @@ impl Zeroize for EdwardsPoint { impl ValidityCheck for EdwardsPoint { fn is_valid(&self) -> bool { - let point_on_curve = self.to_projective().is_valid(); + let point_on_curve = self.as_projective().is_valid(); let on_segre_image = (&self.X * &self.Y) == (&self.Z * &self.T); point_on_curve && on_segre_image @@ -446,7 +494,7 @@ impl ConstantTimeEq for EdwardsPoint { impl PartialEq for EdwardsPoint { fn eq(&self, other: &EdwardsPoint) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } @@ -458,12 +506,12 @@ impl Eq for EdwardsPoint {} impl EdwardsPoint { /// Convert to a ProjectiveNielsPoint - pub(crate) fn to_projective_niels(&self) -> ProjectiveNielsPoint { - ProjectiveNielsPoint{ - Y_plus_X: &self.Y + &self.X, + pub(crate) fn as_projective_niels(&self) -> ProjectiveNielsPoint { + ProjectiveNielsPoint { + Y_plus_X: &self.Y + &self.X, Y_minus_X: &self.Y - &self.X, - Z: self.Z, - T2d: &self.T * &constants::EDWARDS_D2, + Z: self.Z, + T2d: &self.T * &constants::EDWARDS_D2, } } @@ -471,8 +519,8 @@ impl EdwardsPoint { /// coordinates to projective coordinates. /// /// Free. - pub(crate) fn to_projective(&self) -> ProjectivePoint { - ProjectivePoint{ + pub(crate) const fn as_projective(&self) -> ProjectivePoint { + ProjectivePoint { X: self.X, Y: self.Y, Z: self.Z, @@ -481,15 +529,15 @@ impl EdwardsPoint { /// Dehomogenize to a AffineNielsPoint. /// Mainly for testing. - pub(crate) fn to_affine_niels(&self) -> AffineNielsPoint { + pub(crate) fn as_affine_niels(&self) -> AffineNielsPoint { let recip = self.Z.invert(); let x = &self.X * &recip; let y = &self.Y * &recip; let xy2d = &(&x * &y) * &constants::EDWARDS_D2; - AffineNielsPoint{ - y_plus_x: &y + &x, + AffineNielsPoint { + y_plus_x: &y + &x, y_minus_x: &y - &x, - xy2d + xy2d, } } @@ -511,7 +559,7 @@ impl EdwardsPoint { let U = &self.Z + &self.Y; let W = &self.Z - &self.Y; let u = &U * &W.invert(); - MontgomeryPoint(u.to_bytes()) + MontgomeryPoint(u.as_bytes()) } /// Compress this point to `CompressedEdwardsY` format. @@ -521,15 +569,22 @@ impl EdwardsPoint { let y = &self.Y * &recip; let mut s: [u8; 32]; - s = y.to_bytes(); + s = y.as_bytes(); s[31] ^= x.is_negative().unwrap_u8() << 7; CompressedEdwardsY(s) } - /// Perform hashing to the group using the Elligator2 map - /// - /// See https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-10#section-6.7.1 - pub fn hash_from_bytes(bytes: &[u8]) -> EdwardsPoint + #[cfg(feature = "digest")] + /// Maps the digest of the input bytes to the curve. This is NOT a hash-to-curve function, as + /// it produces points with a non-uniform distribution. Rather, it performs something that + /// resembles (but is not) half of the + /// [`hash_to_curve`](https://www.ietf.org/archive/id/draft-irtf-cfrg-hash-to-curve-16.html#section-3-4.2.1) + /// function from the Elligator2 spec. + #[deprecated( + since = "4.0.0", + note = "previously named `hash_from_bytes`, this is not a secure hash function" + )] + pub fn nonspec_map_to_curve(bytes: &[u8]) -> EdwardsPoint where D: Digest + Default, { @@ -559,7 +614,7 @@ impl EdwardsPoint { impl EdwardsPoint { /// Add this point to itself. pub(crate) fn double(&self) -> EdwardsPoint { - self.to_projective().double().to_extended() + self.as_projective().double().as_extended() } } @@ -570,11 +625,15 @@ impl EdwardsPoint { impl<'a, 'b> Add<&'b EdwardsPoint> for &'a EdwardsPoint { type Output = EdwardsPoint; fn add(self, other: &'b EdwardsPoint) -> EdwardsPoint { - (self + &other.to_projective_niels()).to_extended() + (self + &other.as_projective_niels()).as_extended() } } -define_add_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint, Output = EdwardsPoint); +define_add_variants!( + LHS = EdwardsPoint, + RHS = EdwardsPoint, + Output = EdwardsPoint +); impl<'b> AddAssign<&'b EdwardsPoint> for EdwardsPoint { fn add_assign(&mut self, _rhs: &'b EdwardsPoint) { @@ -587,11 +646,15 @@ define_add_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint); impl<'a, 'b> Sub<&'b EdwardsPoint> for &'a EdwardsPoint { type Output = EdwardsPoint; fn sub(self, other: &'b EdwardsPoint) -> EdwardsPoint { - (self - &other.to_projective_niels()).to_extended() + (self - &other.as_projective_niels()).as_extended() } } -define_sub_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint, Output = EdwardsPoint); +define_sub_variants!( + LHS = EdwardsPoint, + RHS = EdwardsPoint, + Output = EdwardsPoint +); impl<'b> SubAssign<&'b EdwardsPoint> for EdwardsPoint { fn sub_assign(&mut self, _rhs: &'b EdwardsPoint) { @@ -603,17 +666,16 @@ define_sub_assign_variants!(LHS = EdwardsPoint, RHS = EdwardsPoint); impl Sum for EdwardsPoint where - T: Borrow + T: Borrow, { fn sum(iter: I) -> Self where - I: Iterator + I: Iterator, { iter.fold(EdwardsPoint::identity(), |acc, item| acc + item.borrow()) } } - // ------------------------------------------------------------------------ // Negation // ------------------------------------------------------------------------ @@ -622,10 +684,10 @@ impl<'a> Neg for &'a EdwardsPoint { type Output = EdwardsPoint; fn neg(self) -> EdwardsPoint { - EdwardsPoint{ + EdwardsPoint { X: -(&self.X), - Y: self.Y, - Z: self.Z, + Y: self.Y, + Z: self.Z, T: -(&self.T), } } @@ -662,7 +724,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsPoint { /// For scalar multiplication of a basepoint, /// `EdwardsBasepointTable` is approximately 4x faster. fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { - scalar_mul::variable_base::mul(self, scalar) + crate::backend::variable_base_mul(self, scalar) } } @@ -678,6 +740,52 @@ impl<'a, 'b> Mul<&'b EdwardsPoint> for &'a Scalar { } } +impl EdwardsPoint { + /// Fixed-base scalar multiplication by the Ed25519 base point. + /// + /// Uses precomputed basepoint tables when the `precomputed-tables` feature + /// is enabled, trading off increased code size for ~4x better performance. + pub fn mul_base(scalar: &Scalar) -> Self { + #[cfg(not(feature = "precomputed-tables"))] + { + scalar * constants::ED25519_BASEPOINT_POINT + } + + #[cfg(feature = "precomputed-tables")] + { + scalar * constants::ED25519_BASEPOINT_TABLE + } + } + + /// Multiply this point by `clamp_integer(bytes)`. For a description of clamping, see + /// [`clamp_integer`]. + pub fn mul_clamped(self, bytes: [u8; 32]) -> Self { + // We have to construct a Scalar that is not reduced mod l, which breaks scalar invariant + // #2. But #2 is not necessary for correctness of variable-base multiplication. All that + // needs to hold is invariant #1, i.e., the scalar is less than 2^255. This is guaranteed + // by clamping. + // Further, we don't do any reduction or arithmetic with this clamped value, so there's no + // issues arising from the fact that the curve point is not necessarily in the prime-order + // subgroup. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + s * self + } + + /// Multiply the basepoint by `clamp_integer(bytes)`. For a description of clamping, see + /// [`clamp_integer`]. + pub fn mul_base_clamped(bytes: [u8; 32]) -> Self { + // See reasoning in Self::mul_clamped why it is OK to make an unreduced Scalar here. We + // note that fixed-base multiplication is also defined for all values of `bytes` less than + // 2^255. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + Self::mul_base(&s) + } +} + // ------------------------------------------------------------------------ // Multiscalar Multiplication impls // ------------------------------------------------------------------------ @@ -713,7 +821,7 @@ impl MultiscalarMul for EdwardsPoint { // size-dependent algorithm dispatch, use this as the hint. let _size = s_lo; - scalar_mul::straus::Straus::multiscalar_mul(scalars, points) + crate::backend::straus_multiscalar_mul(scalars, points) } } @@ -745,9 +853,9 @@ impl VartimeMultiscalarMul for EdwardsPoint { let size = s_lo; if size < 190 { - scalar_mul::straus::Straus::optional_multiscalar_mul(scalars, points) + crate::backend::straus_optional_multiscalar_mul(scalars, points) } else { - scalar_mul::pippenger::Pippenger::optional_multiscalar_mul(scalars, points) + crate::backend::pippenger_optional_multiscalar_mul(scalars, points) } } } @@ -757,7 +865,7 @@ impl VartimeMultiscalarMul for EdwardsPoint { // decouple stability of the inner type from the stability of the // outer type. #[cfg(feature = "alloc")] -pub struct VartimeEdwardsPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); +pub struct VartimeEdwardsPrecomputation(crate::backend::VartimePrecomputedStraus); #[cfg(feature = "alloc")] impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { @@ -768,7 +876,7 @@ impl VartimePrecomputedMultiscalarMul for VartimeEdwardsPrecomputation { I: IntoIterator, I::Item: Borrow, { - Self(scalar_mul::precomputed_straus::VartimePrecomputedStraus::new(static_points)) + Self(crate::backend::VartimePrecomputedStraus::new(static_points)) } fn optional_mixed_multiscalar_mul( @@ -796,290 +904,216 @@ impl EdwardsPoint { A: &EdwardsPoint, b: &Scalar, ) -> EdwardsPoint { - scalar_mul::vartime_double_base::mul(a, A, b) + crate::backend::vartime_double_base_mul(a, A, b) } } +#[cfg(feature = "precomputed-tables")] macro_rules! impl_basepoint_table { (Name = $name:ident, LookupTable = $table:ident, Point = $point:ty, Radix = $radix:expr, Additions = $adds:expr) => { + /// A precomputed table of multiples of a basepoint, for accelerating + /// fixed-base scalar multiplication. One table, for the Ed25519 + /// basepoint, is provided in the [`constants`] module. + /// + /// The basepoint tables are reasonably large, so they should probably be boxed. + /// + /// The sizes for the tables and the number of additions required for one scalar + /// multiplication are as follows: + /// + /// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A + /// (this is the default size, and is used for + /// [`constants::ED25519_BASEPOINT_TABLE`]) + /// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A + /// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A + /// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A + /// + /// # Why 33 additions for radix-256? + /// + /// Normally, the radix-256 tables would allow for only 32 additions per scalar + /// multiplication. However, due to the fact that standardised definitions of + /// legacy protocols—such as x25519—require allowing unreduced 255-bit scalars + /// invariants, when converting such an unreduced scalar's representation to + /// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last + /// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of + /// the radix, is \\(w < 8\\), we can fold the final carry onto the last + /// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so + /// $$ + /// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8} + /// $$ + /// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we + /// add the carry bit onto an additional coefficient. + #[derive(Clone)] + #[repr(transparent)] + pub struct $name(pub(crate) [$table; 32]); + + impl BasepointTable for $name { + type Point = $point; + + /// Create a table of precomputed multiples of `basepoint`. + fn create(basepoint: &$point) -> $name { + // XXX use init_with + let mut table = $name([$table::default(); 32]); + let mut P = *basepoint; + for i in 0..32 { + // P = (2w)^i * B + table.0[i] = $table::from(&P); + P = P.mul_by_pow_2($radix + $radix); + } + table + } -/// A precomputed table of multiples of a basepoint, for accelerating -/// fixed-base scalar multiplication. One table, for the Ed25519 -/// basepoint, is provided in the `constants` module. -/// -/// The basepoint tables are reasonably large, so they should probably be boxed. -/// -/// The sizes for the tables and the number of additions required for one scalar -/// multiplication are as follows: -/// -/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A -/// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`]) -/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A -/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A -/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A -/// -/// # Why 33 additions for radix-256? -/// -/// Normally, the radix-256 tables would allow for only 32 additions per scalar -/// multiplication. However, due to the fact that standardised definitions of -/// legacy protocols—such as x25519—require allowing unreduced 255-bit scalar -/// invariants, when converting such an unreduced scalar's representation to -/// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last -/// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of -/// the radix, is \\(w < 8\\), we can fold the final carry onto the last -/// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so -/// $$ -/// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8} -/// $$ -/// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we -/// add the carry bit onto an additional coefficient. -#[derive(Clone)] -pub struct $name(pub(crate) [$table; 32]); - -impl BasepointTable for $name { - type Point = $point; - - /// Create a table of precomputed multiples of `basepoint`. - fn create(basepoint: &$point) -> $name { - // XXX use init_with - let mut table = $name([$table::default(); 32]); - let mut P = *basepoint; - for i in 0..32 { - // P = (2w)^i * B - table.0[i] = $table::from(&P); - P = P.mul_by_pow_2($radix + $radix); - } - table - } + /// Get the basepoint for this table as an `EdwardsPoint`. + fn basepoint(&self) -> $point { + // self.0[0].select(1) = 1*(16^2)^0*B + // but as an `AffineNielsPoint`, so add identity to convert to extended. + (&<$point>::identity() + &self.0[0].select(1)).as_extended() + } - /// Get the basepoint for this table as an `EdwardsPoint`. - fn basepoint(&self) -> $point { - // self.0[0].select(1) = 1*(16^2)^0*B - // but as an `AffineNielsPoint`, so add identity to convert to extended. - (&<$point>::identity() + &self.0[0].select(1)).to_extended() - } + /// The computation uses Pippeneger's algorithm, as described for the + /// specific case of radix-16 on page 13 of the Ed25519 paper. + /// + /// # Piggenger's Algorithm Generalised + /// + /// Write the scalar \\(a\\) in radix-\\(w\\), where \\(w\\) is a power of + /// 2, with coefficients in \\([\frac{-w}{2},\frac{w}{2})\\), i.e., + /// $$ + /// a = a\_0 + a\_1 w\^1 + \cdots + a\_{x} w\^{x}, + /// $$ + /// with + /// $$ + /// \begin{aligned} + /// \frac{-w}{2} \leq a_i < \frac{w}{2} + /// &&\cdots&& + /// \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2} + /// \end{aligned} + /// $$ + /// and the number of additions, \\(x\\), is given by + /// \\(x = \lceil \frac{256}{w} \rceil\\). Then + /// $$ + /// a B = a\_0 B + a\_1 w\^1 B + \cdots + a\_{x-1} w\^{x-1} B. + /// $$ + /// Grouping even and odd coefficients gives + /// $$ + /// \begin{aligned} + /// a B = \quad a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B \\\\ + /// + a\_1 w\^1 B +& a\_3 w\^3 B + \cdots + a\_{x-1} w\^{x-1} B \\\\ + /// = \quad(a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B) \\\\ + /// + w(a\_1 w\^0 B +& a\_3 w\^2 B + \cdots + a\_{x-1} w\^{x-2} B). \\\\ + /// \end{aligned} + /// $$ + /// For each \\(i = 0 \ldots 31\\), we create a lookup table of + /// $$ + /// [w\^{2i} B, \ldots, \frac{w}{2}\cdot w\^{2i} B], + /// $$ + /// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time. + /// + /// The radix-\\(w\\) representation requires that the scalar is bounded + /// by \\(2\^{255}\\), which is always the case. + /// + /// The above algorithm is trivially generalised to other powers-of-2 radices. + fn mul_base(&self, scalar: &Scalar) -> $point { + let a = scalar.as_radix_2w($radix); + + let tables = &self.0; + let mut P = <$point>::identity(); + + for i in (0..$adds).filter(|x| x % 2 == 1) { + P = (&P + &tables[i / 2].select(a[i])).as_extended(); + } - /// The computation uses Pippeneger's algorithm, as described for the - /// specific case of radix-16 on page 13 of the Ed25519 paper. - /// - /// # Piggenger's Algorithm Generalised - /// - /// Write the scalar \\(a\\) in radix-\\(w\\), where \\(w\\) is a power of - /// 2, with coefficients in \\([\frac{-w}{2},\frac{w}{2})\\), i.e., - /// $$ - /// a = a\_0 + a\_1 w\^1 + \cdots + a\_{x} w\^{x}, - /// $$ - /// with - /// $$ - /// \frac{-w}{2} \leq a_i < \frac{w}{2}, \cdots, \frac{-w}{2} \leq a\_{x} \leq \frac{w}{2} - /// $$ - /// and the number of additions, \\(x\\), is given by \\(x = \lceil \frac{256}{w} \rceil\\). - /// Then - /// $$ - /// a B = a\_0 B + a\_1 w\^1 B + \cdots + a\_{x-1} w\^{x-1} B. - /// $$ - /// Grouping even and odd coefficients gives - /// $$ - /// \begin{aligned} - /// a B = \quad a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B \\\\ - /// + a\_1 w\^1 B +& a\_3 w\^3 B + \cdots + a\_{x-1} w\^{x-1} B \\\\ - /// = \quad(a\_0 w\^0 B +& a\_2 w\^2 B + \cdots + a\_{x-2} w\^{x-2} B) \\\\ - /// + w(a\_1 w\^0 B +& a\_3 w\^2 B + \cdots + a\_{x-1} w\^{x-2} B). \\\\ - /// \end{aligned} - /// $$ - /// For each \\(i = 0 \ldots 31\\), we create a lookup table of - /// $$ - /// [w\^{2i} B, \ldots, \frac{w}{2}\cdotw\^{2i} B], - /// $$ - /// and use it to select \\( y \cdot w\^{2i} \cdot B \\) in constant time. - /// - /// The radix-\\(w\\) representation requires that the scalar is bounded - /// by \\(2\^{255}\\), which is always the case. - /// - /// The above algorithm is trivially generalised to other powers-of-2 radices. - fn basepoint_mul(&self, scalar: &Scalar) -> $point { - let a = scalar.to_radix_2w($radix); + P = P.mul_by_pow_2($radix); - let tables = &self.0; - let mut P = <$point>::identity(); + for i in (0..$adds).filter(|x| x % 2 == 0) { + P = (&P + &tables[i / 2].select(a[i])).as_extended(); + } - for i in (0..$adds).filter(|x| x % 2 == 1) { - P = (&P + &tables[i/2].select(a[i])).to_extended(); + P + } } - P = P.mul_by_pow_2($radix); + impl<'a, 'b> Mul<&'b Scalar> for &'a $name { + type Output = $point; - for i in (0..$adds).filter(|x| x % 2 == 0) { - P = (&P + &tables[i/2].select(a[i])).to_extended(); + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, scalar: &'b Scalar) -> $point { + // delegate to a private function so that its documentation appears in internal docs + self.mul_base(scalar) + } } - P - } -} - -impl<'a, 'b> Mul<&'b Scalar> for &'a $name { - type Output = $point; - - /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by - /// computing the multiple \\(aB\\) of this basepoint \\(B\\). - fn mul(self, scalar: &'b Scalar) -> $point { - // delegate to a private function so that its documentation appears in internal docs - self.basepoint_mul(scalar) - } -} - -impl<'a, 'b> Mul<&'a $name> for &'b Scalar { - type Output = $point; + impl<'a, 'b> Mul<&'a $name> for &'b Scalar { + type Output = $point; - /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by - /// computing the multiple \\(aB\\) of this basepoint \\(B\\). - fn mul(self, basepoint_table: &'a $name) -> $point { - basepoint_table * self - } -} - -impl Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{:?}([\n", stringify!($name))?; - for i in 0..32 { - write!(f, "\t{:?},\n", &self.0[i])?; + /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by + /// computing the multiple \\(aB\\) of this basepoint \\(B\\). + fn mul(self, basepoint_table: &'a $name) -> $point { + basepoint_table * self + } } - write!(f, "])") - } -} -}} // End macro_rules! impl_basepoint_table + impl Debug for $name { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}([\n", stringify!($name))?; + for i in 0..32 { + write!(f, "\t{:?},\n", &self.0[i])?; + } + write!(f, "])") + } + } + }; +} // End macro_rules! impl_basepoint_table // The number of additions required is ceil(256/w) where w is the radix representation. -impl_basepoint_table! {Name = EdwardsBasepointTableRadix16, LookupTable = LookupTableRadix16, Point = EdwardsPoint, Radix = 4, Additions = 64} -impl_basepoint_table! {Name = EdwardsBasepointTableRadix32, LookupTable = LookupTableRadix32, Point = EdwardsPoint, Radix = 5, Additions = 52} -impl_basepoint_table! {Name = EdwardsBasepointTableRadix64, LookupTable = LookupTableRadix64, Point = EdwardsPoint, Radix = 6, Additions = 43} -impl_basepoint_table! {Name = EdwardsBasepointTableRadix128, LookupTable = LookupTableRadix128, Point = EdwardsPoint, Radix = 7, Additions = 37} -impl_basepoint_table! {Name = EdwardsBasepointTableRadix256, LookupTable = LookupTableRadix256, Point = EdwardsPoint, Radix = 8, Additions = 33} - -// ------------------------------------------------------------------------------------- -// BEGIN legacy 3.x series code for backwards compatibility with BasepointTable trait -// ------------------------------------------------------------------------------------- - -/// A precomputed table of multiples of a basepoint, for accelerating -/// fixed-base scalar multiplication. One table, for the Ed25519 -/// basepoint, is provided in the `constants` module. -/// -/// The basepoint tables are reasonably large, so they should probably be boxed. -/// -/// The sizes for the tables and the number of additions required for one scalar -/// multiplication are as follows: -/// -/// * [`EdwardsBasepointTableRadix16`]: 30KB, 64A -/// (this is the default size, and is used for [`ED25519_BASEPOINT_TABLE`]) -/// * [`EdwardsBasepointTableRadix64`]: 120KB, 43A -/// * [`EdwardsBasepointTableRadix128`]: 240KB, 37A -/// * [`EdwardsBasepointTableRadix256`]: 480KB, 33A -/// -/// # Why 33 additions for radix-256? -/// -/// Normally, the radix-256 tables would allow for only 32 additions per scalar -/// multiplication. However, due to the fact that standardised definitions of -/// legacy protocols—such as x25519—require allowing unreduced 255-bit scalar -/// invariants, when converting such an unreduced scalar's representation to -/// radix-\\(2^{8}\\), we cannot guarantee the carry bit will fit in the last -/// coefficient (the coefficients are `i8`s). When, \\(w\\), the power-of-2 of -/// the radix, is \\(w < 8\\), we can fold the final carry onto the last -/// coefficient, \\(d\\), because \\(d < 2^{w/2}\\), so -/// $$ -/// d + carry \cdot 2^{w} = d + 1 \cdot 2^{w} < 2^{w+1} < 2^{8} -/// $$ -/// When \\(w = 8\\), we can't fit \\(carry \cdot 2^{w}\\) into an `i8`, so we -/// add the carry bit onto an additional coefficient. -#[derive(Clone)] -pub struct EdwardsBasepointTable(pub(crate) [LookupTable; 32]); - -impl EdwardsBasepointTable { - /// Create a table of precomputed multiples of `basepoint`. - #[allow(warnings)] - pub fn create(basepoint: &EdwardsPoint) -> EdwardsBasepointTable { - Self(EdwardsBasepointTableRadix16::create(basepoint).0) - } - - /// The computation uses Pippenger's algorithm, as described on - /// page 13 of the Ed25519 paper. Write the scalar \\(a\\) in radix \\(16\\) with - /// coefficients in \\([-8,8)\\), i.e., - /// $$ - /// a = a\_0 + a\_1 16\^1 + \cdots + a\_{63} 16\^{63}, - /// $$ - /// with \\(-8 \leq a_i < 8\\), \\(-8 \leq a\_{63} \leq 8\\). Then - /// $$ - /// a B = a\_0 B + a\_1 16\^1 B + \cdots + a\_{63} 16\^{63} B. - /// $$ - /// Grouping even and odd coefficients gives - /// $$ - /// \begin{aligned} - /// a B = \quad a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B \\\\ - /// + a\_1 16\^1 B +& a\_3 16\^3 B + \cdots + a\_{63} 16\^{63} B \\\\ - /// = \quad(a\_0 16\^0 B +& a\_2 16\^2 B + \cdots + a\_{62} 16\^{62} B) \\\\ - /// + 16(a\_1 16\^0 B +& a\_3 16\^2 B + \cdots + a\_{63} 16\^{62} B). \\\\ - /// \end{aligned} - /// $$ - /// For each \\(i = 0 \ldots 31\\), we create a lookup table of - /// $$ - /// [16\^{2i} B, \ldots, 8\cdot16\^{2i} B], - /// $$ - /// and use it to select \\( x \cdot 16\^{2i} \cdot B \\) in constant time. - /// - /// The radix-\\(16\\) representation requires that the scalar is bounded - /// by \\(2\^{255}\\), which is always the case. - #[allow(warnings)] - pub fn basepoint_mul(&self, scalar: &Scalar) -> EdwardsPoint { - let a = scalar.to_radix_16(); - - let tables = &self.0; - let mut P = EdwardsPoint::identity(); - - for i in (0..64).filter(|x| x % 2 == 1) { - P = (&P + &tables[i/2].select(a[i])).to_extended(); +cfg_if! { + if #[cfg(feature = "precomputed-tables")] { + impl_basepoint_table! { + Name = EdwardsBasepointTable, + LookupTable = LookupTableRadix16, + Point = EdwardsPoint, + Radix = 4, + Additions = 64 } - - P = P.mul_by_pow_2(4); - - for i in (0..64).filter(|x| x % 2 == 0) { - P = (&P + &tables[i/2].select(a[i])).to_extended(); + impl_basepoint_table! { + Name = EdwardsBasepointTableRadix32, + LookupTable = LookupTableRadix32, + Point = EdwardsPoint, + Radix = 5, + Additions = 52 + } + impl_basepoint_table! { + Name = EdwardsBasepointTableRadix64, + LookupTable = LookupTableRadix64, + Point = EdwardsPoint, + Radix = 6, + Additions = 43 + } + impl_basepoint_table! { + Name = EdwardsBasepointTableRadix128, + LookupTable = LookupTableRadix128, + Point = EdwardsPoint, + Radix = 7, + Additions = 37 + } + impl_basepoint_table! { + Name = EdwardsBasepointTableRadix256, + LookupTable = LookupTableRadix256, + Point = EdwardsPoint, + Radix = 8, + Additions = 33 } - P - } - - /// Get the basepoint for this table as an `EdwardsPoint`. - #[allow(warnings)] - pub fn basepoint(&self) -> EdwardsPoint { - (&EdwardsPoint::identity() + &self.0[0].select(1)).to_extended() - } -} - -impl<'a, 'b> Mul<&'b Scalar> for &'a EdwardsBasepointTable { - type Output = EdwardsPoint; - - /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by - /// computing the multiple \\(aB\\) of this basepoint \\(B\\). - fn mul(self, scalar: &'b Scalar) -> EdwardsPoint { - // delegate to a private function so that its documentation appears in internal docs - self.basepoint_mul(scalar) - } -} - -impl<'a, 'b> Mul<&'a EdwardsBasepointTable> for &'b Scalar { - type Output = EdwardsPoint; - - /// Construct an `EdwardsPoint` from a `Scalar` \\(a\\) by - /// computing the multiple \\(aB\\) of this basepoint \\(B\\). - fn mul(self, basepoint_table: &'a EdwardsBasepointTable) -> EdwardsPoint { - basepoint_table * self + /// A type-alias for [`EdwardsBasepointTable`] because the latter is + /// used as a constructor in the [`constants`] module. + // + // Same as for `LookupTableRadix16`, we have to define `EdwardsBasepointTable` + // first, because it's used as a constructor, and then provide a type alias for + // it. + pub type EdwardsBasepointTableRadix16 = EdwardsBasepointTable; } } -// ------------------------------------------------------------------------------------- -// END legacy 3.x series code for backwards compatibility with BasepointTable trait -// ------------------------------------------------------------------------------------- - +#[cfg(feature = "precomputed-tables")] macro_rules! impl_basepoint_table_conversions { (LHS = $lhs:ty, RHS = $rhs:ty) => { impl<'a> From<&'a $lhs> for $rhs { @@ -1093,47 +1127,86 @@ macro_rules! impl_basepoint_table_conversions { <$lhs>::create(&table.basepoint()) } } - } + }; } -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix32} -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix64} -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix128} -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix16, RHS = EdwardsBasepointTableRadix256} +cfg_if! { + if #[cfg(feature = "precomputed-tables")] { + // Conversions from radix 16 + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix16, + RHS = EdwardsBasepointTableRadix32 + } + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix16, + RHS = EdwardsBasepointTableRadix64 + } + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix16, + RHS = EdwardsBasepointTableRadix128 + } + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix16, + RHS = EdwardsBasepointTableRadix256 + } -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix64} -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix128} -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix32, RHS = EdwardsBasepointTableRadix256} + // Conversions from radix 32 + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix32, + RHS = EdwardsBasepointTableRadix64 + } + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix32, + RHS = EdwardsBasepointTableRadix128 + } + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix32, + RHS = EdwardsBasepointTableRadix256 + } -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix128} -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix64, RHS = EdwardsBasepointTableRadix256} + // Conversions from radix 64 + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix64, + RHS = EdwardsBasepointTableRadix128 + } + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix64, + RHS = EdwardsBasepointTableRadix256 + } -impl_basepoint_table_conversions!{LHS = EdwardsBasepointTableRadix128, RHS = EdwardsBasepointTableRadix256} + // Conversions from radix 128 + impl_basepoint_table_conversions! { + LHS = EdwardsBasepointTableRadix128, + RHS = EdwardsBasepointTableRadix256 + } + } +} impl EdwardsPoint { - /// Multiply by the cofactor: return \\([8]P\\). + /// Multiply by the cofactor: return \\(\[8\]P\\). pub fn mul_by_cofactor(&self) -> EdwardsPoint { self.mul_by_pow_2(3) } /// Compute \\([2\^k] P \\) by successive doublings. Requires \\( k > 0 \\). pub(crate) fn mul_by_pow_2(&self, k: u32) -> EdwardsPoint { - debug_assert!( k > 0 ); + debug_assert!(k > 0); let mut r: CompletedPoint; - let mut s = self.to_projective(); - for _ in 0..(k-1) { - r = s.double(); s = r.to_projective(); + let mut s = self.as_projective(); + for _ in 0..(k - 1) { + r = s.double(); + s = r.as_projective(); } - // Unroll last iteration so we can go directly to_extended() - s.double().to_extended() + // Unroll last iteration so we can go directly as_extended() + s.double().as_extended() } /// Determine if this point is of small order. /// /// # Return /// - /// * `true` if `self` is in the torsion subgroup \\( \mathcal E[8] \\); - /// * `false` if `self` is not in the torsion subgroup \\( \mathcal E[8] \\). + /// * `true` if `self` is in the torsion subgroup \\( \mathcal E\[8\] \\); + /// * `false` if `self` is not in the torsion subgroup \\( \mathcal E\[8\] \\). /// /// # Example /// @@ -1182,7 +1255,7 @@ impl EdwardsPoint { /// assert_eq!((P+Q).is_torsion_free(), false); /// ``` pub fn is_torsion_free(&self) -> bool { - (self * constants::BASEPOINT_ORDER).is_identity() + (self * constants::BASEPOINT_ORDER_PRIVATE).is_identity() } } @@ -1191,9 +1264,324 @@ impl EdwardsPoint { // ------------------------------------------------------------------------ impl Debug for EdwardsPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", - &self.X, &self.Y, &self.Z, &self.T) + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!( + f, + "EdwardsPoint{{\n\tX: {:?},\n\tY: {:?},\n\tZ: {:?},\n\tT: {:?}\n}}", + &self.X, &self.Y, &self.Z, &self.T + ) + } +} + +// ------------------------------------------------------------------------ +// group traits +// ------------------------------------------------------------------------ + +// Use the full trait path to avoid Group::identity overlapping Identity::identity in the +// rest of the module (e.g. tests). +#[cfg(feature = "group")] +impl group::Group for EdwardsPoint { + type Scalar = Scalar; + + fn random(mut rng: impl RngCore) -> Self { + let mut repr = CompressedEdwardsY([0u8; 32]); + loop { + rng.fill_bytes(&mut repr.0); + if let Some(p) = repr.decompress() { + if !IsIdentity::is_identity(&p) { + break p; + } + } + } + } + + fn identity() -> Self { + Identity::identity() + } + + fn generator() -> Self { + constants::ED25519_BASEPOINT_POINT + } + + fn is_identity(&self) -> Choice { + self.ct_eq(&Identity::identity()) + } + + fn double(&self) -> Self { + self.double() + } +} + +#[cfg(feature = "group")] +impl GroupEncoding for EdwardsPoint { + type Repr = [u8; 32]; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + let repr = CompressedEdwardsY(*bytes); + let (is_valid_y_coord, X, Y, Z) = decompress::step_1(&repr); + CtOption::new(decompress::step_2(&repr, X, Y, Z), is_valid_y_coord) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + // Just use the checked API; there are no checks we can skip. + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + self.compress().to_bytes() + } +} + +/// A `SubgroupPoint` represents a point on the Edwards form of Curve25519, that is +/// guaranteed to be in the prime-order subgroup. +#[cfg(feature = "group")] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct SubgroupPoint(EdwardsPoint); + +#[cfg(feature = "group")] +impl From for EdwardsPoint { + fn from(p: SubgroupPoint) -> Self { + p.0 + } +} + +#[cfg(feature = "group")] +impl Neg for SubgroupPoint { + type Output = Self; + + fn neg(self) -> Self::Output { + SubgroupPoint(-self.0) + } +} + +#[cfg(feature = "group")] +impl Add<&SubgroupPoint> for &SubgroupPoint { + type Output = SubgroupPoint; + fn add(self, other: &SubgroupPoint) -> SubgroupPoint { + SubgroupPoint(self.0 + other.0) + } +} + +#[cfg(feature = "group")] +define_add_variants!( + LHS = SubgroupPoint, + RHS = SubgroupPoint, + Output = SubgroupPoint +); + +#[cfg(feature = "group")] +impl Add<&SubgroupPoint> for &EdwardsPoint { + type Output = EdwardsPoint; + fn add(self, other: &SubgroupPoint) -> EdwardsPoint { + self + other.0 + } +} + +#[cfg(feature = "group")] +define_add_variants!( + LHS = EdwardsPoint, + RHS = SubgroupPoint, + Output = EdwardsPoint +); + +#[cfg(feature = "group")] +impl AddAssign<&SubgroupPoint> for SubgroupPoint { + fn add_assign(&mut self, rhs: &SubgroupPoint) { + self.0 += rhs.0 + } +} + +#[cfg(feature = "group")] +define_add_assign_variants!(LHS = SubgroupPoint, RHS = SubgroupPoint); + +#[cfg(feature = "group")] +impl AddAssign<&SubgroupPoint> for EdwardsPoint { + fn add_assign(&mut self, rhs: &SubgroupPoint) { + *self += rhs.0 + } +} + +#[cfg(feature = "group")] +define_add_assign_variants!(LHS = EdwardsPoint, RHS = SubgroupPoint); + +#[cfg(feature = "group")] +impl Sub<&SubgroupPoint> for &SubgroupPoint { + type Output = SubgroupPoint; + fn sub(self, other: &SubgroupPoint) -> SubgroupPoint { + SubgroupPoint(self.0 - other.0) + } +} + +#[cfg(feature = "group")] +define_sub_variants!( + LHS = SubgroupPoint, + RHS = SubgroupPoint, + Output = SubgroupPoint +); + +#[cfg(feature = "group")] +impl Sub<&SubgroupPoint> for &EdwardsPoint { + type Output = EdwardsPoint; + fn sub(self, other: &SubgroupPoint) -> EdwardsPoint { + self - other.0 + } +} + +#[cfg(feature = "group")] +define_sub_variants!( + LHS = EdwardsPoint, + RHS = SubgroupPoint, + Output = EdwardsPoint +); + +#[cfg(feature = "group")] +impl SubAssign<&SubgroupPoint> for SubgroupPoint { + fn sub_assign(&mut self, rhs: &SubgroupPoint) { + self.0 -= rhs.0; + } +} + +#[cfg(feature = "group")] +define_sub_assign_variants!(LHS = SubgroupPoint, RHS = SubgroupPoint); + +#[cfg(feature = "group")] +impl SubAssign<&SubgroupPoint> for EdwardsPoint { + fn sub_assign(&mut self, rhs: &SubgroupPoint) { + *self -= rhs.0; + } +} + +#[cfg(feature = "group")] +define_sub_assign_variants!(LHS = EdwardsPoint, RHS = SubgroupPoint); + +#[cfg(feature = "group")] +impl Sum for SubgroupPoint +where + T: Borrow, +{ + fn sum(iter: I) -> Self + where + I: Iterator, + { + use group::Group; + iter.fold(SubgroupPoint::identity(), |acc, item| acc + item.borrow()) + } +} + +#[cfg(feature = "group")] +impl Mul<&Scalar> for &SubgroupPoint { + type Output = SubgroupPoint; + + /// Scalar multiplication: compute `scalar * self`. + /// + /// For scalar multiplication of a basepoint, + /// `EdwardsBasepointTable` is approximately 4x faster. + fn mul(self, scalar: &Scalar) -> SubgroupPoint { + SubgroupPoint(self.0 * scalar) + } +} + +#[cfg(feature = "group")] +define_mul_variants!(LHS = Scalar, RHS = SubgroupPoint, Output = SubgroupPoint); + +#[cfg(feature = "group")] +impl Mul<&SubgroupPoint> for &Scalar { + type Output = SubgroupPoint; + + /// Scalar multiplication: compute `scalar * self`. + /// + /// For scalar multiplication of a basepoint, + /// `EdwardsBasepointTable` is approximately 4x faster. + fn mul(self, point: &SubgroupPoint) -> SubgroupPoint { + point * self + } +} + +#[cfg(feature = "group")] +define_mul_variants!(LHS = SubgroupPoint, RHS = Scalar, Output = SubgroupPoint); + +#[cfg(feature = "group")] +impl MulAssign<&Scalar> for SubgroupPoint { + fn mul_assign(&mut self, scalar: &Scalar) { + self.0 *= scalar; + } +} + +#[cfg(feature = "group")] +define_mul_assign_variants!(LHS = SubgroupPoint, RHS = Scalar); + +#[cfg(feature = "group")] +impl group::Group for SubgroupPoint { + type Scalar = Scalar; + + fn random(mut rng: impl RngCore) -> Self { + use group::ff::Field; + + // This will almost never loop, but `Group::random` is documented as returning a + // non-identity element. + let s = loop { + let s: Scalar = Field::random(&mut rng); + if !s.is_zero_vartime() { + break s; + } + }; + + // This gives an element of the prime-order subgroup. + Self::generator() * s + } + + fn identity() -> Self { + SubgroupPoint(Identity::identity()) + } + + fn generator() -> Self { + SubgroupPoint(EdwardsPoint::generator()) + } + + fn is_identity(&self) -> Choice { + self.0.ct_eq(&Identity::identity()) + } + + fn double(&self) -> Self { + SubgroupPoint(self.0.double()) + } +} + +#[cfg(feature = "group")] +impl GroupEncoding for SubgroupPoint { + type Repr = ::Repr; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + EdwardsPoint::from_bytes(bytes).and_then(|p| p.into_subgroup()) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + EdwardsPoint::from_bytes_unchecked(bytes).and_then(|p| p.into_subgroup()) + } + + fn to_bytes(&self) -> Self::Repr { + self.0.compress().to_bytes() + } +} + +#[cfg(feature = "group")] +impl PrimeGroup for SubgroupPoint {} + +/// Ristretto has a cofactor of 1. +#[cfg(feature = "group")] +impl CofactorGroup for EdwardsPoint { + type Subgroup = SubgroupPoint; + + fn clear_cofactor(&self) -> Self::Subgroup { + SubgroupPoint(self.mul_by_cofactor()) + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(SubgroupPoint(self), CofactorGroup::is_torsion_free(&self)) + } + + fn is_torsion_free(&self) -> Choice { + (self * constants::BASEPOINT_ORDER_PRIVATE).ct_eq(&Self::identity()) } } @@ -1203,72 +1591,80 @@ impl Debug for EdwardsPoint { #[cfg(test)] mod test { - use field::FieldElement; - use scalar::Scalar; - use subtle::ConditionallySelectable; - use constants; use super::*; + // If `group` is set, then this is already imported in super + #[cfg(not(feature = "group"))] + use rand_core::RngCore; + + #[cfg(feature = "alloc")] + use alloc::vec::Vec; + + #[cfg(feature = "precomputed-tables")] + use crate::constants::ED25519_BASEPOINT_TABLE; + /// X coordinate of the basepoint. /// = 15112221349535400772501151409588531511454012693041857206046113283949847762202 - static BASE_X_COORD_BYTES: [u8; 32] = - [0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, 0x69, - 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, 0x69, 0x21]; + static BASE_X_COORD_BYTES: [u8; 32] = [ + 0x1a, 0xd5, 0x25, 0x8f, 0x60, 0x2d, 0x56, 0xc9, 0xb2, 0xa7, 0x25, 0x95, 0x60, 0xc7, 0x2c, + 0x69, 0x5c, 0xdc, 0xd6, 0xfd, 0x31, 0xe2, 0xa4, 0xc0, 0xfe, 0x53, 0x6e, 0xcd, 0xd3, 0x36, + 0x69, 0x21, + ]; /// Compressed Edwards Y form of 2*basepoint. - static BASE2_CMPRSSD: CompressedEdwardsY = - CompressedEdwardsY([0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe, - 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, 0x97, - 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, - 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, 0x60, 0x22]); + static BASE2_CMPRSSD: CompressedEdwardsY = CompressedEdwardsY([ + 0xc9, 0xa3, 0xf8, 0x6a, 0xae, 0x46, 0x5f, 0xe, 0x56, 0x51, 0x38, 0x64, 0x51, 0x0f, 0x39, + 0x97, 0x56, 0x1f, 0xa2, 0xc9, 0xe8, 0x5e, 0xa2, 0x1d, 0xc2, 0x29, 0x23, 0x09, 0xf3, 0xcd, + 0x60, 0x22, + ]); /// Compressed Edwards Y form of 16*basepoint. - static BASE16_CMPRSSD: CompressedEdwardsY = - CompressedEdwardsY([0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, - 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, 0xb0, - 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, - 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, 0x96, 0x70]); + static BASE16_CMPRSSD: CompressedEdwardsY = CompressedEdwardsY([ + 0xeb, 0x27, 0x67, 0xc1, 0x37, 0xab, 0x7a, 0xd8, 0x27, 0x9c, 0x07, 0x8e, 0xff, 0x11, 0x6a, + 0xb0, 0x78, 0x6e, 0xad, 0x3a, 0x2e, 0x0f, 0x98, 0x9f, 0x72, 0xc3, 0x7f, 0x82, 0xf2, 0x96, + 0x96, 0x70, + ]); /// 4493907448824000747700850167940867464579944529806937181821189941592931634714 - pub static A_SCALAR: Scalar = Scalar{ + pub static A_SCALAR: Scalar = Scalar { bytes: [ - 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, - 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d, - 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, - 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09, + 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, + 0x26, 0x4d, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0x58, 0x9e, 0x7b, 0x7f, + 0x23, 0x76, 0xef, 0x09, ], }; /// 2506056684125797857694181776241676200180934651973138769173342316833279714961 - pub static B_SCALAR: Scalar = Scalar{ + pub static B_SCALAR: Scalar = Scalar { bytes: [ - 0x91, 0x26, 0x7a, 0xcf, 0x25, 0xc2, 0x09, 0x1b, - 0xa2, 0x17, 0x74, 0x7b, 0x66, 0xf0, 0xb3, 0x2e, - 0x9d, 0xf2, 0xa5, 0x67, 0x41, 0xcf, 0xda, 0xc4, - 0x56, 0xa7, 0xd4, 0xaa, 0xb8, 0x60, 0x8a, 0x05, + 0x91, 0x26, 0x7a, 0xcf, 0x25, 0xc2, 0x09, 0x1b, 0xa2, 0x17, 0x74, 0x7b, 0x66, 0xf0, + 0xb3, 0x2e, 0x9d, 0xf2, 0xa5, 0x67, 0x41, 0xcf, 0xda, 0xc4, 0x56, 0xa7, 0xd4, 0xaa, + 0xb8, 0x60, 0x8a, 0x05, ], }; /// A_SCALAR * basepoint, computed with ed25519.py pub static A_TIMES_BASEPOINT: CompressedEdwardsY = CompressedEdwardsY([ - 0xea, 0x27, 0xe2, 0x60, 0x53, 0xdf, 0x1b, 0x59, - 0x56, 0xf1, 0x4d, 0x5d, 0xec, 0x3c, 0x34, 0xc3, - 0x84, 0xa2, 0x69, 0xb7, 0x4c, 0xc3, 0x80, 0x3e, - 0xa8, 0xe2, 0xe7, 0xc9, 0x42, 0x5e, 0x40, 0xa5]); + 0xea, 0x27, 0xe2, 0x60, 0x53, 0xdf, 0x1b, 0x59, 0x56, 0xf1, 0x4d, 0x5d, 0xec, 0x3c, 0x34, + 0xc3, 0x84, 0xa2, 0x69, 0xb7, 0x4c, 0xc3, 0x80, 0x3e, 0xa8, 0xe2, 0xe7, 0xc9, 0x42, 0x5e, + 0x40, 0xa5, + ]); /// A_SCALAR * (A_TIMES_BASEPOINT) + B_SCALAR * BASEPOINT /// computed with ed25519.py static DOUBLE_SCALAR_MULT_RESULT: CompressedEdwardsY = CompressedEdwardsY([ - 0x7d, 0xfd, 0x6c, 0x45, 0xaf, 0x6d, 0x6e, 0x0e, - 0xba, 0x20, 0x37, 0x1a, 0x23, 0x64, 0x59, 0xc4, - 0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85, - 0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13, 0x2b, 0x42]); + 0x7d, 0xfd, 0x6c, 0x45, 0xaf, 0x6d, 0x6e, 0x0e, 0xba, 0x20, 0x37, 0x1a, 0x23, 0x64, 0x59, + 0xc4, 0xc0, 0x46, 0x83, 0x43, 0xde, 0x70, 0x4b, 0x85, 0x09, 0x6f, 0xfe, 0x35, 0x4f, 0x13, + 0x2b, 0x42, + ]); /// Test round-trip decompression for the basepoint. #[test] fn basepoint_decompression_compression() { let base_X = FieldElement::from_bytes(&BASE_X_COORD_BYTES); - let bp = constants::ED25519_BASEPOINT_COMPRESSED.decompress().unwrap(); + let bp = constants::ED25519_BASEPOINT_COMPRESSED + .decompress() + .unwrap(); assert!(bp.is_valid()); // Check that decompression actually gives the correct X coordinate assert_eq!(base_X, bp.X); @@ -1279,30 +1675,33 @@ mod test { #[test] fn decompression_sign_handling() { // Manually set the high bit of the last byte to flip the sign - let mut minus_basepoint_bytes = constants::ED25519_BASEPOINT_COMPRESSED.as_bytes().clone(); + let mut minus_basepoint_bytes = *constants::ED25519_BASEPOINT_COMPRESSED.as_bytes(); minus_basepoint_bytes[31] |= 1 << 7; let minus_basepoint = CompressedEdwardsY(minus_basepoint_bytes) - .decompress().unwrap(); + .decompress() + .unwrap(); // Test projective coordinates exactly since we know they should // only differ by a flipped sign. assert_eq!(minus_basepoint.X, -(&constants::ED25519_BASEPOINT_POINT.X)); - assert_eq!(minus_basepoint.Y, constants::ED25519_BASEPOINT_POINT.Y); - assert_eq!(minus_basepoint.Z, constants::ED25519_BASEPOINT_POINT.Z); + assert_eq!(minus_basepoint.Y, constants::ED25519_BASEPOINT_POINT.Y); + assert_eq!(minus_basepoint.Z, constants::ED25519_BASEPOINT_POINT.Z); assert_eq!(minus_basepoint.T, -(&constants::ED25519_BASEPOINT_POINT.T)); } /// Test that computing 1*basepoint gives the correct basepoint. + #[cfg(feature = "precomputed-tables")] #[test] fn basepoint_mult_one_vs_basepoint() { - let bp = &constants::ED25519_BASEPOINT_TABLE * &Scalar::one(); + let bp = ED25519_BASEPOINT_TABLE * &Scalar::ONE; let compressed = bp.compress(); assert_eq!(compressed, constants::ED25519_BASEPOINT_COMPRESSED); } /// Test that `EdwardsBasepointTable::basepoint()` gives the correct basepoint. + #[cfg(feature = "precomputed-tables")] #[test] fn basepoint_table_basepoint_function_correct() { - let bp = constants::ED25519_BASEPOINT_TABLE.basepoint(); + let bp = ED25519_BASEPOINT_TABLE.basepoint(); assert_eq!(bp.compress(), constants::ED25519_BASEPOINT_COMPRESSED); } @@ -1311,7 +1710,7 @@ mod test { #[test] fn basepoint_plus_basepoint_vs_basepoint2() { let bp = constants::ED25519_BASEPOINT_POINT; - let bp_added = &bp + &bp; + let bp_added = bp + bp; assert_eq!(bp_added.compress(), BASE2_CMPRSSD); } @@ -1320,7 +1719,7 @@ mod test { #[test] fn basepoint_plus_basepoint_projective_niels_vs_basepoint2() { let bp = constants::ED25519_BASEPOINT_POINT; - let bp_added = (&bp + &bp.to_projective_niels()).to_extended(); + let bp_added = (&bp + &bp.as_projective_niels()).as_extended(); assert_eq!(bp_added.compress(), BASE2_CMPRSSD); } @@ -1329,8 +1728,8 @@ mod test { #[test] fn basepoint_plus_basepoint_affine_niels_vs_basepoint2() { let bp = constants::ED25519_BASEPOINT_POINT; - let bp_affine_niels = bp.to_affine_niels(); - let bp_added = (&bp + &bp_affine_niels).to_extended(); + let bp_affine_niels = bp.as_affine_niels(); + let bp_added = (&bp + &bp_affine_niels).as_extended(); assert_eq!(bp_added.compress(), BASE2_CMPRSSD); } @@ -1338,86 +1737,90 @@ mod test { /// coordinates correctly. #[test] fn extended_point_equality_handles_scaling() { - let mut two_bytes = [0u8; 32]; two_bytes[0] = 2; + let mut two_bytes = [0u8; 32]; + two_bytes[0] = 2; let id1 = EdwardsPoint::identity(); - let id2 = EdwardsPoint{ - X: FieldElement::zero(), + let id2 = EdwardsPoint { + X: FieldElement::ZERO, Y: FieldElement::from_bytes(&two_bytes), Z: FieldElement::from_bytes(&two_bytes), - T: FieldElement::zero() + T: FieldElement::ZERO, }; - assert_eq!(id1.ct_eq(&id2).unwrap_u8(), 1u8); + assert!(bool::from(id1.ct_eq(&id2))); } /// Sanity check for conversion to precomputed points + #[cfg(feature = "precomputed-tables")] #[test] fn to_affine_niels_clears_denominators() { // construct a point as aB so it has denominators (ie. Z != 1) - let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; - let aB_affine_niels = aB.to_affine_niels(); - let also_aB = (&EdwardsPoint::identity() + &aB_affine_niels).to_extended(); - assert_eq!( aB.compress(), - also_aB.compress()); + let aB = ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB_affine_niels = aB.as_affine_niels(); + let also_aB = (&EdwardsPoint::identity() + &aB_affine_niels).as_extended(); + assert_eq!(aB.compress(), also_aB.compress()); } - /// Test basepoint_mult versus a known scalar multiple from ed25519.py + /// Test mul_base versus a known scalar multiple from ed25519.py #[test] fn basepoint_mult_vs_ed25519py() { - let aB = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB = EdwardsPoint::mul_base(&A_SCALAR); assert_eq!(aB.compress(), A_TIMES_BASEPOINT); } /// Test that multiplication by the basepoint order kills the basepoint #[test] fn basepoint_mult_by_basepoint_order() { - let B = &constants::ED25519_BASEPOINT_TABLE; - let should_be_id = B * &constants::BASEPOINT_ORDER; + let should_be_id = EdwardsPoint::mul_base(&constants::BASEPOINT_ORDER_PRIVATE); assert!(should_be_id.is_identity()); } /// Test precomputed basepoint mult + #[cfg(feature = "precomputed-tables")] #[test] fn test_precomputed_basepoint_mult() { - let aB_1 = &constants::ED25519_BASEPOINT_TABLE * &A_SCALAR; - let aB_2 = &constants::ED25519_BASEPOINT_POINT * &A_SCALAR; + let aB_1 = ED25519_BASEPOINT_TABLE * &A_SCALAR; + let aB_2 = constants::ED25519_BASEPOINT_POINT * A_SCALAR; assert_eq!(aB_1.compress(), aB_2.compress()); } /// Test scalar_mul versus a known scalar multiple from ed25519.py #[test] fn scalar_mul_vs_ed25519py() { - let aB = &constants::ED25519_BASEPOINT_POINT * &A_SCALAR; + let aB = constants::ED25519_BASEPOINT_POINT * A_SCALAR; assert_eq!(aB.compress(), A_TIMES_BASEPOINT); } /// Test basepoint.double() versus the 2*basepoint constant. #[test] fn basepoint_double_vs_basepoint2() { - assert_eq!(constants::ED25519_BASEPOINT_POINT.double().compress(), - BASE2_CMPRSSD); + assert_eq!( + constants::ED25519_BASEPOINT_POINT.double().compress(), + BASE2_CMPRSSD + ); } /// Test that computing 2*basepoint is the same as basepoint.double() #[test] fn basepoint_mult_two_vs_basepoint2() { let two = Scalar::from(2u64); - let bp2 = &constants::ED25519_BASEPOINT_TABLE * &two; + let bp2 = EdwardsPoint::mul_base(&two); assert_eq!(bp2.compress(), BASE2_CMPRSSD); } /// Test that all the basepoint table types compute the same results. + #[cfg(feature = "precomputed-tables")] #[test] fn basepoint_tables() { let P = &constants::ED25519_BASEPOINT_POINT; let a = A_SCALAR; - let table_radix16 = EdwardsBasepointTableRadix16::create(&P); - let table_radix32 = EdwardsBasepointTableRadix32::create(&P); - let table_radix64 = EdwardsBasepointTableRadix64::create(&P); - let table_radix128 = EdwardsBasepointTableRadix128::create(&P); - let table_radix256 = EdwardsBasepointTableRadix256::create(&P); + let table_radix16 = EdwardsBasepointTableRadix16::create(P); + let table_radix32 = EdwardsBasepointTableRadix32::create(P); + let table_radix64 = EdwardsBasepointTableRadix64::create(P); + let table_radix128 = EdwardsBasepointTableRadix128::create(P); + let table_radix256 = EdwardsBasepointTableRadix256::create(P); - let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); + let aP = (ED25519_BASEPOINT_TABLE * &a).compress(); let aP16 = (&table_radix16 * &a).compress(); let aP32 = (&table_radix32 * &a).compress(); let aP64 = (&table_radix64 * &a).compress(); @@ -1431,24 +1834,21 @@ mod test { assert_eq!(aP128, aP256); } - // Check a unreduced scalar multiplication by the basepoint tables. + /// Check unreduced scalar multiplication by the basepoint tables is the same no matter what + /// radix the table is. + #[cfg(feature = "precomputed-tables")] #[test] fn basepoint_tables_unreduced_scalar() { let P = &constants::ED25519_BASEPOINT_POINT; - let a = Scalar::from_bits([ - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - ]); - - let table_radix16 = EdwardsBasepointTableRadix16::create(&P); - let table_radix32 = EdwardsBasepointTableRadix32::create(&P); - let table_radix64 = EdwardsBasepointTableRadix64::create(&P); - let table_radix128 = EdwardsBasepointTableRadix128::create(&P); - let table_radix256 = EdwardsBasepointTableRadix256::create(&P); - - let aP = (&constants::ED25519_BASEPOINT_TABLE * &a).compress(); + let a = crate::scalar::test::LARGEST_UNREDUCED_SCALAR; + + let table_radix16 = EdwardsBasepointTableRadix16::create(P); + let table_radix32 = EdwardsBasepointTableRadix32::create(P); + let table_radix64 = EdwardsBasepointTableRadix64::create(P); + let table_radix128 = EdwardsBasepointTableRadix128::create(P); + let table_radix256 = EdwardsBasepointTableRadix256::create(P); + + let aP = (ED25519_BASEPOINT_TABLE * &a).compress(); let aP16 = (&table_radix16 * &a).compress(); let aP32 = (&table_radix32 * &a).compress(); let aP64 = (&table_radix64 * &a).compress(); @@ -1465,9 +1865,13 @@ mod test { /// Check that converting to projective and then back to extended round-trips. #[test] fn basepoint_projective_extended_round_trip() { - assert_eq!(constants::ED25519_BASEPOINT_POINT - .to_projective().to_extended().compress(), - constants::ED25519_BASEPOINT_COMPRESSED); + assert_eq!( + constants::ED25519_BASEPOINT_POINT + .as_projective() + .as_extended() + .compress(), + constants::ED25519_BASEPOINT_COMPRESSED + ); } /// Test computing 16*basepoint vs mul_by_pow_2(4) @@ -1477,19 +1881,68 @@ mod test { assert_eq!(bp16.compress(), BASE16_CMPRSSD); } + /// Check that mul_base_clamped and mul_clamped agree #[test] - fn impl_sum() { + fn mul_base_clamped() { + let mut csprng = rand_core::OsRng; + + // Make a random curve point in the curve. Give it torsion to make things interesting. + #[cfg(feature = "precomputed-tables")] + let random_point = { + let mut b = [0u8; 32]; + csprng.fill_bytes(&mut b); + EdwardsPoint::mul_base_clamped(b) + constants::EIGHT_TORSION[1] + }; + // Make a basepoint table from the random point. We'll use this with mul_base_clamped + #[cfg(feature = "precomputed-tables")] + let random_table = EdwardsBasepointTableRadix256::create(&random_point); + + // Now test scalar mult. agreement on the default basepoint as well as random_point + + // Test that mul_base_clamped and mul_clamped agree on a large integer. Even after + // clamping, this integer is not reduced mod l. + let a_bytes = [0xff; 32]; + assert_eq!( + EdwardsPoint::mul_base_clamped(a_bytes), + constants::ED25519_BASEPOINT_POINT.mul_clamped(a_bytes) + ); + #[cfg(feature = "precomputed-tables")] + assert_eq!( + random_table.mul_base_clamped(a_bytes), + random_point.mul_clamped(a_bytes) + ); + + // Test agreement on random integers + for _ in 0..100 { + // This will be reduced mod l with probability l / 2^256 ≈ 6.25% + let mut a_bytes = [0u8; 32]; + csprng.fill_bytes(&mut a_bytes); + assert_eq!( + EdwardsPoint::mul_base_clamped(a_bytes), + constants::ED25519_BASEPOINT_POINT.mul_clamped(a_bytes) + ); + #[cfg(feature = "precomputed-tables")] + assert_eq!( + random_table.mul_base_clamped(a_bytes), + random_point.mul_clamped(a_bytes) + ); + } + } + + #[test] + #[cfg(feature = "alloc")] + fn impl_sum() { // Test that sum works for non-empty iterators let BASE = constants::ED25519_BASEPOINT_POINT; let s1 = Scalar::from(999u64); - let P1 = &BASE * &s1; + let P1 = BASE * s1; let s2 = Scalar::from(333u64); - let P2 = &BASE * &s2; + let P2 = BASE * s2; - let vec = vec![P1.clone(), P2.clone()]; + let vec = vec![P1, P2]; let sum: EdwardsPoint = vec.iter().sum(); assert_eq!(sum, P1 + P2); @@ -1505,16 +1958,15 @@ mod test { let mapped = vec.iter().map(|x| x * s); let sum: EdwardsPoint = mapped.sum(); - assert_eq!(sum, &P1 * &s + &P2 * &s); - } - + assert_eq!(sum, P1 * s + P2 * s); + } /// Test that the conditional assignment trait works for AffineNielsPoints. #[test] fn conditional_assign_for_affine_niels_point() { - let id = AffineNielsPoint::identity(); + let id = AffineNielsPoint::identity(); let mut p1 = AffineNielsPoint::identity(); - let bp = constants::ED25519_BASEPOINT_POINT.to_affine_niels(); + let bp = constants::ED25519_BASEPOINT_POINT.as_affine_niels(); p1.conditional_assign(&bp, Choice::from(0)); assert_eq!(p1, id); @@ -1534,13 +1986,15 @@ mod test { #[test] fn compressed_identity() { - assert_eq!(EdwardsPoint::identity().compress(), - CompressedEdwardsY::identity()); + assert_eq!( + EdwardsPoint::identity().compress(), + CompressedEdwardsY::identity() + ); } #[test] fn is_identity() { - assert!( EdwardsPoint::identity().is_identity()); + assert!(EdwardsPoint::identity().is_identity()); assert!(!constants::ED25519_BASEPOINT_POINT.is_identity()); } @@ -1569,39 +2023,31 @@ mod test { let G: EdwardsPoint = constants::ED25519_BASEPOINT_POINT; let s: Scalar = A_SCALAR; - let P1 = &G * &s; - let P2 = &s * &G; + let P1 = G * s; + let P2 = s * G; assert!(P1.compress().to_bytes() == P2.compress().to_bytes()); } // A single iteration of a consistency check for MSM. + #[cfg(feature = "alloc")] fn multiscalar_consistency_iter(n: usize) { - use core::iter; let mut rng = rand::thread_rng(); // Construct random coefficients x0, ..., x_{n-1}, // followed by some extra hardcoded ones. - let xs = (0..n) - .map(|_| Scalar::random(&mut rng)) - // The largest scalar allowed by the type system, 2^255-1 - .chain(iter::once(Scalar::from_bits([0xff; 32]))) - .collect::>(); - let check = xs.iter() - .map(|xi| xi * xi) - .sum::(); + let xs = (0..n).map(|_| Scalar::random(&mut rng)).collect::>(); + let check = xs.iter().map(|xi| xi * xi).sum::(); // Construct points G_i = x_i * B - let Gs = xs.iter() - .map(|xi| xi * &constants::ED25519_BASEPOINT_TABLE) - .collect::>(); + let Gs = xs.iter().map(EdwardsPoint::mul_base).collect::>(); // Compute H1 = (consttime) let H1 = EdwardsPoint::multiscalar_mul(&xs, &Gs); // Compute H2 = (vartime) let H2 = EdwardsPoint::vartime_multiscalar_mul(&xs, &Gs); // Compute H3 = = sum(xi^2) * B - let H3 = &check * &constants::ED25519_BASEPOINT_TABLE; + let H3 = EdwardsPoint::mul_base(&check); assert_eq!(H1, H3); assert_eq!(H2, H3); @@ -1611,6 +2057,7 @@ mod test { // parameters. #[test] + #[cfg(feature = "alloc")] fn multiscalar_consistency_n_100() { let iters = 50; for _ in 0..iters { @@ -1619,6 +2066,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn multiscalar_consistency_n_250() { let iters = 50; for _ in 0..iters { @@ -1627,6 +2075,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn multiscalar_consistency_n_500() { let iters = 50; for _ in 0..iters { @@ -1635,6 +2084,7 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn multiscalar_consistency_n_1000() { let iters = 50; for _ in 0..iters { @@ -1643,11 +2093,10 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); - let B = &::constants::ED25519_BASEPOINT_TABLE; - let static_scalars = (0..128) .map(|_| Scalar::random(&mut rng)) .collect::>(); @@ -1662,8 +2111,14 @@ mod test { .map(|s| s * s) .sum(); - let static_points = static_scalars.iter().map(|s| s * B).collect::>(); - let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::>(); + let static_points = static_scalars + .iter() + .map(EdwardsPoint::mul_base) + .collect::>(); + let dynamic_points = dynamic_scalars + .iter() + .map(EdwardsPoint::mul_base) + .collect::>(); let precomputation = VartimeEdwardsPrecomputation::new(static_points.iter()); @@ -1673,13 +2128,13 @@ mod test { &dynamic_points, ); - use traits::VartimeMultiscalarMul; + use crate::traits::VartimeMultiscalarMul; let Q = EdwardsPoint::vartime_multiscalar_mul( static_scalars.iter().chain(dynamic_scalars.iter()), static_points.iter().chain(dynamic_points.iter()), ); - let R = &check_scalar * B; + let R = EdwardsPoint::mul_base(&check_scalar); assert_eq!(P.compress(), R.compress()); assert_eq!(Q.compress(), R.compress()); @@ -1687,36 +2142,39 @@ mod test { mod vartime { use super::super::*; - use super::{A_SCALAR, B_SCALAR, A_TIMES_BASEPOINT, DOUBLE_SCALAR_MULT_RESULT}; + use super::{A_SCALAR, A_TIMES_BASEPOINT, B_SCALAR, DOUBLE_SCALAR_MULT_RESULT}; /// Test double_scalar_mul_vartime vs ed25519.py #[test] fn double_scalar_mul_basepoint_vs_ed25519py() { let A = A_TIMES_BASEPOINT.decompress().unwrap(); - let result = EdwardsPoint::vartime_double_scalar_mul_basepoint(&A_SCALAR, &A, &B_SCALAR); + let result = + EdwardsPoint::vartime_double_scalar_mul_basepoint(&A_SCALAR, &A, &B_SCALAR); assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT); } #[test] + #[cfg(feature = "alloc")] fn multiscalar_mul_vs_ed25519py() { let A = A_TIMES_BASEPOINT.decompress().unwrap(); let result = EdwardsPoint::vartime_multiscalar_mul( &[A_SCALAR, B_SCALAR], - &[A, constants::ED25519_BASEPOINT_POINT] + &[A, constants::ED25519_BASEPOINT_POINT], ); assert_eq!(result.compress(), DOUBLE_SCALAR_MULT_RESULT); } #[test] + #[cfg(feature = "alloc")] fn multiscalar_mul_vartime_vs_consttime() { let A = A_TIMES_BASEPOINT.decompress().unwrap(); let result_vartime = EdwardsPoint::vartime_multiscalar_mul( &[A_SCALAR, B_SCALAR], - &[A, constants::ED25519_BASEPOINT_POINT] + &[A, constants::ED25519_BASEPOINT_POINT], ); let result_consttime = EdwardsPoint::multiscalar_mul( &[A_SCALAR, B_SCALAR], - &[A, constants::ED25519_BASEPOINT_POINT] + &[A, constants::ED25519_BASEPOINT_POINT], ); assert_eq!(result_vartime.compress(), result_consttime.compress()); @@ -1752,6 +2210,7 @@ mod test { // https://github.com/signalapp/libsignal-protocol-c/ // //////////////////////////////////////////////////////////// + #[cfg(all(feature = "alloc", feature = "digest"))] fn test_vectors() -> Vec> { vec![ vec![ @@ -1798,12 +2257,14 @@ mod test { } #[test] + #[allow(deprecated)] + #[cfg(all(feature = "alloc", feature = "digest"))] fn elligator_signal_test_vectors() { for vector in test_vectors().iter() { let input = hex::decode(vector[0]).unwrap(); let output = hex::decode(vector[1]).unwrap(); - let point = EdwardsPoint::hash_from_bytes::(&input); + let point = EdwardsPoint::nonspec_map_to_curve::(&input); assert_eq!(point.compress().to_bytes(), output[..]); } } diff --git a/src/field.rs b/curve25519-dalek/src/field.rs similarity index 85% rename from src/field.rs rename to curve25519-dalek/src/field.rs index 16d5d03f9..44faa8db8 100644 --- a/src/field.rs +++ b/curve25519-dalek/src/field.rs @@ -23,66 +23,70 @@ //! Field operations defined in terms of other field operations, such as //! field inversion or square roots, are defined here. -use core::cmp::{Eq, PartialEq}; +#[allow(unused_qualifications)] + +use cfg_if::cfg_if; -use subtle::ConditionallySelectable; -use subtle::ConditionallyNegatable; use subtle::Choice; +use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; -use constants; -use backend; - -#[cfg(feature = "fiat_u32_backend")] -pub use backend::serial::fiat_u32::field::*; -#[cfg(feature = "fiat_u64_backend")] -pub use backend::serial::fiat_u64::field::*; -/// A `FieldElement` represents an element of the field -/// \\( \mathbb Z / (2\^{255} - 19)\\). -/// -/// The `FieldElement` type is an alias for one of the platform-specific -/// implementations. -/// Using formally-verified field arithmetic from fiat-crypto -#[cfg(feature = "fiat_u32_backend")] -pub type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; -#[cfg(feature = "fiat_u64_backend")] -pub type FieldElement = backend::serial::fiat_u64::field::FieldElement51; - -#[cfg(feature = "u64_backend")] -pub use backend::serial::u64::field::*; -/// A `FieldElement` represents an element of the field -/// \\( \mathbb Z / (2\^{255} - 19)\\). -/// -/// The `FieldElement` type is an alias for one of the platform-specific -/// implementations. -#[cfg(feature = "u64_backend")] -pub type FieldElement = backend::serial::u64::field::FieldElement51; - -#[cfg(feature = "u32_backend")] -pub use backend::serial::u32::field::*; -/// A `FieldElement` represents an element of the field -/// \\( \mathbb Z / (2\^{255} - 19)\\). -/// -/// The `FieldElement` type is an alias for one of the platform-specific -/// implementations. -#[cfg(feature = "u32_backend")] -pub type FieldElement = backend::serial::u32::field::FieldElement2625; - -#[cfg(feature = "u32e_backend")] -pub use backend::serial::u32e::field::*; -/// A `FieldElement` represents an element of the field -/// \\( \mathbb Z / (2\^{255} - 19)\\). -/// -/// The `FieldElement` type is an alias for one of the platform-specific -/// implementations. -#[cfg(feature = "u32e_backend")] -pub type FieldElement = backend::serial::u32e::field::Engine25519; +use crate::backend; +use crate::constants; + +cfg_if! { + if #[cfg(curve25519_dalek_backend = "u32e_backend")]{ + pub use backend::serial::u32e::field::*; + /// A `FieldElement` represents an element of the field + /// \\( \mathbb Z / (2\^{255} - 19)\\). + /// + /// The `FieldElement` type is an alias for one of the platform-specific + /// implementations. + pub type FieldElement = backend::serial::u32e::field::Engine25519; + + } else if #[cfg(curve25519_dalek_backend = "fiat")] { + /// A `FieldElement` represents an element of the field + /// \\( \mathbb Z / (2\^{255} - 19)\\). + /// + /// The `FieldElement` type is an alias for one of the platform-specific + /// implementations. + /// + /// Using formally-verified field arithmetic from fiat-crypto. + #[cfg(curve25519_dalek_bits = "32")] + pub(crate) type FieldElement = backend::serial::fiat_u32::field::FieldElement2625; + + /// A `FieldElement` represents an element of the field + /// \\( \mathbb Z / (2\^{255} - 19)\\). + /// + /// The `FieldElement` type is an alias for one of the platform-specific + /// implementations. + /// + /// Using formally-verified field arithmetic from fiat-crypto. + #[cfg(curve25519_dalek_bits = "64")] + pub(crate) type FieldElement = backend::serial::fiat_u64::field::FieldElement51; + } else if #[cfg(curve25519_dalek_bits = "64")] { + /// A `FieldElement` represents an element of the field + /// \\( \mathbb Z / (2\^{255} - 19)\\). + /// + /// The `FieldElement` type is an alias for one of the platform-specific + /// implementations. + pub(crate) type FieldElement = backend::serial::u64::field::FieldElement51; + } else { + /// A `FieldElement` represents an element of the field + /// \\( \mathbb Z / (2\^{255} - 19)\\). + /// + /// The `FieldElement` type is an alias for one of the platform-specific + /// implementations. + pub(crate) type FieldElement = backend::serial::u32::field::FieldElement2625; + } +} impl Eq for FieldElement {} impl PartialEq for FieldElement { fn eq(&self, other: &FieldElement) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } @@ -91,7 +95,7 @@ impl ConstantTimeEq for FieldElement { /// internal representation is not canonical, the field elements /// are normalized to wire format before comparison. fn ct_eq(&self, other: &FieldElement) -> Choice { - self.to_bytes().ct_eq(&other.to_bytes()) + self.as_bytes().ct_eq(&other.as_bytes()) } } @@ -103,8 +107,8 @@ impl FieldElement { /// # Return /// /// If negative, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_negative(&self) -> Choice { - let bytes = self.to_bytes(); + pub(crate) fn is_negative(&self) -> Choice { + let bytes = self.as_bytes(); (bytes[0] & 1).into() } @@ -113,15 +117,16 @@ impl FieldElement { /// # Return /// /// If zero, return `Choice(1)`. Otherwise, return `Choice(0)`. - pub fn is_zero(&self) -> Choice { + pub(crate) fn is_zero(&self) -> Choice { let zero = [0u8; 32]; - let bytes = self.to_bytes(); + let bytes = self.as_bytes(); bytes.ct_eq(&zero) } /// Compute (self^(2^250-1), self^11), used as a helper function /// within invert() and pow22523(). + #[rustfmt::skip] // keep alignment of explanatory comments fn pow22501(&self) -> (FieldElement, FieldElement) { // Instead of managing which temporary variables are used // for what, we define as many as we need and leave stack @@ -158,30 +163,31 @@ impl FieldElement { (t19, t3) } - /// Given a slice of public `FieldElements`, replace each with its inverse. + /// Given a slice of pub(crate)lic `FieldElements`, replace each with its inverse. /// - /// All input `FieldElements` **MUST** be nonzero. + /// When an input `FieldElement` is zero, its value is unchanged. #[cfg(feature = "alloc")] - pub fn batch_invert(inputs: &mut [FieldElement]) { + pub(crate) fn batch_invert(inputs: &mut [FieldElement]) { // Montgomery’s Trick and Fast Implementation of Masked AES // Genelle, Prouff and Quisquater // Section 3.2 let n = inputs.len(); - let mut scratch = vec![FieldElement::one(); n]; + let mut scratch = vec![FieldElement::ONE; n]; // Keep an accumulator of all of the previous products - let mut acc = FieldElement::one(); + let mut acc = FieldElement::ONE; // Pass through the input vector, recording the previous // products in the scratch space for (input, scratch) in inputs.iter().zip(scratch.iter_mut()) { *scratch = acc; - acc = &acc * input; + // acc <- acc * input, but skipping zeros (constant-time) + acc.conditional_assign(&(&acc * input), !input.is_zero()); } - // acc is nonzero iff all inputs are nonzero - assert_eq!(acc.is_zero().unwrap_u8(), 0); + // acc is nonzero because we skipped zeros in inputs + assert!(bool::from(!acc.is_zero())); // Compute the inverse of all products acc = acc.invert(); @@ -190,8 +196,11 @@ impl FieldElement { // in place for (input, scratch) in inputs.iter_mut().rev().zip(scratch.into_iter().rev()) { let tmp = &acc * input; - *input = &acc * &scratch; - acc = tmp; + // input <- acc * scratch, then acc <- tmp + // Again, we skip zeros in a constant-time way + let nz = !input.is_zero(); + input.conditional_assign(&(&acc * &scratch), nz); + acc.conditional_assign(&tmp, nz); } } @@ -201,7 +210,9 @@ impl FieldElement { /// x^(p-2)x = x^(p-1) = 1 (mod p). /// /// This function returns zero on input zero. - pub fn invert(&self) -> FieldElement { + #[rustfmt::skip] // keep alignment of explanatory comments + #[allow(clippy::let_and_return)] + pub(crate) fn invert(&self) -> FieldElement { // The bits of p-2 = 2^255 -19 -2 are 11010111111...11. // // nonzero bits of exponent @@ -213,6 +224,8 @@ impl FieldElement { } /// Raise this field element to the power (p-5)/8 = 2^252 -3. + #[rustfmt::skip] // keep alignment of explanatory comments + #[allow(clippy::let_and_return)] fn pow_p58(&self) -> FieldElement { // The bits of (p-5)/8 are 101111.....11. // @@ -236,7 +249,7 @@ impl FieldElement { /// - `(Choice(0), zero) ` if `v` is zero and `u` is nonzero; /// - `(Choice(0), +sqrt(i*u/v))` if `u/v` is nonsquare (so `i*u/v` is square). /// - pub fn sqrt_ratio_i(u: &FieldElement, v: &FieldElement) -> (Choice, FieldElement) { + pub(crate) fn sqrt_ratio_i(u: &FieldElement, v: &FieldElement) -> (Choice, FieldElement) { // Using the same trick as in ed25519 decoding, we merge the // inversion, the square root, and the square test as follows. // @@ -261,16 +274,16 @@ impl FieldElement { // // If v is zero, r is also zero. - let v3 = &v.square() * v; + let v3 = &v.square() * v; let v7 = &v3.square() * v; let mut r = &(u * &v3) * &(u * &v7).pow_p58(); let check = v * &r.square(); let i = &constants::SQRT_M1; - let correct_sign_sqrt = check.ct_eq( u); - let flipped_sign_sqrt = check.ct_eq( &(-u)); - let flipped_sign_sqrt_i = check.ct_eq(&(&(-u)*i)); + let correct_sign_sqrt = check.ct_eq(u); + let flipped_sign_sqrt = check.ct_eq(&(-u)); + let flipped_sign_sqrt_i = check.ct_eq(&(&(-u) * i)); let r_prime = &constants::SQRT_M1 * &r; r.conditional_assign(&r_prime, flipped_sign_sqrt | flipped_sign_sqrt_i); @@ -296,8 +309,8 @@ impl FieldElement { /// - `(Choice(0), zero) ` if `self` is zero; /// - `(Choice(0), +sqrt(i/self)) ` if `self` is a nonzero nonsquare; /// - pub fn invsqrt(&self) -> (Choice, FieldElement) { - FieldElement::sqrt_ratio_i(&FieldElement::one(), self) + pub(crate) fn invsqrt(&self) -> (Choice, FieldElement) { + FieldElement::sqrt_ratio_i(&FieldElement::ONE, self) } } @@ -306,38 +319,37 @@ extern crate rand; #[cfg(test)] mod test { - use field::*; - use subtle::ConditionallyNegatable; + use crate::field::*; /// Random element a of GF(2^255-19), from Sage /// a = 1070314506888354081329385823235218444233221\ /// 2228051251926706380353716438957572 - static A_BYTES: [u8; 32] = - [ 0x04, 0xfe, 0xdf, 0x98, 0xa7, 0xfa, 0x0a, 0x68, - 0x84, 0x92, 0xbd, 0x59, 0x08, 0x07, 0xa7, 0x03, - 0x9e, 0xd1, 0xf6, 0xf2, 0xe1, 0xd9, 0xe2, 0xa4, - 0xa4, 0x51, 0x47, 0x36, 0xf3, 0xc3, 0xa9, 0x17]; + static A_BYTES: [u8; 32] = [ + 0x04, 0xfe, 0xdf, 0x98, 0xa7, 0xfa, 0x0a, 0x68, 0x84, 0x92, 0xbd, 0x59, 0x08, 0x07, 0xa7, + 0x03, 0x9e, 0xd1, 0xf6, 0xf2, 0xe1, 0xd9, 0xe2, 0xa4, 0xa4, 0x51, 0x47, 0x36, 0xf3, 0xc3, + 0xa9, 0x17, + ]; /// Byte representation of a**2 - static ASQ_BYTES: [u8; 32] = - [ 0x75, 0x97, 0x24, 0x9e, 0xe6, 0x06, 0xfe, 0xab, - 0x24, 0x04, 0x56, 0x68, 0x07, 0x91, 0x2d, 0x5d, - 0x0b, 0x0f, 0x3f, 0x1c, 0xb2, 0x6e, 0xf2, 0xe2, - 0x63, 0x9c, 0x12, 0xba, 0x73, 0x0b, 0xe3, 0x62]; + static ASQ_BYTES: [u8; 32] = [ + 0x75, 0x97, 0x24, 0x9e, 0xe6, 0x06, 0xfe, 0xab, 0x24, 0x04, 0x56, 0x68, 0x07, 0x91, 0x2d, + 0x5d, 0x0b, 0x0f, 0x3f, 0x1c, 0xb2, 0x6e, 0xf2, 0xe2, 0x63, 0x9c, 0x12, 0xba, 0x73, 0x0b, + 0xe3, 0x62, + ]; /// Byte representation of 1/a - static AINV_BYTES: [u8; 32] = - [0x96, 0x1b, 0xcd, 0x8d, 0x4d, 0x5e, 0xa2, 0x3a, - 0xe9, 0x36, 0x37, 0x93, 0xdb, 0x7b, 0x4d, 0x70, - 0xb8, 0x0d, 0xc0, 0x55, 0xd0, 0x4c, 0x1d, 0x7b, - 0x90, 0x71, 0xd8, 0xe9, 0xb6, 0x18, 0xe6, 0x30]; + static AINV_BYTES: [u8; 32] = [ + 0x96, 0x1b, 0xcd, 0x8d, 0x4d, 0x5e, 0xa2, 0x3a, 0xe9, 0x36, 0x37, 0x93, 0xdb, 0x7b, 0x4d, + 0x70, 0xb8, 0x0d, 0xc0, 0x55, 0xd0, 0x4c, 0x1d, 0x7b, 0x90, 0x71, 0xd8, 0xe9, 0xb6, 0x18, + 0xe6, 0x30, + ]; /// Byte representation of a^((p-5)/8) - static AP58_BYTES: [u8; 32] = - [0x6a, 0x4f, 0x24, 0x89, 0x1f, 0x57, 0x60, 0x36, - 0xd0, 0xbe, 0x12, 0x3c, 0x8f, 0xf5, 0xb1, 0x59, - 0xe0, 0xf0, 0xb8, 0x1b, 0x20, 0xd2, 0xb5, 0x1f, - 0x15, 0x21, 0xf9, 0xe3, 0xe1, 0x61, 0x21, 0x55]; + static AP58_BYTES: [u8; 32] = [ + 0x6a, 0x4f, 0x24, 0x89, 0x1f, 0x57, 0x60, 0x36, 0xd0, 0xbe, 0x12, 0x3c, 0x8f, 0xf5, 0xb1, + 0x59, 0xe0, 0xf0, 0xb8, 0x1b, 0x20, 0xd2, 0xb5, 0x1f, 0x15, 0x21, 0xf9, 0xe3, 0xe1, 0x61, + 0x21, 0x55, + ]; #[test] fn a_mul_a_vs_a_squared_constant() { @@ -357,82 +369,84 @@ mod test { fn a_square2_vs_a_squared_constant() { let a = FieldElement::from_bytes(&A_BYTES); let asq = FieldElement::from_bytes(&ASQ_BYTES); - assert_eq!(a.square2(), &asq+&asq); + assert_eq!(a.square2(), &asq + &asq); } #[test] fn a_invert_vs_inverse_of_a_constant() { - let a = FieldElement::from_bytes(&A_BYTES); + let a = FieldElement::from_bytes(&A_BYTES); let ainv = FieldElement::from_bytes(&AINV_BYTES); let should_be_inverse = a.invert(); assert_eq!(ainv, should_be_inverse); - assert_eq!(FieldElement::one(), &a * &should_be_inverse); + assert_eq!(FieldElement::ONE, &a * &should_be_inverse); } #[test] + #[cfg(feature = "alloc")] fn batch_invert_a_matches_nonbatched() { - let a = FieldElement::from_bytes(&A_BYTES); + let a = FieldElement::from_bytes(&A_BYTES); let ap58 = FieldElement::from_bytes(&AP58_BYTES); - let asq = FieldElement::from_bytes(&ASQ_BYTES); + let asq = FieldElement::from_bytes(&ASQ_BYTES); let ainv = FieldElement::from_bytes(&AINV_BYTES); - let a2 = &a + &a; - let a_list = vec![a, ap58, asq, ainv, a2]; + let a0 = &a - &a; + let a2 = &a + &a; + let a_list = vec![a, ap58, asq, ainv, a0, a2]; let mut ainv_list = a_list.clone(); FieldElement::batch_invert(&mut ainv_list[..]); - for i in 0..5 { + for i in 0..6 { assert_eq!(a_list[i].invert(), ainv_list[i]); } } #[test] fn sqrt_ratio_behavior() { - let zero = FieldElement::zero(); - let one = FieldElement::one(); + let zero = FieldElement::ZERO; + let one = FieldElement::ONE; let i = constants::SQRT_M1; let two = &one + &one; // 2 is nonsquare mod p. let four = &two + &two; // 4 is square mod p. // 0/0 should return (1, 0) since u is 0 let (choice, sqrt) = FieldElement::sqrt_ratio_i(&zero, &zero); - assert_eq!(choice.unwrap_u8(), 1); + assert!(bool::from(choice)); assert_eq!(sqrt, zero); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); // 1/0 should return (0, 0) since v is 0, u is nonzero let (choice, sqrt) = FieldElement::sqrt_ratio_i(&one, &zero); - assert_eq!(choice.unwrap_u8(), 0); + assert!(bool::from(!choice)); assert_eq!(sqrt, zero); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); // 2/1 is nonsquare, so we expect (0, sqrt(i*2)) let (choice, sqrt) = FieldElement::sqrt_ratio_i(&two, &one); - assert_eq!(choice.unwrap_u8(), 0); + assert!(bool::from(!choice)); assert_eq!(sqrt.square(), &two * &i); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); // 4/1 is square, so we expect (1, sqrt(4)) let (choice, sqrt) = FieldElement::sqrt_ratio_i(&four, &one); - assert_eq!(choice.unwrap_u8(), 1); + assert!(bool::from(choice)); assert_eq!(sqrt.square(), four); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); // 1/4 is square, so we expect (1, 1/sqrt(4)) let (choice, sqrt) = FieldElement::sqrt_ratio_i(&one, &four); - assert_eq!(choice.unwrap_u8(), 1); + assert!(bool::from(choice)); assert_eq!(&sqrt.square() * &four, one); - assert_eq!(sqrt.is_negative().unwrap_u8(), 0); + assert!(bool::from(!sqrt.is_negative())); } #[test] fn a_p58_vs_ap58_constant() { - let a = FieldElement::from_bytes(&A_BYTES); + let a = FieldElement::from_bytes(&A_BYTES); let ap58 = FieldElement::from_bytes(&AP58_BYTES); assert_eq!(ap58, a.pow_p58()); } #[test] fn equality() { - let a = FieldElement::from_bytes(&A_BYTES); + let a = FieldElement::from_bytes(&A_BYTES); let ainv = FieldElement::from_bytes(&AINV_BYTES); assert!(a == a); assert!(a != ainv); @@ -440,25 +454,24 @@ mod test { /// Notice that the last element has the high bit set, which /// should be ignored - static B_BYTES: [u8;32] = - [113, 191, 169, 143, 91, 234, 121, 15, - 241, 131, 217, 36, 230, 101, 92, 234, - 8, 208, 170, 251, 97, 127, 70, 210, - 58, 23, 166, 87, 240, 169, 184, 178]; + static B_BYTES: [u8; 32] = [ + 113, 191, 169, 143, 91, 234, 121, 15, 241, 131, 217, 36, 230, 101, 92, 234, 8, 208, 170, + 251, 97, 127, 70, 210, 58, 23, 166, 87, 240, 169, 184, 178, + ]; #[test] fn from_bytes_highbit_is_ignored() { let mut cleared_bytes = B_BYTES; cleared_bytes[31] &= 127u8; - let with_highbit_set = FieldElement::from_bytes(&B_BYTES); + let with_highbit_set = FieldElement::from_bytes(&B_BYTES); let without_highbit_set = FieldElement::from_bytes(&cleared_bytes); assert_eq!(without_highbit_set, with_highbit_set); } #[test] fn conditional_negate() { - let one = FieldElement::one(); - let minus_one = FieldElement::minus_one(); + let one = FieldElement::ONE; + let minus_one = FieldElement::MINUS_ONE; let mut x = one; x.conditional_negate(Choice::from(1)); assert_eq!(x, minus_one); @@ -471,23 +484,29 @@ mod test { #[test] fn encoding_is_canonical() { // Encode 1 wrongly as 1 + (2^255 - 19) = 2^255 - 18 - let one_encoded_wrongly_bytes: [u8;32] = [0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]; + let one_encoded_wrongly_bytes: [u8; 32] = [ + 0xee, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, + ]; // Decode to a field element let one = FieldElement::from_bytes(&one_encoded_wrongly_bytes); // .. then check that the encoding is correct - let one_bytes = one.to_bytes(); + let one_bytes = one.as_bytes(); assert_eq!(one_bytes[0], 1); - for i in 1..32 { - assert_eq!(one_bytes[i], 0); + for byte in &one_bytes[1..] { + assert_eq!(*byte, 0); } } #[test] + #[cfg(feature = "alloc")] fn batch_invert_empty() { FieldElement::batch_invert(&mut []); } #[test] + #[cfg(curve25519_dalek_backend = "u32e_backend")] fn make_vectors() { // reminder to self: to create just this vector, run // cargo test field::test::make_vectors @@ -498,7 +517,7 @@ mod test { use self::rand::Rng; fn write_helper(file: &mut File, elem: FieldElement) { - let elem_bytes = elem.to_bytes(); + let elem_bytes = elem.as_bytes(); let _ = file.write(&elem_bytes); /* for i in 0..elem_bytes.len()/4 { @@ -575,8 +594,8 @@ mod test { // test vectors // 1 plus -1 = 0 -> this works overflow path - let a = FieldElement::one(); - let b = FieldElement::minus_one(); + let a = FieldElement::ONE; + let b = FieldElement::MINUS_ONE; let q = &a + &b; write_helper(&mut file, a); @@ -595,11 +614,11 @@ mod test { } fn ref_fact(n: usize) -> FieldElement { - let mut a = FieldElement::one(); - let mut result = FieldElement::one(); + let mut a = FieldElement::ONE; + let mut result = FieldElement::ONE; for _ in 0..n { result = &result * &a; - a = &a + &FieldElement::one(); + a = &a + &FieldElement::ONE; } result } @@ -633,10 +652,10 @@ mod test { write_test_header(&mut file, loading_address, &mcode, num_src_regs, reg_window, num_tests); // test vectors - let mut n = FieldElement::one(); + let mut n = FieldElement::ONE; for i in 1..6 { write_helper(&mut file, n); - n = &n + &FieldElement::one(); // mirror i's progression + n = &n + &FieldElement::ONE; // mirror i's progression let q = ref_fact(i); write_helper(&mut file, q); } @@ -668,10 +687,10 @@ mod test { let swap: FieldElement; let q: FieldElement; if i % 2 == 0 { - swap = FieldElement::zero(); + swap = FieldElement::ZERO; q = a; } else { - swap = FieldElement::one(); + swap = FieldElement::ONE; q = b; } write_helper(&mut file, a); @@ -698,16 +717,16 @@ mod test { write_test_header(&mut file, loading_address, &mcode, num_src_regs, reg_window, num_tests); // 1: 1*1 - simple case - let a = FieldElement::one(); - let b = FieldElement::one(); + let a = FieldElement::ONE; + let b = FieldElement::ONE; let q = &a * &b; write_helper(&mut file, a); write_helper(&mut file, b); write_helper(&mut file, q); // 2: 1*-1 - simple case - let a = FieldElement::one(); - let b = FieldElement::minus_one(); + let a = FieldElement::ONE; + let b = FieldElement::MINUS_ONE; let q = &a * &b; write_helper(&mut file, a); write_helper(&mut file, b); @@ -719,7 +738,7 @@ mod test { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7f,]); - let b = FieldElement::one(); + let b = FieldElement::ONE; let q = &a * &b; write_helper(&mut file, a); write_helper(&mut file, b); @@ -943,7 +962,7 @@ mod test { fn test_diff_add_and_double(mut file: &mut File) { - use montgomery::ProjectivePoint; + use crate::montgomery::ProjectivePoint; // test cswap. three input registers: (r0, r1) to swap, (r2) to control swap, one output register (r31). let num_src_regs = 5; @@ -1052,7 +1071,7 @@ mod test { fin // finish execution ); write_test_header(&mut file, loading_address, &mcode, num_src_regs, reg_window, num_tests); - use montgomery::differential_add_and_double; + use crate::montgomery::differential_add_and_double; // test vectors for _ in 0..8 { @@ -1076,7 +1095,7 @@ mod test { } fn test_scalar_mul(mut file: &mut File) { - use montgomery::ProjectivePoint; + use crate::montgomery::ProjectivePoint; // test cswap. three input registers: (r0, r1) to swap, (r2) to control swap, one output register (r31). let num_src_regs = 7; @@ -1239,9 +1258,9 @@ mod test { write_test_header(&mut file, loading_address, &mcode, num_src_regs, reg_window, num_tests); - use scalar::Scalar; - use montgomery::MontgomeryPoint; - use montgomery::differential_add_and_double; + use crate::scalar::Scalar; + use crate::montgomery::MontgomeryPoint; + use crate::montgomery::differential_add_and_double; fn clamp_scalar(mut scalar: [u8; 32]) -> Scalar { scalar[0] &= 248; @@ -1256,12 +1275,12 @@ mod test { // Algorithm 8 of Costello-Smith 2017 let affine_u = FieldElement::from_bytes(&mp.0); let mut x0 = ProjectivePoint { - U: FieldElement::one(), - W: FieldElement::zero(), + U: FieldElement::ONE, + W: FieldElement::ZERO, }; let mut x1 = ProjectivePoint { U: affine_u, - W: FieldElement::one(), + W: FieldElement::ONE, }; // test vectors input to test routine diff --git a/curve25519-dalek/src/lib.rs b/curve25519-dalek/src/lib.rs new file mode 100644 index 000000000..a446c53d1 --- /dev/null +++ b/curve25519-dalek/src/lib.rs @@ -0,0 +1,121 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +#![no_std] +#![cfg_attr( + all( + curve25519_dalek_backend = "simd", + nightly, + any(target_arch = "x86", target_arch = "x86_64") + ), + feature(stdarch_x86_avx512) +)] +#![cfg_attr( + all(curve25519_dalek_backend = "simd", nightly), + feature(avx512_target_feature) +)] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] +#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] +//------------------------------------------------------------------------ +// Documentation: +//------------------------------------------------------------------------ +#![doc( + html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png" +)] +#![doc = include_str!("../README.md")] +//------------------------------------------------------------------------ +// Linting: +//------------------------------------------------------------------------ +#![cfg_attr(allow_unused_unsafe, allow(unused_unsafe))] +#![warn( + clippy::unwrap_used, + missing_docs, + rust_2018_idioms, + unused_lifetimes, + unused_qualifications +)] +// needed for engine25519-as. +#![recursion_limit = "512"] + +//------------------------------------------------------------------------ +// External dependencies: +//------------------------------------------------------------------------ + +#[cfg(feature = "alloc")] +#[allow(unused_imports)] +#[macro_use] +extern crate alloc; + +// TODO: move std-dependent tests to `tests/` +#[cfg(test)] +#[macro_use] +extern crate std; + +#[cfg(feature = "digest")] +pub use digest; + +// Internal macros. Must come first! +#[macro_use] +pub(crate) mod macros; + +//To consider upstreaming, we likely can't do this. Consider the "panic_on_sw_eval" feature +#[allow(unused_imports)] +#[cfg(curve25519_dalek_backend = "u32e_backend")] +#[macro_use] +extern crate engine25519_as; + +//------------------------------------------------------------------------ +// curve25519-dalek public modules +//------------------------------------------------------------------------ + +// Scalar arithmetic mod l = 2^252 + ..., the order of the Ristretto group +pub mod scalar; + +// Point operations on the Montgomery form of Curve25519 +pub mod montgomery; + +// Point operations on the Edwards form of Curve25519 +pub mod edwards; + +// Group operations on the Ristretto group +pub mod ristretto; + +// Useful constants, like the Ed25519 basepoint +pub mod constants; + +// External (and internal) traits. +pub mod traits; + +//------------------------------------------------------------------------ +// curve25519-dalek internal modules +//------------------------------------------------------------------------ + +// Finite field arithmetic mod p = 2^255 - 19 +pub(crate) mod field; + +// Arithmetic backends (using u32, u64, etc) live here +#[cfg(docsrs)] +pub mod backend; +#[cfg(all(not(docsrs), not(curve25519_dalek_backend = "u32e_backend")))] +pub(crate) mod backend; +#[cfg(curve25519_dalek_backend = "u32e_backend")] +pub mod backend; + +// Generic code for window lookups +pub(crate) mod window; + +pub use crate::{ + edwards::EdwardsPoint, montgomery::MontgomeryPoint, ristretto::RistrettoPoint, scalar::Scalar, +}; + +// Build time diagnostics for validation +#[cfg(curve25519_dalek_diagnostics = "build")] +mod diagnostics; diff --git a/src/macros.rs b/curve25519-dalek/src/macros.rs similarity index 98% rename from src/macros.rs rename to curve25519-dalek/src/macros.rs index 84a2ce128..a0f0345a2 100644 --- a/src/macros.rs +++ b/curve25519-dalek/src/macros.rs @@ -34,7 +34,7 @@ macro_rules! define_add_variants { &self + &rhs } } - } + }; } /// Define non-borrow variants of `AddAssign`. @@ -45,7 +45,7 @@ macro_rules! define_add_assign_variants { *self += &rhs; } } - } + }; } /// Define borrow and non-borrow variants of `Sub`. @@ -71,7 +71,7 @@ macro_rules! define_sub_variants { &self - &rhs } } - } + }; } /// Define non-borrow variants of `SubAssign`. @@ -82,7 +82,7 @@ macro_rules! define_sub_assign_variants { *self -= &rhs; } } - } + }; } /// Define borrow and non-borrow variants of `Mul`. @@ -108,7 +108,7 @@ macro_rules! define_mul_variants { &self * &rhs } } - } + }; } /// Define non-borrow variants of `MulAssign`. @@ -119,6 +119,5 @@ macro_rules! define_mul_assign_variants { *self *= &rhs; } } - } + }; } - diff --git a/curve25519-dalek/src/montgomery.rs b/curve25519-dalek/src/montgomery.rs new file mode 100644 index 000000000..c78bea385 --- /dev/null +++ b/curve25519-dalek/src/montgomery.rs @@ -0,0 +1,1237 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Scalar multiplication on the Montgomery form of Curve25519. +//! +//! To avoid notational confusion with the Edwards code, we use +//! variables \\( u, v \\) for the Montgomery curve, so that “Montgomery +//! \\(u\\)” here corresponds to “Montgomery \\(x\\)” elsewhere. +//! +//! Montgomery arithmetic works not on the curve itself, but on the +//! \\(u\\)-line, which discards sign information and unifies the curve +//! and its quadratic twist. See [_Montgomery curves and their +//! arithmetic_][costello-smith] by Costello and Smith for more details. +//! +//! The `MontgomeryPoint` struct contains the affine \\(u\\)-coordinate +//! \\(u\_0(P)\\) of a point \\(P\\) on either the curve or the twist. +//! Here the map \\(u\_0 : \mathcal M \rightarrow \mathbb F\_p \\) is +//! defined by \\(u\_0((u,v)) = u\\); \\(u\_0(\mathcal O) = 0\\). See +//! section 5.4 of Costello-Smith for more details. +//! +//! # Scalar Multiplication +//! +//! Scalar multiplication on `MontgomeryPoint`s is provided by the `*` +//! operator, which implements the Montgomery ladder. +//! +//! # Edwards Conversion +//! +//! The \\(2\\)-to-\\(1\\) map from the Edwards model to the Montgomery +//! \\(u\\)-line is provided by `EdwardsPoint::to_montgomery()`. +//! +//! To lift a `MontgomeryPoint` to an `EdwardsPoint`, use +//! `MontgomeryPoint::to_edwards()`, which takes a sign parameter. +//! This function rejects `MontgomeryPoints` which correspond to points +//! on the twist. +//! +//! [costello-smith]: https://eprint.iacr.org/2017/212.pdf + +// We allow non snake_case names because coordinates in projective space are +// traditionally denoted by the capitalisation of their respective +// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my +// affine and projective cakes and eat both of them too. +#![allow(non_snake_case)] + +use core::{ + hash::{Hash, Hasher}, + ops::{Mul, MulAssign}, +}; + +#[cfg(not(curve25519_dalek_backend = "u32e_backend"))] +use crate::constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; +#[cfg(curve25519_dalek_backend = "u32e_backend")] +use crate::constants::{MONTGOMERY_A, MONTGOMERY_A_NEG}; // eliminate constants absorbed into the microcode engine + +use crate::edwards::{CompressedEdwardsY, EdwardsPoint}; +use crate::field::FieldElement; +use crate::scalar::{clamp_integer, Scalar}; + +use crate::traits::Identity; + +use subtle::Choice; +use subtle::ConstantTimeEq; +use subtle::{ConditionallyNegatable, ConditionallySelectable}; + +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + +/// Holds the \\(u\\)-coordinate of a point on the Montgomery form of +/// Curve25519 or its twist. +#[derive(Copy, Clone, Debug, Default)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct MontgomeryPoint(pub [u8; 32]); + +/// Equality of `MontgomeryPoint`s is defined mod p. +impl ConstantTimeEq for MontgomeryPoint { + fn ct_eq(&self, other: &MontgomeryPoint) -> Choice { + let self_fe = FieldElement::from_bytes(&self.0); + let other_fe = FieldElement::from_bytes(&other.0); + + self_fe.ct_eq(&other_fe) + } +} + +impl PartialEq for MontgomeryPoint { + fn eq(&self, other: &MontgomeryPoint) -> bool { + self.ct_eq(other).into() + } +} + +impl Eq for MontgomeryPoint {} + +// Equal MontgomeryPoints must hash to the same value. So we have to get them into a canonical +// encoding first +impl Hash for MontgomeryPoint { + fn hash(&self, state: &mut H) { + // Do a round trip through a `FieldElement`. `as_bytes` is guaranteed to give a canonical + // 32-byte encoding + let canonical_bytes = FieldElement::from_bytes(&self.0).as_bytes(); + canonical_bytes.hash(state); + } +} + +impl Identity for MontgomeryPoint { + /// Return the group identity element, which has order 4. + fn identity() -> MontgomeryPoint { + MontgomeryPoint([0u8; 32]) + } +} + +#[cfg(feature = "zeroize")] +impl Zeroize for MontgomeryPoint { + fn zeroize(&mut self) { + self.0.zeroize(); + } +} + +impl MontgomeryPoint { + /// Fixed-base scalar multiplication (i.e. multiplication by the base point). + pub fn mul_base(scalar: &Scalar) -> Self { + EdwardsPoint::mul_base(scalar).to_montgomery() + } + + /// Multiply this point by `clamp_integer(bytes)`. For a description of clamping, see + /// [`clamp_integer`]. + pub fn mul_clamped(self, bytes: [u8; 32]) -> Self { + // We have to construct a Scalar that is not reduced mod l, which breaks scalar invariant + // #2. But #2 is not necessary for correctness of variable-base multiplication. All that + // needs to hold is invariant #1, i.e., the scalar is less than 2^255. This is guaranteed + // by clamping. + // Further, we don't do any reduction or arithmetic with this clamped value, so there's no + // issues arising from the fact that the curve point is not necessarily in the prime-order + // subgroup. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + s * self + } + + /// Multiply the basepoint by `clamp_integer(bytes)`. For a description of clamping, see + /// [`clamp_integer`]. + pub fn mul_base_clamped(bytes: [u8; 32]) -> Self { + // See reasoning in Self::mul_clamped why it is OK to make an unreduced Scalar here. We + // note that fixed-base multiplication is also defined for all values of `bytes` less than + // 2^255. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + Self::mul_base(&s) + } + + //TODO: understand _clamped multiplication_ and ensure we are doing it correctly and + //compatibily as this has changed since our fork. + /// Given `self` \\( = u\_0(P) \\), and a big-endian bit representation of an integer + /// \\(n\\), return \\( u\_0(\[n\]P) \\). This is constant time in the length of `bits`. + /// + /// **NOTE:** You probably do not want to use this function. Almost every protocol built on + /// Curve25519 uses _clamped multiplication_, explained + /// [here](https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/). + /// When in doubt, use [`Self::mul_clamped`]. + pub fn mul_bits_be(&self, bits: impl Iterator) -> MontgomeryPoint { + // Algorithm 8 of Costello-Smith 2017 + let affine_u = FieldElement::from_bytes(&self.0); + let mut x0 = ProjectivePoint::identity(); + let mut x1 = ProjectivePoint { + U: affine_u, + W: FieldElement::ONE, + }; + + // Go through the bits from most to least significant, using a sliding window of 2 + let mut prev_bit = false; + for cur_bit in bits { + let choice: u8 = (prev_bit ^ cur_bit) as u8; + + debug_assert!(choice == 0 || choice == 1); + + ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into()); + differential_add_and_double(&mut x0, &mut x1, &affine_u); + + prev_bit = cur_bit; + } + // The final value of prev_bit above is scalar.bits()[0], i.e., the LSB of scalar + ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(prev_bit as u8)); + // Don't leave the bit in the stack + #[cfg(feature = "zeroize")] + prev_bit.zeroize(); + + x0.as_affine() + } + + /// View this `MontgomeryPoint` as an array of bytes. + pub const fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + + /// Convert this `MontgomeryPoint` to an array of bytes. + pub const fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// Attempt to convert to an `EdwardsPoint`, using the supplied + /// choice of sign for the `EdwardsPoint`. + /// + /// # Inputs + /// + /// * `sign`: a `u8` donating the desired sign of the resulting + /// `EdwardsPoint`. `0` denotes positive and `1` negative. + /// + /// # Return + /// + /// * `Some(EdwardsPoint)` if `self` is the \\(u\\)-coordinate of a + /// point on (the Montgomery form of) Curve25519; + /// + /// * `None` if `self` is the \\(u\\)-coordinate of a point on the + /// twist of (the Montgomery form of) Curve25519; + /// + pub fn to_edwards(&self, sign: u8) -> Option { + // To decompress the Montgomery u coordinate to an + // `EdwardsPoint`, we apply the birational map to obtain the + // Edwards y coordinate, then do Edwards decompression. + // + // The birational map is y = (u-1)/(u+1). + // + // The exceptional points are the zeros of the denominator, + // i.e., u = -1. + // + // But when u = -1, v^2 = u*(u^2+486662*u+1) = 486660. + // + // Since this is nonsquare mod p, u = -1 corresponds to a point + // on the twist, not the curve, so we can reject it early. + + let u = FieldElement::from_bytes(&self.0); + + if u == FieldElement::MINUS_ONE { + return None; + } + + let one = FieldElement::ONE; + + let y = &(&u - &one) * &(&u + &one).invert(); + + let mut y_bytes = y.as_bytes(); + y_bytes[31] ^= sign << 7; + + CompressedEdwardsY(y_bytes).decompress() + } +} + +/// Perform the Elligator2 mapping to a Montgomery point. +/// +/// See +// +// TODO Determine how much of the hash-to-group API should be exposed after the CFRG +// draft gets into a more polished/accepted state. +#[allow(unused)] +pub(crate) fn elligator_encode(r_0: &FieldElement) -> MontgomeryPoint { + let one = FieldElement::ONE; + let d_1 = &one + &r_0.square2(); /* 2r^2 */ + + let d = &MONTGOMERY_A_NEG * &(d_1.invert()); /* A/(1+2r^2) */ + + let d_sq = &d.square(); + let au = &MONTGOMERY_A * &d; + + let inner = &(d_sq + &au) + &one; + let eps = &d * &inner; /* eps = d^3 + Ad^2 + d */ + + let (eps_is_sq, _eps) = FieldElement::sqrt_ratio_i(&eps, &one); + + let zero = FieldElement::ZERO; + let Atemp = FieldElement::conditional_select(&MONTGOMERY_A, &zero, eps_is_sq); /* 0, or A if nonsquare*/ + let mut u = &d + &Atemp; /* d, or d+A if nonsquare */ + u.conditional_negate(!eps_is_sq); /* d, or -d-A if nonsquare */ + + MontgomeryPoint(u.as_bytes()) +} + +/// A `ProjectivePoint` holds a point on the projective line +/// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer +/// line of the Montgomery curve. +#[derive(Copy, Clone, Debug)] +pub(crate) struct ProjectivePoint { + pub U: FieldElement, + pub W: FieldElement, +} + +impl Identity for ProjectivePoint { + fn identity() -> ProjectivePoint { + ProjectivePoint { + U: FieldElement::ONE, + W: FieldElement::ZERO, + } + } +} + +impl Default for ProjectivePoint { + fn default() -> ProjectivePoint { + ProjectivePoint::identity() + } +} + +impl ConditionallySelectable for ProjectivePoint { + fn conditional_select( + a: &ProjectivePoint, + b: &ProjectivePoint, + choice: Choice, + ) -> ProjectivePoint { + ProjectivePoint { + U: FieldElement::conditional_select(&a.U, &b.U, choice), + W: FieldElement::conditional_select(&a.W, &b.W, choice), + } + } +} + +impl ProjectivePoint { + /// Dehomogenize this point to affine coordinates. + /// + /// # Return + /// + /// * \\( u = U / W \\) if \\( W \neq 0 \\); + /// * \\( 0 \\) if \\( W \eq 0 \\); + #[cfg(not(curve25519_dalek_backend = "u32e_backend"))] + pub fn as_affine(&self) -> MontgomeryPoint { + //TODO: consider making this a seperate feature. Something like "panic_on_sw_eval" which would + //be ameniable to upstreaming + #[cfg(all(not(test), curve25519_dalek_backend = "u32e_backend"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. + log::warn!("sw as_affine being used - check for build config errors!"); + let u = &self.U * &self.W.invert(); + MontgomeryPoint(u.as_bytes()) + } + #[allow(dead_code)] + #[cfg(curve25519_dalek_backend = "u32e_backend")] + pub fn as_affine(&self) -> MontgomeryPoint { + let mcode = assemble_engine25519!( + start: + // W.invert() in %21 + // U in %29 + // W in %30 + // result in %31 + // loop counter in %28 + + // from FieldElement.invert() + // let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0 + // let t0 = self.square(); // 1 e_0 = 2^1 + mul %0, %30, %30 // self is W, e.g. %30 + // let t1 = t0.square().square(); // 3 e_1 = 2^3 + mul %1, %0, %0 + mul %1, %1, %1 + // let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0 + mul %2, %30, %1 + // let t3 = &t0 * &t2; // 3,1,0 + mul %3, %0, %2 + // let t4 = t3.square(); // 4,2,1 + mul %4, %3, %3 + // let t5 = &t2 * &t4; // 4,3,2,1,0 + mul %5, %2, %4 + + // let t6 = t5.pow2k(5); // 9,8,7,6,5 + psa %28, #5 // coincidentally, constant #5 is the number 5 + mul %6, %5, %5 + pow2k_5: + sub %28, %28, #1 // %28 = %28 - 1 + brz pow2k_5_exit, %28 + mul %6, %6, %6 + brz pow2k_5, #0 + pow2k_5_exit: + // let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0 + mul %7, %6, %5 + + // let t8 = t7.pow2k(10); // 19..10 + psa %28, #6 // constant #6 is the number 10 + mul %8, %7, %7 + pow2k_10: + sub %28, %28, #1 + brz pow2k_10_exit, %28 + mul %8, %8, %8 + brz pow2k_10, #0 + pow2k_10_exit: + // let t9 = &t8 * &t7; // 19..0 + mul %9, %8, %7 + + // let t10 = t9.pow2k(20); // 39..20 + psa %28, #7 // constant #7 is the number 20 + mul %10, %9, %9 + pow2k_20: + sub %28, %28, #1 + brz pow2k_20_exit, %28 + mul %10, %10, %10 + brz pow2k_20, #0 + pow2k_20_exit: + // let t11 = &t10 * &t9; // 39..0 + mul %11, %10, %9 + + // let t12 = t11.pow2k(10); // 49..10 + psa %28, #6 // constant #6 is the number 10 + mul %12, %11, %11 + pow2k_10b: + sub %28, %28, #1 + brz pow2k_10b_exit, %28 + mul %12, %12, %12 + brz pow2k_10b, #0 + pow2k_10b_exit: + // let t13 = &t12 * &t7; // 49..0 + mul %13, %12, %7 + + // let t14 = t13.pow2k(50); // 99..50 + psa %28, #8 // constant #8 is the number 50 + mul %14, %13, %13 + pow2k_50a: + sub %28, %28, #1 + brz pow2k_50a_exit, %28 + mul %14, %14, %14 + brz pow2k_50a, #0 + pow2k_50a_exit: + // let t15 = &t14 * &t13; // 99..0 + mul %15, %14, %13 + + // let t16 = t15.pow2k(100); // 199..100 + psa %28, #9 // constant #9 is the number 100 + mul %16, %15, %15 + pow2k_100: + sub %28, %28, #1 + brz pow2k_100_exit, %28 + mul %16, %16, %16 + brz pow2k_100, #0 + pow2k_100_exit: + // let t17 = &t16 * &t15; // 199..0 + mul %17, %16, %15 + + // let t18 = t17.pow2k(50); // 249..50 + psa %28, #8 // constant #8 is the number 50 + mul %18, %17, %17 + pow2k_50b: + sub %28, %28, #1 + brz pow2k_50b_exit, %28 + mul %18, %18, %18 + brz pow2k_50b, #0 + pow2k_50b_exit: + // let t19 = &t18 * &t13; // 249..0 + mul %19, %18, %13 + //(t19, t3) // just a return value, values are already there, do nothing + + //let t20 = t19.pow2k(5); // 254..5 + psa %28, #5 + mul %20, %19, %19 + pow2k_5_last: + sub %28, %28, #1 + brz pow2k_5_last_exit, %28 + mul %20, %20, %20 + brz pow2k_5_last, #0 + pow2k_5_last_exit: + + //let t21 = &t20 * &t3; // 254..5,3,1,0 + mul %21, %20, %3 + + // u = &self.U * &self.W.invert() + mul %31, %29, %21 + fin // finish execution + ); + + use crate::backend::serial::u32e::*; + ensure_engine(); + // safety: these were called after ensure_engine() + let mut ucode_hw = unsafe { get_ucode() }; + let rf_hw = unsafe { get_rf() }; + + copy_to_rf(self.U.as_bytes(), 29, rf_hw, 0); + copy_to_rf(self.W.as_bytes(), 30, rf_hw, 0); + + MontgomeryPoint(run_job(&mut ucode_hw, &rf_hw, &mcode, 0)) + } +} + +/// Perform the double-and-add step of the Montgomery ladder. +/// +/// Given projective points +/// \\( (U\_P : W\_P) = u(P) \\), +/// \\( (U\_Q : W\_Q) = u(Q) \\), +/// and the affine difference +/// \\( u\_{P-Q} = u(P-Q) \\), set +/// $$ +/// (U\_P : W\_P) \gets u(\[2\]P) +/// $$ +/// and +/// $$ +/// (U\_Q : W\_Q) \gets u(P + Q). +/// $$ +#[cfg(not(curve25519_dalek_backend = "u32e_backend"))] +#[rustfmt::skip] // keep alignment of explanatory comments +pub(crate) fn differential_add_and_double( + P: &mut ProjectivePoint, + Q: &mut ProjectivePoint, + affine_PmQ: &FieldElement, +) { + let t0 = &P.U + &P.W; + let t1 = &P.U - &P.W; + let t2 = &Q.U + &Q.W; + let t3 = &Q.U - &Q.W; + + let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 + let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 + + let t6 = &t4 - &t5; // 4 U_P W_P + + let t7 = &t0 * &t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q + let t8 = &t1 * &t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q + + let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) + let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) + + let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 + let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 + + let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q + + let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 + let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P + + let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) + + let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 + let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 + + P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 + P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) + Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 + Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 +} + +#[allow(dead_code)] // absorbed into mul, but might be useful later on as a subroutine for something else +#[cfg(curve25519_dalek_backend = "u32e_backend")] +pub(crate) fn differential_add_and_double( + P: &mut ProjectivePoint, + Q: &mut ProjectivePoint, + affine_PmQ: &FieldElement, +) { + let mcode = assemble_engine25519!( + start: + // P.U in %20 + // P.W in %21 + // Q.U in %22 + // Q.W in %23 + // affine_PmQ in %24 + // %30 is the TRD scratch register + // %29 is the subtraction temporary value register + + // let t0 = &P.U + &P.W; + add %0, %20, %21 + trd %30, %0 + sub %0, %0, %30 + // let t1 = &P.U - &P.W; + sub %21, #3, %21 // negate &P.W using #FIELDPRIME (#3) + add %1, %20, %21 + trd %30, %1 + sub %1, %1, %30 + // let t2 = &Q.U + &Q.W; + add %2, %22, %23 + trd %30, %2 + sub %2, %2, %30 + // let t3 = &Q.U - &Q.W; + sub %23, #3, %23 + add %3, %22, %23 + trd %30, %3 + sub %3, %3, %30 + // let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 + mul %4, %0, %0 + // let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 + mul %5, %1, %1 + // let t6 = &t4 - &t5; // 4 U_P W_P + sub %29, #3, %5 + add %6, %4, %29 + trd %30, %6 + sub %6, %6, %30 + // let t7 = &t0 * &t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q + mul %7, %0, %3 + // let t8 = &t1 * &t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q + mul %8, %1, %2 + // let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) + add %9, %7, %8 + trd %30, %9 + sub %9, %9, %30 + // let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) + sub %29, #3, %8 + add %10, %7, %29 + trd %30, %10 + sub %10, %10, %30 + // let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 + mul %11, %9, %9 + // let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 + mul %12, %10, %10 + // let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q + mul %13, #4, %6 // #4 is A+2/4 + // let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 + mul %14, %4, %5 + // let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P + add %15, %13, %5 + trd %30, %15 + sub %15, %15, %30 + // let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) + mul %16, %6, %15 + // let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 + mul %17, %24, %12 // affine_PmQ loaded into %24 + + ///// these can be eliminated down the road, but included for 1:1 algorithm correspodence to reference in early testing + // let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 + psa %18, %11 + // P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 + psa %20, %14 + // P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) + psa %21, %16 + // Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 + psa %22, %18 + // Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 + psa %23, %17 + + fin // finish execution + ); + use crate::backend::serial::u32e::*; + ensure_engine(); + // safety: these were called after ensure_engine() + let mut ucode_hw = unsafe { get_ucode() }; + let rf_hw = unsafe { get_rf() }; + + // P.U in %20 + // P.W in %21 + // Q.U in %22 + // Q.W in %23 + // affine_PmQ in %24 + copy_to_rf(P.U.as_bytes(), 20, rf_hw, 0); + copy_to_rf(P.W.as_bytes(), 21, rf_hw, 0); + copy_to_rf(Q.U.as_bytes(), 22, rf_hw, 0); + copy_to_rf(Q.W.as_bytes(), 23, rf_hw, 0); + copy_to_rf(affine_PmQ.as_bytes(), 24, rf_hw, 0); + + // start the run + run_job(&mut ucode_hw, &rf_hw, &mcode, 0); + + P.U = FieldElement::from_bytes(©_from_rf(20, &rf_hw, 0)); + P.W = FieldElement::from_bytes(©_from_rf(21, &rf_hw, 0)); + Q.U = FieldElement::from_bytes(©_from_rf(22, &rf_hw, 0)); + Q.W = FieldElement::from_bytes(©_from_rf(23, &rf_hw, 0)); +} + +define_mul_assign_variants!(LHS = MontgomeryPoint, RHS = Scalar); + +define_mul_variants!( + LHS = MontgomeryPoint, + RHS = Scalar, + Output = MontgomeryPoint +); +define_mul_variants!( + LHS = Scalar, + RHS = MontgomeryPoint, + Output = MontgomeryPoint +); + +/// Multiply this `MontgomeryPoint` by a `Scalar`. +impl Mul<&Scalar> for &MontgomeryPoint { + type Output = MontgomeryPoint; + + /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0([n]P) \\). + #[cfg(curve25519_dalek_backend = "u32e_backend")] + fn mul(self, scalar: &Scalar) -> MontgomeryPoint { + use crate::backend::serial::u32e::*; + + log::debug!("hw mont"); + // Algorithm 8 of Costello-Smith 2017 + let affine_u = FieldElement::from_bytes(&self.0); + let x0 = ProjectivePoint::identity(); + let x1 = ProjectivePoint { + U: affine_u, + W: FieldElement::ONE, + }; + + // for now, prefer to use the fully-accelerated version where this code is local to the server + // instead of transmitting it every call with the data...gives about a 2x performance speedup + let mcode = assemble_engine25519!( + start: + // P.U in %20 + // P.W in %21 + // Q.U in %22 + // Q.W in %23 + // affine_PmQ in %24 + // %30 is the TRD scratch register and cswap dummy + // %29 is the subtraction temporary value register and k_t + // x0.U in %25 + // x0.W in %26 + // x1.U in %27 + // x1.W in %28 + // %19 is the loop counter, starts with 254 (if 0, loop runs exactly once) + // %31 is the scalar + // %18 is the swap variable + psa %18, #0 + + // for i in (0..255).rev() + mainloop: + // let choice: u8 = (bits[i + 1] ^ bits[i]) as u8; + // ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into()); + xbt %29, %31 // orignally[k_t = (k>>t) & 1] now[k_t = k[254]] + shl %31, %31 // k = k<<1 + xor %18, %18, %29 // swap ^= k_t + + // cswap x0.U (%25), x1.U (%27) + xor %30, %25, %27 + msk %30, %18, %30 + xor %25, %30, %25 + xor %27, %30, %27 + // cswap x0.W (%26), x1.W (%28) + xor %30, %26, %28 + msk %30, %18, %30 + xor %26, %30, %26 + xor %28, %30, %28 + + psa %18, %29 // swap = k_t + + // differential_add_and_double(&mut x0, &mut x1, &affine_u); + psa %20, %25 + psa %21, %26 + psa %22, %27 + psa %23, %28 + // affine_u is already in %24 + + // let t0 = &P.U + &P.W; + add %0, %20, %21 + trd %30, %0 + sub %0, %0, %30 + // let t1 = &P.U - &P.W; + sub %21, #3, %21 // negate &P.W using #FIELDPRIME (#3) + add %1, %20, %21 + trd %30, %1 + sub %1, %1, %30 + // let t2 = &Q.U + &Q.W; + add %2, %22, %23 + trd %30, %2 + sub %2, %2, %30 + // let t3 = &Q.U - &Q.W; + sub %23, #3, %23 + add %3, %22, %23 + trd %30, %3 + sub %3, %3, %30 + // let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 + mul %4, %0, %0 + // let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 + mul %5, %1, %1 + // let t6 = &t4 - &t5; // 4 U_P W_P + sub %29, #3, %5 + add %6, %4, %29 + trd %30, %6 + sub %6, %6, %30 + // let t7 = &t0 * &t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q + mul %7, %0, %3 + // let t8 = &t1 * &t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q + mul %8, %1, %2 + // let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) + add %9, %7, %8 + trd %30, %9 + sub %9, %9, %30 + // let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) + sub %29, #3, %8 + add %10, %7, %29 + trd %30, %10 + sub %10, %10, %30 + // let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 + mul %11, %9, %9 + // let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 + mul %12, %10, %10 + // let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q + mul %13, #4, %6 // #4 is A+2/4 + // let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 + mul %14, %4, %5 + // let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P + add %15, %13, %5 + trd %30, %15 + sub %15, %15, %30 + // let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) + mul %16, %6, %15 + // let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 + mul %17, %24, %12 // affine_PmQ loaded into %24 + + ///// these can be eliminated down the road, but included for 1:1 algorithm correspodence to reference in early testing + // P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 + psa %20, %14 + // P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) + psa %21, %16 + // let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 + // Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 + psa %22, %11 // collapsed two to save a register + // Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 + psa %23, %17 + + ///// 'return' arguments for next iteration, can be optimized out later + psa %25, %20 + psa %26, %21 + psa %27, %22 + psa %28, %23 + + brz end, %19 // if loop counter is 0, quit + sub %19, %19, #1 // subtract one from the loop counter and run again + brz mainloop, #0 // go back to the top + end: + // ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8)); + // cswap x0.U (%25), x1.U (%27) + xor %30, %25, %27 + msk %30, %18, %30 + xor %25, %30, %25 + xor %27, %30, %27 + // cswap x0.W (%26), x1.W (%28) + xor %30, %26, %28 + msk %30, %18, %30 + xor %26, %30, %26 + xor %28, %30, %28 + + // AFFINE SPLICE -- pass arguments to the affine block + psa %29, %25 + psa %30, %26 + // W.invert() in %21 + // U in %29 + // W in %30 + // result in %31 + // loop counter in %28 + + // from FieldElement.invert() + // let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0 + // let t0 = self.square(); // 1 e_0 = 2^1 + mul %0, %30, %30 // self is W, e.g. %30 + // let t1 = t0.square().square(); // 3 e_1 = 2^3 + mul %1, %0, %0 + mul %1, %1, %1 + // let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0 + mul %2, %30, %1 + // let t3 = &t0 * &t2; // 3,1,0 + mul %3, %0, %2 + // let t4 = t3.square(); // 4,2,1 + mul %4, %3, %3 + // let t5 = &t2 * &t4; // 4,3,2,1,0 + mul %5, %2, %4 + + // let t6 = t5.pow2k(5); // 9,8,7,6,5 + psa %28, #5 // coincidentally, constant #5 is the number 5 + mul %6, %5, %5 + pow2k_5: + sub %28, %28, #1 // %28 = %28 - 1 + brz pow2k_5_exit, %28 + mul %6, %6, %6 + brz pow2k_5, #0 + pow2k_5_exit: + // let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0 + mul %7, %6, %5 + + // let t8 = t7.pow2k(10); // 19..10 + psa %28, #6 // constant #6 is the number 10 + mul %8, %7, %7 + pow2k_10: + sub %28, %28, #1 + brz pow2k_10_exit, %28 + mul %8, %8, %8 + brz pow2k_10, #0 + pow2k_10_exit: + // let t9 = &t8 * &t7; // 19..0 + mul %9, %8, %7 + + // let t10 = t9.pow2k(20); // 39..20 + psa %28, #7 // constant #7 is the number 20 + mul %10, %9, %9 + pow2k_20: + sub %28, %28, #1 + brz pow2k_20_exit, %28 + mul %10, %10, %10 + brz pow2k_20, #0 + pow2k_20_exit: + // let t11 = &t10 * &t9; // 39..0 + mul %11, %10, %9 + + // let t12 = t11.pow2k(10); // 49..10 + psa %28, #6 // constant #6 is the number 10 + mul %12, %11, %11 + pow2k_10b: + sub %28, %28, #1 + brz pow2k_10b_exit, %28 + mul %12, %12, %12 + brz pow2k_10b, #0 + pow2k_10b_exit: + // let t13 = &t12 * &t7; // 49..0 + mul %13, %12, %7 + + // let t14 = t13.pow2k(50); // 99..50 + psa %28, #8 // constant #8 is the number 50 + mul %14, %13, %13 + pow2k_50a: + sub %28, %28, #1 + brz pow2k_50a_exit, %28 + mul %14, %14, %14 + brz pow2k_50a, #0 + pow2k_50a_exit: + // let t15 = &t14 * &t13; // 99..0 + mul %15, %14, %13 + + // let t16 = t15.pow2k(100); // 199..100 + psa %28, #9 // constant #9 is the number 100 + mul %16, %15, %15 + pow2k_100: + sub %28, %28, #1 + brz pow2k_100_exit, %28 + mul %16, %16, %16 + brz pow2k_100, #0 + pow2k_100_exit: + // let t17 = &t16 * &t15; // 199..0 + mul %17, %16, %15 + + // let t18 = t17.pow2k(50); // 249..50 + psa %28, #8 // constant #8 is the number 50 + mul %18, %17, %17 + pow2k_50b: + sub %28, %28, #1 + brz pow2k_50b_exit, %28 + mul %18, %18, %18 + brz pow2k_50b, #0 + pow2k_50b_exit: + // let t19 = &t18 * &t13; // 249..0 + mul %19, %18, %13 + //(t19, t3) // just a return value, values are already there, do nothing + + //let t20 = t19.pow2k(5); // 254..5 + psa %28, #5 + mul %20, %19, %19 + pow2k_5_last: + sub %28, %28, #1 + brz pow2k_5_last_exit, %28 + mul %20, %20, %20 + brz pow2k_5_last, #0 + pow2k_5_last_exit: + + //let t21 = &t20 * &t3; // 254..5,3,1,0 + mul %21, %20, %3 + + // u = &self.U * &self.W.invert() + mul %31, %29, %21 + fin // finish execution + ); + + let window = 0; + ensure_engine(); + // safety: these were called after ensure_engine() + let mut ucode_hw = unsafe { get_ucode() }; + let mut rf_hw = unsafe { get_rf() }; + + copy_to_rf(x0.U.as_bytes(), 25, &mut rf_hw, window); + copy_to_rf(x0.W.as_bytes(), 26, &mut rf_hw, window); + copy_to_rf(x1.U.as_bytes(), 27, &mut rf_hw, window); + copy_to_rf(x1.W.as_bytes(), 28, &mut rf_hw, window); + copy_to_rf(affine_u.as_bytes(), 24, &mut rf_hw, window); + copy_to_rf(scalar.bytes, 31, &mut rf_hw, window); + copy_to_rf( + [ + 254, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + ], + 19, + &mut rf_hw, + window, + ); // 254 as loop counter + + MontgomeryPoint(run_job(&mut ucode_hw, &rf_hw, &mcode, window)) + } + + /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0(\[n\]P) \\) + #[cfg(not(curve25519_dalek_backend = "u32e_backend"))] + fn mul(self, scalar: &Scalar) -> MontgomeryPoint { + // TODO: consider feature "panic_on_sw_eval" + #[cfg(all(not(test), curve25519_dalek_backend = "u32e_backend"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. + log::warn!("sw montgomery multiply being used - check for build config errors!"); + // We multiply by the integer representation of the given Scalar. By scalar invariant #1, + // the MSB is 0, so we can skip it. + self.mul_bits_be(scalar.bits_le().rev().skip(1)) + } +} + +impl MulAssign<&Scalar> for MontgomeryPoint { + fn mul_assign(&mut self, scalar: &Scalar) { + *self = (self as &MontgomeryPoint) * scalar; + } +} + +impl Mul<&MontgomeryPoint> for &Scalar { + type Output = MontgomeryPoint; + + fn mul(self, point: &MontgomeryPoint) -> MontgomeryPoint { + point * self + } +} + +// ------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------ + +#[cfg(test)] +mod test { + use super::*; + use crate::constants; + + #[cfg(feature = "alloc")] + use alloc::vec::Vec; + + use rand_core::{CryptoRng, RngCore}; + + #[test] + fn identity_in_different_coordinates() { + let id_projective = ProjectivePoint::identity(); + let id_montgomery = id_projective.as_affine(); + + assert!(id_montgomery == MontgomeryPoint::identity()); + } + + #[test] + fn identity_in_different_models() { + assert!(EdwardsPoint::identity().to_montgomery() == MontgomeryPoint::identity()); + } + + #[test] + #[cfg(feature = "serde")] + fn serde_bincode_basepoint_roundtrip() { + use bincode; + + let encoded = bincode::serialize(&constants::X25519_BASEPOINT).unwrap(); + let decoded: MontgomeryPoint = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded, constants::X25519_BASEPOINT); + + let raw_bytes = constants::X25519_BASEPOINT.as_bytes(); + let bp: MontgomeryPoint = bincode::deserialize(raw_bytes).unwrap(); + assert_eq!(bp, constants::X25519_BASEPOINT); + } + + /// Test Montgomery -> Edwards on the X/Ed25519 basepoint + #[test] + fn basepoint_montgomery_to_edwards() { + // sign bit = 0 => basepoint + assert_eq!( + constants::ED25519_BASEPOINT_POINT, + constants::X25519_BASEPOINT.to_edwards(0).unwrap() + ); + // sign bit = 1 => minus basepoint + assert_eq!( + -constants::ED25519_BASEPOINT_POINT, + constants::X25519_BASEPOINT.to_edwards(1).unwrap() + ); + } + + /// Test Edwards -> Montgomery on the X/Ed25519 basepoint + #[test] + fn basepoint_edwards_to_montgomery() { + assert_eq!( + constants::ED25519_BASEPOINT_POINT.to_montgomery(), + constants::X25519_BASEPOINT + ); + } + + /// Check that Montgomery -> Edwards fails for points on the twist. + #[test] + fn montgomery_to_edwards_rejects_twist() { + let one = FieldElement::ONE; + + // u = 2 corresponds to a point on the twist. + let two = MontgomeryPoint((&one + &one).as_bytes()); + + assert!(two.to_edwards(0).is_none()); + + // u = -1 corresponds to a point on the twist, but should be + // checked explicitly because it's an exceptional point for the + // birational map. For instance, libsignal will accept it. + let minus_one = MontgomeryPoint((-&one).as_bytes()); + + assert!(minus_one.to_edwards(0).is_none()); + } + + #[test] + fn eq_defined_mod_p() { + let mut u18_bytes = [0u8; 32]; + u18_bytes[0] = 18; + let u18 = MontgomeryPoint(u18_bytes); + let u18_unred = MontgomeryPoint([255; 32]); + + assert_eq!(u18, u18_unred); + } + + /// Returns a random point on the prime-order subgroup + fn rand_prime_order_point(mut rng: impl RngCore + CryptoRng) -> EdwardsPoint { + let s: Scalar = Scalar::random(&mut rng); + EdwardsPoint::mul_base(&s) + } + + /// Given a bytestring that's little-endian at the byte level, return an iterator over all the + /// bits, in little-endian order. + fn bytestring_bits_le(x: &[u8]) -> impl DoubleEndedIterator + Clone + '_ { + let bitlen = x.len() * 8; + (0..bitlen).map(|i| { + // As i runs from 0..256, the bottom 3 bits index the bit, while the upper bits index + // the byte. Since self.bytes is little-endian at the byte level, this iterator is + // little-endian on the bit level + ((x[i >> 3] >> (i & 7)) & 1u8) == 1 + }) + } + + #[test] + fn montgomery_ladder_matches_edwards_scalarmult() { + let mut csprng = rand_core::OsRng; + + for _ in 0..100 { + let p_edwards = rand_prime_order_point(&mut csprng); + let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); + + let s: Scalar = Scalar::random(&mut csprng); + let expected = s * p_edwards; + let result = s * p_montgomery; + + assert_eq!(result, expected.to_montgomery()) + } + } + + // Tests that, on the prime-order subgroup, MontgomeryPoint::mul_bits_be is the same as + // multiplying by the Scalar representation of the same bits + #[test] + fn montgomery_mul_bits_be() { + let mut csprng = rand_core::OsRng; + + for _ in 0..100 { + // Make a random prime-order point P + let p_edwards = rand_prime_order_point(&mut csprng); + let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); + + // Make a random integer b + let mut bigint = [0u8; 64]; + csprng.fill_bytes(&mut bigint[..]); + let bigint_bits_be = bytestring_bits_le(&bigint).rev(); + + // Check that bP is the same whether calculated as scalar-times-edwards or + // integer-times-montgomery. + let expected = Scalar::from_bytes_mod_order_wide(&bigint) * p_edwards; + let result = p_montgomery.mul_bits_be(bigint_bits_be); + assert_eq!(result, expected.to_montgomery()) + } + } + + // Tests that MontgomeryPoint::mul_bits_be is consistent on any point, even ones that might be + // on the curve's twist. Specifically, this tests that b₁(b₂P) == b₂(b₁P) for random + // integers b₁, b₂ and random (curve or twist) point P. + #[test] + fn montgomery_mul_bits_be_twist() { + let mut csprng = rand_core::OsRng; + + for _ in 0..100 { + // Make a random point P on the curve or its twist + let p_montgomery = { + let mut buf = [0u8; 32]; + csprng.fill_bytes(&mut buf); + MontgomeryPoint(buf) + }; + + // Compute two big integers b₁ and b₂ + let mut bigint1 = [0u8; 64]; + let mut bigint2 = [0u8; 64]; + csprng.fill_bytes(&mut bigint1[..]); + csprng.fill_bytes(&mut bigint2[..]); + + // Compute b₁P and b₂P + let bigint1_bits_be = bytestring_bits_le(&bigint1).rev(); + let bigint2_bits_be = bytestring_bits_le(&bigint2).rev(); + let prod1 = p_montgomery.mul_bits_be(bigint1_bits_be.clone()); + let prod2 = p_montgomery.mul_bits_be(bigint2_bits_be.clone()); + + // Check that b₁(b₂P) == b₂(b₁P) + assert_eq!( + prod1.mul_bits_be(bigint2_bits_be), + prod2.mul_bits_be(bigint1_bits_be) + ); + } + } + + /// Check that mul_base_clamped and mul_clamped agree + #[test] + fn mul_base_clamped() { + let mut csprng = rand_core::OsRng; + + // Test agreement on a large integer. Even after clamping, this is not reduced mod l. + let a_bytes = [0xff; 32]; + assert_eq!( + MontgomeryPoint::mul_base_clamped(a_bytes), + constants::X25519_BASEPOINT.mul_clamped(a_bytes) + ); + + // Test agreement on random integers + for _ in 0..100 { + // This will be reduced mod l with probability l / 2^256 ≈ 6.25% + let mut a_bytes = [0u8; 32]; + csprng.fill_bytes(&mut a_bytes); + + assert_eq!( + MontgomeryPoint::mul_base_clamped(a_bytes), + constants::X25519_BASEPOINT.mul_clamped(a_bytes) + ); + } + } + + #[cfg(feature = "alloc")] + const ELLIGATOR_CORRECT_OUTPUT: [u8; 32] = [ + 0x5f, 0x35, 0x20, 0x00, 0x1c, 0x6c, 0x99, 0x36, 0xa3, 0x12, 0x06, 0xaf, 0xe7, 0xc7, 0xac, + 0x22, 0x4e, 0x88, 0x61, 0x61, 0x9b, 0xf9, 0x88, 0x72, 0x44, 0x49, 0x15, 0x89, 0x9d, 0x95, + 0xf4, 0x6e, + ]; + + #[test] + #[cfg(feature = "alloc")] + fn montgomery_elligator_correct() { + let bytes: Vec = (0u8..32u8).collect(); + let bits_in: [u8; 32] = (&bytes[..]).try_into().expect("Range invariant broken"); + + let fe = FieldElement::from_bytes(&bits_in); + let eg = elligator_encode(&fe); + assert_eq!(eg.to_bytes(), ELLIGATOR_CORRECT_OUTPUT); + } + + #[test] + fn montgomery_elligator_zero_zero() { + let zero = [0u8; 32]; + let fe = FieldElement::from_bytes(&zero); + let eg = elligator_encode(&fe); + assert_eq!(eg.to_bytes(), zero); + } +} diff --git a/src/ristretto.rs b/curve25519-dalek/src/ristretto.rs similarity index 52% rename from src/ristretto.rs rename to curve25519-dalek/src/ristretto.rs index bd5dc6a77..c9d16aba3 100644 --- a/src/ristretto.rs +++ b/curve25519-dalek/src/ristretto.rs @@ -113,7 +113,7 @@ //! used to implement //! //! * `RistrettoPoint::random()`, which generates random points from an -//! RNG; +//! RNG - enabled by `rand_core` feature; //! //! * `RistrettoPoint::from_hash()` and //! `RistrettoPoint::hash_from_bytes()`, which perform hashing to the @@ -124,7 +124,7 @@ //! ## Implementation //! //! The Decaf suggestion is to use a quotient group, such as \\(\mathcal -//! E / \mathcal E[4]\\) or \\(2 \mathcal E / \mathcal E[2] \\), to +//! E / \mathcal E\[4\]\\) or \\(2 \mathcal E / \mathcal E\[2\] \\), to //! implement a prime-order group using a non-prime-order curve. //! //! This requires only changing @@ -158,6 +158,10 @@ //! [ristretto_main]: //! https://ristretto.group/ +#[cfg(feature = "alloc")] +use alloc::vec::Vec; + +use core::array::TryFromSliceError; use core::borrow::Borrow; use core::fmt::Debug; use core::iter::Sum; @@ -165,44 +169,43 @@ use core::ops::{Add, Neg, Sub}; use core::ops::{AddAssign, SubAssign}; use core::ops::{Mul, MulAssign}; -use rand_core::{CryptoRng, RngCore}; +#[cfg(any(test, feature = "rand_core"))] +use rand_core::CryptoRngCore; +#[cfg(feature = "digest")] use digest::generic_array::typenum::U64; +#[cfg(feature = "digest")] use digest::Digest; -use constants; -use field::FieldElement; +use crate::constants; +use crate::field::FieldElement; + +#[cfg(feature = "group")] +use { + group::{cofactor::CofactorGroup, prime::PrimeGroup, GroupEncoding}, + rand_core::RngCore, + subtle::CtOption, +}; use subtle::Choice; -use subtle::ConditionallySelectable; use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; -use edwards::EdwardsBasepointTable; -use edwards::EdwardsPoint; +#[cfg(feature = "precomputed-tables")] +use crate::edwards::EdwardsBasepointTable; +use crate::edwards::EdwardsPoint; -#[allow(unused_imports)] -use prelude::*; +use crate::scalar::Scalar; -use scalar::Scalar; - -use traits::Identity; -#[cfg(any(feature = "alloc", feature = "std"))] -use traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; - -#[cfg(not(all( - feature = "simd_backend", - any(target_feature = "avx2", target_feature = "avx512ifma") -)))] -#[cfg(all(not(feature = "betrusted"), not(feature = "u32e_backend")))] -use backend::serial::scalar_mul; -#[cfg(all( - feature = "simd_backend", - any(target_feature = "avx2", target_feature = "avx512ifma") -))] -use backend::vector::scalar_mul; +#[cfg(feature = "precomputed-tables")] +use crate::traits::BasepointTable; +use crate::traits::Identity; +#[cfg(feature = "alloc")] +use crate::traits::{MultiscalarMul, VartimeMultiscalarMul, VartimePrecomputedMultiscalarMul}; // ------------------------------------------------------------------------ // Compressed points @@ -223,26 +226,23 @@ impl ConstantTimeEq for CompressedRistretto { impl CompressedRistretto { /// Copy the bytes of this `CompressedRistretto`. - pub fn to_bytes(&self) -> [u8; 32] { + pub const fn to_bytes(&self) -> [u8; 32] { self.0 } /// View this `CompressedRistretto` as an array of bytes. - pub fn as_bytes(&self) -> &[u8; 32] { + pub const fn as_bytes(&self) -> &[u8; 32] { &self.0 } /// Construct a `CompressedRistretto` from a slice of bytes. /// - /// # Panics + /// # Errors /// - /// If the input `bytes` slice does not have a length of 32. - pub fn from_slice(bytes: &[u8]) -> CompressedRistretto { - let mut tmp = [0u8; 32]; - - tmp.copy_from_slice(bytes); - - CompressedRistretto(tmp) + /// Returns [`TryFromSliceError`] if the input `bytes` slice does not have + /// a length of 32. + pub fn from_slice(bytes: &[u8]) -> Result { + bytes.try_into().map(CompressedRistretto) } /// Attempt to decompress to an `RistrettoPoint`. @@ -253,6 +253,26 @@ impl CompressedRistretto { /// /// - `None` if `self` was not the canonical encoding of a point. pub fn decompress(&self) -> Option { + let (s_encoding_is_canonical, s_is_negative, s) = decompress::step_1(self); + + if (!s_encoding_is_canonical | s_is_negative).into() { + return None; + } + + let (ok, t_is_negative, y_is_zero, res) = decompress::step_2(s); + + if (!ok | t_is_negative | y_is_zero).into() { + None + } else { + Some(res) + } + } +} + +mod decompress { + use super::*; + + pub(super) fn step_1(repr: &CompressedRistretto) -> (Choice, Choice, FieldElement) { // Step 1. Check s for validity: // 1.a) s must be 32 bytes (we get this from the type system) // 1.b) s < p @@ -264,21 +284,20 @@ impl CompressedRistretto { // converting back to bytes, and checking that we get the // original input, since our encoding routine is canonical. - let s = FieldElement::from_bytes(self.as_bytes()); - let s_bytes_check = s.to_bytes(); - let s_encoding_is_canonical = - &s_bytes_check[..].ct_eq(self.as_bytes()); + let s = FieldElement::from_bytes(repr.as_bytes()); + let s_bytes_check = s.as_bytes(); + let s_encoding_is_canonical = s_bytes_check[..].ct_eq(repr.as_bytes()); let s_is_negative = s.is_negative(); - if s_encoding_is_canonical.unwrap_u8() == 0u8 || s_is_negative.unwrap_u8() == 1u8 { - return None; - } + (s_encoding_is_canonical, s_is_negative, s) + } + pub(super) fn step_2(s: FieldElement) -> (Choice, Choice, Choice, RistrettoPoint) { // Step 2. Compute (X:Y:Z:T). - let one = FieldElement::one(); + let one = FieldElement::ONE; let ss = s.square(); - let u1 = &one - &ss; // 1 + as² - let u2 = &one + &ss; // 1 - as² where a=-1 + let u1 = &one - &ss; // 1 + as² + let u2 = &one + &ss; // 1 - as² where a=-1 let u2_sqr = u2.square(); // (1 - as²)² // v == ad(1+as²)² - (1-as²)² where d=-121665/121666 @@ -286,7 +305,7 @@ impl CompressedRistretto { let (ok, I) = (&v * &u2_sqr).invsqrt(); // 1/sqrt(v*u_2²) - let Dx = &I * &u2; // 1/sqrt(v) + let Dx = &I * &u2; // 1/sqrt(v) let Dy = &I * &(&Dx * &v); // 1/u2 // x == | 2s/sqrt(v) | == + sqrt(4s²/(ad(1+as²)² - (1-as²)²)) @@ -300,11 +319,17 @@ impl CompressedRistretto { // t == ((1+as²) sqrt(4s²/(ad(1+as²)² - (1-as²)²)))/(1-as²) let t = &x * &y; - if ok.unwrap_u8() == 0u8 || t.is_negative().unwrap_u8() == 1u8 || y.is_zero().unwrap_u8() == 1u8 { - None - } else { - Some(RistrettoPoint(EdwardsPoint{X: x, Y: y, Z: one, T: t})) - } + ( + ok, + t.is_negative(), + y.is_zero(), + RistrettoPoint(EdwardsPoint { + X: x, + Y: y, + Z: one, + T: t, + }), + ) } } @@ -320,6 +345,14 @@ impl Default for CompressedRistretto { } } +impl TryFrom<&[u8]> for CompressedRistretto { + type Error = TryFromSliceError; + + fn try_from(slice: &[u8]) -> Result { + Self::from_slice(slice) + } +} + // ------------------------------------------------------------------------ // Serde support // ------------------------------------------------------------------------ @@ -328,15 +361,16 @@ impl Default for CompressedRistretto { // structs containing `RistrettoPoint`s and use Serde's derived // serializers to serialize those structures. -#[cfg(feature = "serde")] -use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] impl Serialize for RistrettoPoint { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -350,7 +384,8 @@ impl Serialize for RistrettoPoint { #[cfg(feature = "serde")] impl Serialize for CompressedRistretto { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -364,28 +399,32 @@ impl Serialize for CompressedRistretto { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for RistrettoPoint { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct RistrettoPointVisitor; impl<'de> Visitor<'de> for RistrettoPointVisitor { type Value = RistrettoPoint; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("a valid point in Ristretto format") } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { - bytes[i] = seq.next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + bytes[i] = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } CompressedRistretto(bytes) .decompress() - .ok_or(serde::de::Error::custom("decompression failed")) + .ok_or_else(|| serde::de::Error::custom("decompression failed")) } } @@ -396,24 +435,28 @@ impl<'de> Deserialize<'de> for RistrettoPoint { #[cfg(feature = "serde")] impl<'de> Deserialize<'de> for CompressedRistretto { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct CompressedRistrettoVisitor; impl<'de> Visitor<'de> for CompressedRistrettoVisitor { type Value = CompressedRistretto; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { formatter.write_str("32 bytes of data") } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { - bytes[i] = seq.next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + bytes[i] = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } Ok(CompressedRistretto(bytes)) } @@ -475,7 +518,7 @@ impl RistrettoPoint { let s_is_negative = s.is_negative(); s.conditional_negate(s_is_negative); - CompressedRistretto(s.to_bytes()) + CompressedRistretto(s.as_bytes()) } /// Double-and-compress a batch of points. The Ristretto encoding @@ -483,19 +526,19 @@ impl RistrettoPoint { /// /// However, given input points \\( P\_1, \ldots, P\_n, \\) /// it is possible to compute the encodings of their doubles \\( - /// \mathrm{enc}( [2]P\_1), \ldots, \mathrm{enc}( [2]P\_n ) \\) + /// \mathrm{enc}( \[2\]P\_1), \ldots, \mathrm{enc}( \[2\]P\_n ) \\) /// in a batch. /// - /// ``` - /// # extern crate curve25519_dalek; + #[cfg_attr(feature = "rand_core", doc = "```")] + #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] /// # use curve25519_dalek::ristretto::RistrettoPoint; - /// extern crate rand_core; /// use rand_core::OsRng; /// /// # // Need fn main() here in comment so the doctest compiles /// # // See https://doc.rust-lang.org/book/documentation.html#documentation-as-tests /// # fn main() { /// let mut rng = OsRng; + /// /// let points: Vec = /// (0..32).map(|_| RistrettoPoint::random(&mut rng)).collect(); /// @@ -508,7 +551,8 @@ impl RistrettoPoint { /// ``` #[cfg(feature = "alloc")] pub fn double_and_compress_batch<'a, I>(points: I) -> Vec - where I: IntoIterator + where + I: IntoIterator, { #[derive(Copy, Clone, Debug)] struct BatchCompressState { @@ -527,6 +571,7 @@ impl RistrettoPoint { } impl<'a> From<&'a RistrettoPoint> for BatchCompressState { + #[rustfmt::skip] // keep alignment of explanatory comments fn from(P: &'a RistrettoPoint) -> BatchCompressState { let XX = P.0.X.square(); let YY = P.0.Y.square(); @@ -545,57 +590,64 @@ impl RistrettoPoint { } } - let states: Vec = points.into_iter().map(BatchCompressState::from).collect(); + let states: Vec = + points.into_iter().map(BatchCompressState::from).collect(); let mut invs: Vec = states.iter().map(|state| state.efgh()).collect(); FieldElement::batch_invert(&mut invs[..]); - states.iter().zip(invs.iter()).map(|(state, inv): (&BatchCompressState, &FieldElement)| { - let Zinv = &state.eg * &inv; - let Tinv = &state.fh * &inv; + states + .iter() + .zip(invs.iter()) + .map(|(state, inv): (&BatchCompressState, &FieldElement)| { + let Zinv = &state.eg * inv; + let Tinv = &state.fh * inv; - let mut magic = constants::INVSQRT_A_MINUS_D; + let mut magic = constants::INVSQRT_A_MINUS_D; - let negcheck1 = (&state.eg * &Zinv).is_negative(); + let negcheck1 = (&state.eg * &Zinv).is_negative(); - let mut e = state.e; - let mut g = state.g; - let mut h = state.h; + let mut e = state.e; + let mut g = state.g; + let mut h = state.h; - let minus_e = -&e; - let f_times_sqrta = &state.f * &constants::SQRT_M1; + let minus_e = -&e; + let f_times_sqrta = &state.f * &constants::SQRT_M1; - e.conditional_assign(&state.g, negcheck1); - g.conditional_assign(&minus_e, negcheck1); - h.conditional_assign(&f_times_sqrta, negcheck1); + e.conditional_assign(&state.g, negcheck1); + g.conditional_assign(&minus_e, negcheck1); + h.conditional_assign(&f_times_sqrta, negcheck1); - magic.conditional_assign(&constants::SQRT_M1, negcheck1); + magic.conditional_assign(&constants::SQRT_M1, negcheck1); - let negcheck2 = (&(&h * &e) * &Zinv).is_negative(); + let negcheck2 = (&(&h * &e) * &Zinv).is_negative(); - g.conditional_negate(negcheck2); + g.conditional_negate(negcheck2); - let mut s = &(&h - &g) * &(&magic * &(&g * &Tinv)); + let mut s = &(&h - &g) * &(&magic * &(&g * &Tinv)); - let s_is_negative = s.is_negative(); - s.conditional_negate(s_is_negative); + let s_is_negative = s.is_negative(); + s.conditional_negate(s_is_negative); - CompressedRistretto(s.to_bytes()) - }).collect() + CompressedRistretto(s.as_bytes()) + }) + .collect() } - - /// Return the coset self + E[4], for debugging. + /// Return the coset self + E\[4\], for debugging. fn coset4(&self) -> [EdwardsPoint; 4] { - [ self.0 - , &self.0 + &constants::EIGHT_TORSION[2] - , &self.0 + &constants::EIGHT_TORSION[4] - , &self.0 + &constants::EIGHT_TORSION[6] + [ + self.0, + self.0 + constants::EIGHT_TORSION[2], + self.0 + constants::EIGHT_TORSION[4], + self.0 + constants::EIGHT_TORSION[6], ] } - /// Computes the Ristretto Elligator map. + /// Computes the Ristretto Elligator map. This is the + /// [`MAP`](https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#section-4.3.4) + /// function defined in the Ristretto spec. /// /// # Note /// @@ -608,10 +660,10 @@ impl RistrettoPoint { let d_minus_one_sq = &constants::EDWARDS_D_MINUS_ONE_SQUARED; let mut c = constants::MINUS_ONE; - let one = FieldElement::one(); + let one = FieldElement::ONE; let r = i * &r_0.square(); - let N_s = &(&r + &one) * &one_minus_d_sq; + let N_s = &(&r + &one) * one_minus_d_sq; let D = &(&c - &(d * &r)) * &(&r + d); let (Ns_D_is_sq, mut s) = FieldElement::sqrt_ratio_i(&N_s, &D); @@ -622,25 +674,30 @@ impl RistrettoPoint { s.conditional_assign(&s_prime, !Ns_D_is_sq); c.conditional_assign(&r, !Ns_D_is_sq); - let N_t = &(&(&c * &(&r - &one)) * &d_minus_one_sq) - &D; + let N_t = &(&(&c * &(&r - &one)) * d_minus_one_sq) - &D; let s_sq = s.square(); - use backend::serial::curve_models::CompletedPoint; + use crate::backend::serial::curve_models::CompletedPoint; // The conversion from W_i is exactly the conversion from P1xP1. - RistrettoPoint(CompletedPoint{ - X: &(&s + &s) * &D, - Z: &N_t * &constants::SQRT_AD_MINUS_ONE, - Y: &FieldElement::one() - &s_sq, - T: &FieldElement::one() + &s_sq, - }.to_extended()) + RistrettoPoint( + CompletedPoint { + X: &(&s + &s) * &D, + Z: &N_t * &constants::SQRT_AD_MINUS_ONE, + Y: &FieldElement::ONE - &s_sq, + T: &FieldElement::ONE + &s_sq, + } + .as_extended(), + ) } + #[cfg(any(test, feature = "rand_core"))] /// Return a `RistrettoPoint` chosen uniformly at random using a user-provided RNG. /// /// # Inputs /// - /// * `rng`: any RNG which implements the `RngCore + CryptoRng` interface. + /// * `rng`: any RNG which implements `CryptoRngCore` + /// (i.e. `CryptoRng` + `RngCore`) interface. /// /// # Returns /// @@ -652,13 +709,14 @@ impl RistrettoPoint { /// discrete log of the output point with respect to any other /// point should be unknown. The map is applied twice and the /// results are added, to ensure a uniform distribution. - pub fn random(rng: &mut R) -> Self { + pub fn random(rng: &mut R) -> Self { let mut uniform_bytes = [0u8; 64]; rng.fill_bytes(&mut uniform_bytes); RistrettoPoint::from_uniform_bytes(&uniform_bytes) } + #[cfg(feature = "digest")] /// Hash a slice of bytes into a `RistrettoPoint`. /// /// Takes a type parameter `D`, which is any `Digest` producing 64 @@ -675,10 +733,9 @@ impl RistrettoPoint { /// /// # Example /// - /// ``` - /// # extern crate curve25519_dalek; + #[cfg_attr(feature = "digest", doc = "```")] + #[cfg_attr(not(feature = "digest"), doc = "```ignore")] /// # use curve25519_dalek::ristretto::RistrettoPoint; - /// extern crate sha2; /// use sha2::Sha512; /// /// # // Need fn main() here in comment so the doctest compiles @@ -690,25 +747,28 @@ impl RistrettoPoint { /// ``` /// pub fn hash_from_bytes(input: &[u8]) -> RistrettoPoint - where D: Digest + Default + where + D: Digest + Default, { let mut hash = D::default(); hash.update(input); RistrettoPoint::from_hash(hash) } + #[cfg(feature = "digest")] /// Construct a `RistrettoPoint` from an existing `Digest` instance. /// /// Use this instead of `hash_from_bytes` if it is more convenient /// to stream data into the `Digest` than to pass a single byte /// slice. pub fn from_hash(hash: D) -> RistrettoPoint - where D: Digest + Default + where + D: Digest + Default, { // dealing with generic arrays is clumsy, until const generics land let output = hash.finalize(); let mut output_bytes = [0u8; 64]; - output_bytes.copy_from_slice(&output.as_slice()); + output_bytes.copy_from_slice(output.as_slice()); RistrettoPoint::from_uniform_bytes(&output_bytes) } @@ -725,6 +785,8 @@ impl RistrettoPoint { /// takes the low 255 bits of each half mod p, applies the /// Ristretto-flavored Elligator map to each, and adds the results. pub fn from_uniform_bytes(bytes: &[u8; 64]) -> RistrettoPoint { + // This follows the one-way map construction from the Ristretto RFC: + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#section-4.3.4 let mut r_1_bytes = [0u8; 32]; r_1_bytes.copy_from_slice(&bytes[0..32]); let r_1 = FieldElement::from_bytes(&r_1_bytes); @@ -737,7 +799,7 @@ impl RistrettoPoint { // Applying Elligator twice and adding the results ensures a // uniform distribution. - &R_1 + &R_2 + R_1 + R_2 } } @@ -759,7 +821,7 @@ impl Default for RistrettoPoint { impl PartialEq for RistrettoPoint { fn eq(&self, other: &RistrettoPoint) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } @@ -790,11 +852,15 @@ impl<'a, 'b> Add<&'b RistrettoPoint> for &'a RistrettoPoint { type Output = RistrettoPoint; fn add(self, other: &'b RistrettoPoint) -> RistrettoPoint { - RistrettoPoint(&self.0 + &other.0) + RistrettoPoint(self.0 + other.0) } } -define_add_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint, Output = RistrettoPoint); +define_add_variants!( + LHS = RistrettoPoint, + RHS = RistrettoPoint, + Output = RistrettoPoint +); impl<'b> AddAssign<&'b RistrettoPoint> for RistrettoPoint { fn add_assign(&mut self, _rhs: &RistrettoPoint) { @@ -808,11 +874,15 @@ impl<'a, 'b> Sub<&'b RistrettoPoint> for &'a RistrettoPoint { type Output = RistrettoPoint; fn sub(self, other: &'b RistrettoPoint) -> RistrettoPoint { - RistrettoPoint(&self.0 - &other.0) + RistrettoPoint(self.0 - other.0) } } -define_sub_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint, Output = RistrettoPoint); +define_sub_variants!( + LHS = RistrettoPoint, + RHS = RistrettoPoint, + Output = RistrettoPoint +); impl<'b> SubAssign<&'b RistrettoPoint> for RistrettoPoint { fn sub_assign(&mut self, _rhs: &RistrettoPoint) { @@ -824,11 +894,11 @@ define_sub_assign_variants!(LHS = RistrettoPoint, RHS = RistrettoPoint); impl Sum for RistrettoPoint where - T: Borrow + T: Borrow, { fn sum(iter: I) -> Self where - I: Iterator + I: Iterator, { iter.fold(RistrettoPoint::identity(), |acc, item| acc + item.borrow()) } @@ -874,6 +944,24 @@ impl<'a, 'b> Mul<&'b RistrettoPoint> for &'a Scalar { } } +impl RistrettoPoint { + /// Fixed-base scalar multiplication by the Ristretto base point. + /// + /// Uses precomputed basepoint tables when the `precomputed-tables` feature + /// is enabled, trading off increased code size for ~4x better performance. + pub fn mul_base(scalar: &Scalar) -> Self { + #[cfg(not(feature = "precomputed-tables"))] + { + scalar * constants::RISTRETTO_BASEPOINT_POINT + } + + #[cfg(feature = "precomputed-tables")] + { + scalar * constants::RISTRETTO_BASEPOINT_TABLE + } + } +} + define_mul_assign_variants!(LHS = RistrettoPoint, RHS = Scalar); define_mul_variants!(LHS = RistrettoPoint, RHS = Scalar, Output = RistrettoPoint); @@ -898,9 +986,7 @@ impl MultiscalarMul for RistrettoPoint { J::Item: Borrow, { let extended_points = points.into_iter().map(|P| P.borrow().0); - RistrettoPoint( - EdwardsPoint::multiscalar_mul(scalars, extended_points) - ) + RistrettoPoint(EdwardsPoint::multiscalar_mul(scalars, extended_points)) } } @@ -914,7 +1000,7 @@ impl VartimeMultiscalarMul for RistrettoPoint { I::Item: Borrow, J: IntoIterator>, { - let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.borrow().0)); + let extended_points = points.into_iter().map(|opt_P| opt_P.map(|P| P.0)); EdwardsPoint::optional_multiscalar_mul(scalars, extended_points).map(RistrettoPoint) } @@ -925,7 +1011,7 @@ impl VartimeMultiscalarMul for RistrettoPoint { // decouple stability of the inner type from the stability of the // outer type. #[cfg(feature = "alloc")] -pub struct VartimeRistrettoPrecomputation(scalar_mul::precomputed_straus::VartimePrecomputedStraus); +pub struct VartimeRistrettoPrecomputation(crate::backend::VartimePrecomputedStraus); #[cfg(feature = "alloc")] impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { @@ -936,11 +1022,9 @@ impl VartimePrecomputedMultiscalarMul for VartimeRistrettoPrecomputation { I: IntoIterator, I::Item: Borrow, { - Self( - scalar_mul::precomputed_straus::VartimePrecomputedStraus::new( - static_points.into_iter().map(|P| P.borrow().0), - ), - ) + Self(crate::backend::VartimePrecomputedStraus::new( + static_points.into_iter().map(|P| P.borrow().0), + )) } fn optional_mixed_multiscalar_mul( @@ -974,9 +1058,9 @@ impl RistrettoPoint { A: &RistrettoPoint, b: &Scalar, ) -> RistrettoPoint { - RistrettoPoint( - EdwardsPoint::vartime_double_scalar_mul_basepoint(a, &A.0, b) - ) + RistrettoPoint(EdwardsPoint::vartime_double_scalar_mul_basepoint( + a, &A.0, b, + )) } } @@ -986,15 +1070,18 @@ impl RistrettoPoint { /// A precomputed table of multiples of the Ristretto basepoint is /// available in the `constants` module: /// ``` -/// use curve25519_dalek::constants; +/// use curve25519_dalek::constants::RISTRETTO_BASEPOINT_TABLE; /// use curve25519_dalek::scalar::Scalar; /// /// let a = Scalar::from(87329482u64); -/// let P = &a * &constants::RISTRETTO_BASEPOINT_TABLE; +/// let P = &a * RISTRETTO_BASEPOINT_TABLE; /// ``` +#[cfg(feature = "precomputed-tables")] #[derive(Clone)] +#[repr(transparent)] pub struct RistrettoBasepointTable(pub(crate) EdwardsBasepointTable); +#[cfg(feature = "precomputed-tables")] impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { type Output = RistrettoPoint; @@ -1003,6 +1090,7 @@ impl<'a, 'b> Mul<&'b Scalar> for &'a RistrettoBasepointTable { } } +#[cfg(feature = "precomputed-tables")] impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar { type Output = RistrettoPoint; @@ -1011,6 +1099,7 @@ impl<'a, 'b> Mul<&'a RistrettoBasepointTable> for &'b Scalar { } } +#[cfg(feature = "precomputed-tables")] impl RistrettoBasepointTable { /// Create a precomputed table of multiples of the given `basepoint`. pub fn create(basepoint: &RistrettoPoint) -> RistrettoBasepointTable { @@ -1033,9 +1122,6 @@ impl ConditionallySelectable for RistrettoPoint { /// # Example /// /// ``` - /// # extern crate subtle; - /// # extern crate curve25519_dalek; - /// # /// use subtle::ConditionallySelectable; /// use subtle::Choice; /// # @@ -1069,16 +1155,99 @@ impl ConditionallySelectable for RistrettoPoint { // ------------------------------------------------------------------------ impl Debug for CompressedRistretto { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "CompressedRistretto: {:?}", self.as_bytes()) } } impl Debug for RistrettoPoint { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let coset = self.coset4(); - write!(f, "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}", - coset[0], coset[1], coset[2], coset[3]) + write!( + f, + "RistrettoPoint: coset \n{:?}\n{:?}\n{:?}\n{:?}", + coset[0], coset[1], coset[2], coset[3] + ) + } +} + +// ------------------------------------------------------------------------ +// group traits +// ------------------------------------------------------------------------ + +// Use the full trait path to avoid Group::identity overlapping Identity::identity in the +// rest of the module (e.g. tests). +#[cfg(feature = "group")] +impl group::Group for RistrettoPoint { + type Scalar = Scalar; + + fn random(mut rng: impl RngCore) -> Self { + // NOTE: this is duplicated due to different `rng` bounds + let mut uniform_bytes = [0u8; 64]; + rng.fill_bytes(&mut uniform_bytes); + RistrettoPoint::from_uniform_bytes(&uniform_bytes) + } + + fn identity() -> Self { + Identity::identity() + } + + fn generator() -> Self { + constants::RISTRETTO_BASEPOINT_POINT + } + + fn is_identity(&self) -> Choice { + self.ct_eq(&Identity::identity()) + } + + fn double(&self) -> Self { + self + self + } +} + +#[cfg(feature = "group")] +impl GroupEncoding for RistrettoPoint { + type Repr = [u8; 32]; + + fn from_bytes(bytes: &Self::Repr) -> CtOption { + let (s_encoding_is_canonical, s_is_negative, s) = + decompress::step_1(&CompressedRistretto(*bytes)); + + let s_is_valid = s_encoding_is_canonical & !s_is_negative; + + let (ok, t_is_negative, y_is_zero, res) = decompress::step_2(s); + + CtOption::new(res, s_is_valid & ok & !t_is_negative & !y_is_zero) + } + + fn from_bytes_unchecked(bytes: &Self::Repr) -> CtOption { + // Just use the checked API; the checks we could skip aren't expensive. + Self::from_bytes(bytes) + } + + fn to_bytes(&self) -> Self::Repr { + self.compress().to_bytes() + } +} + +#[cfg(feature = "group")] +impl PrimeGroup for RistrettoPoint {} + +/// Ristretto has a cofactor of 1. +#[cfg(feature = "group")] +impl CofactorGroup for RistrettoPoint { + type Subgroup = Self; + + fn clear_cofactor(&self) -> Self::Subgroup { + *self + } + + fn into_subgroup(self) -> CtOption { + CtOption::new(self, Choice::from(1)) + } + + fn is_torsion_free(&self) -> Choice { + Choice::from(1) } } @@ -1086,12 +1255,14 @@ impl Debug for RistrettoPoint { // Zeroize traits // ------------------------------------------------------------------------ +#[cfg(feature = "zeroize")] impl Zeroize for CompressedRistretto { fn zeroize(&mut self) { self.0.zeroize(); } } +#[cfg(feature = "zeroize")] impl Zeroize for RistrettoPoint { fn zeroize(&mut self) { self.0.zeroize(); @@ -1104,13 +1275,10 @@ impl Zeroize for RistrettoPoint { #[cfg(test)] mod test { - use rand_core::OsRng; - - use scalar::Scalar; - use constants; - use edwards::CompressedEdwardsY; - use traits::{Identity}; use super::*; + use crate::edwards::CompressedEdwardsY; + + use rand_core::OsRng; #[test] #[cfg(feature = "serde")] @@ -1118,7 +1286,8 @@ mod test { use bincode; let encoded = bincode::serialize(&constants::RISTRETTO_BASEPOINT_POINT).unwrap(); - let enc_compressed = bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap(); + let enc_compressed = + bincode::serialize(&constants::RISTRETTO_BASEPOINT_COMPRESSED).unwrap(); assert_eq!(encoded, enc_compressed); // Check that the encoding is 32 bytes exactly @@ -1141,25 +1310,25 @@ mod test { let P = constants::RISTRETTO_BASEPOINT_POINT; let s = Scalar::from(999u64); - let P1 = &P * &s; - let P2 = &s * &P; + let P1 = P * s; + let P2 = s * P; assert!(P1.compress().as_bytes() == P2.compress().as_bytes()); } #[test] + #[cfg(feature = "alloc")] fn impl_sum() { - // Test that sum works for non-empty iterators let BASE = constants::RISTRETTO_BASEPOINT_POINT; let s1 = Scalar::from(999u64); - let P1 = &BASE * &s1; + let P1 = BASE * s1; let s2 = Scalar::from(333u64); - let P2 = &BASE * &s2; + let P2 = BASE * s2; - let vec = vec![P1.clone(), P2.clone()]; + let vec = vec![P1, P2]; let sum: RistrettoPoint = vec.iter().sum(); assert_eq!(sum, P1 + P2); @@ -1175,13 +1344,13 @@ mod test { let mapped = vec.iter().map(|x| x * s); let sum: RistrettoPoint = mapped.sum(); - assert_eq!(sum, &P1 * &s + &P2 * &s); + assert_eq!(sum, P1 * s + P2 * s); } #[test] fn decompress_negative_s_fails() { // constants::d is neg, so decompression should fail as |d| != d. - let bad_compressed = CompressedRistretto(constants::EDWARDS_D.to_bytes()); + let bad_compressed = CompressedRistretto(constants::EDWARDS_D.as_bytes()); assert!(bad_compressed.decompress().is_none()); } @@ -1209,7 +1378,7 @@ mod test { let bp_compressed_ristretto = constants::RISTRETTO_BASEPOINT_POINT.compress(); let bp_recaf = bp_compressed_ristretto.decompress().unwrap().0; // Check that bp_recaf differs from bp by a point of order 4 - let diff = &constants::RISTRETTO_BASEPOINT_POINT.0 - &bp_recaf; + let diff = constants::RISTRETTO_BASEPOINT_POINT.0 - bp_recaf; let diff4 = diff.mul_by_pow_2(2); assert_eq!(diff4.compress(), CompressedEdwardsY::identity()); } @@ -1219,27 +1388,75 @@ mod test { // Table of encodings of i*basepoint // Generated using ristretto.sage let compressed = [ - CompressedRistretto([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - CompressedRistretto([226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, 11, 106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118]), - CompressedRistretto([106, 73, 50, 16, 247, 73, 156, 209, 127, 236, 181, 16, 174, 12, 234, 35, 161, 16, 232, 213, 185, 1, 248, 172, 173, 211, 9, 92, 115, 163, 185, 25]), - CompressedRistretto([148, 116, 31, 93, 93, 82, 117, 94, 206, 79, 35, 240, 68, 238, 39, 213, 209, 234, 30, 43, 209, 150, 180, 98, 22, 107, 22, 21, 42, 157, 2, 89]), - CompressedRistretto([218, 128, 134, 39, 115, 53, 139, 70, 111, 250, 223, 224, 179, 41, 58, 179, 217, 253, 83, 197, 234, 108, 149, 83, 88, 245, 104, 50, 45, 175, 106, 87]), - CompressedRistretto([232, 130, 177, 49, 1, 107, 82, 193, 211, 51, 112, 128, 24, 124, 247, 104, 66, 62, 252, 203, 181, 23, 187, 73, 90, 184, 18, 196, 22, 15, 244, 78]), - CompressedRistretto([246, 71, 70, 211, 201, 43, 19, 5, 14, 216, 216, 2, 54, 167, 240, 0, 124, 59, 63, 150, 47, 91, 167, 147, 209, 154, 96, 30, 187, 29, 244, 3]), - CompressedRistretto([68, 245, 53, 32, 146, 110, 200, 31, 189, 90, 56, 120, 69, 190, 183, 223, 133, 169, 106, 36, 236, 225, 135, 56, 189, 207, 166, 167, 130, 42, 23, 109]), - CompressedRistretto([144, 50, 147, 216, 242, 40, 126, 190, 16, 226, 55, 77, 193, 165, 62, 11, 200, 135, 229, 146, 105, 159, 2, 208, 119, 213, 38, 60, 221, 85, 96, 28]), - CompressedRistretto([2, 98, 42, 206, 143, 115, 3, 163, 28, 175, 198, 63, 143, 196, 143, 220, 22, 225, 200, 200, 210, 52, 178, 240, 214, 104, 82, 130, 169, 7, 96, 49]), - CompressedRistretto([32, 112, 111, 215, 136, 178, 114, 10, 30, 210, 165, 218, 212, 149, 43, 1, 244, 19, 188, 240, 231, 86, 77, 232, 205, 200, 22, 104, 158, 45, 185, 95]), - CompressedRistretto([188, 232, 63, 139, 165, 221, 47, 165, 114, 134, 76, 36, 186, 24, 16, 249, 82, 43, 198, 0, 74, 254, 149, 135, 122, 199, 50, 65, 202, 253, 171, 66]), - CompressedRistretto([228, 84, 158, 225, 107, 154, 160, 48, 153, 202, 32, 140, 103, 173, 175, 202, 250, 76, 63, 62, 78, 83, 3, 222, 96, 38, 227, 202, 143, 248, 68, 96]), - CompressedRistretto([170, 82, 224, 0, 223, 46, 22, 245, 95, 177, 3, 47, 195, 59, 196, 39, 66, 218, 214, 189, 90, 143, 192, 190, 1, 103, 67, 108, 89, 72, 80, 31]), - CompressedRistretto([70, 55, 107, 128, 244, 9, 178, 157, 194, 181, 246, 240, 197, 37, 145, 153, 8, 150, 229, 113, 111, 65, 71, 124, 211, 0, 133, 171, 127, 16, 48, 30]), - CompressedRistretto([224, 196, 24, 247, 200, 217, 196, 205, 215, 57, 91, 147, 234, 18, 79, 58, 217, 144, 33, 187, 104, 29, 252, 51, 2, 169, 217, 154, 46, 83, 230, 78]), + CompressedRistretto([ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]), + CompressedRistretto([ + 226, 242, 174, 10, 106, 188, 78, 113, 168, 132, 169, 97, 197, 0, 81, 95, 88, 227, + 11, 106, 165, 130, 221, 141, 182, 166, 89, 69, 224, 141, 45, 118, + ]), + CompressedRistretto([ + 106, 73, 50, 16, 247, 73, 156, 209, 127, 236, 181, 16, 174, 12, 234, 35, 161, 16, + 232, 213, 185, 1, 248, 172, 173, 211, 9, 92, 115, 163, 185, 25, + ]), + CompressedRistretto([ + 148, 116, 31, 93, 93, 82, 117, 94, 206, 79, 35, 240, 68, 238, 39, 213, 209, 234, + 30, 43, 209, 150, 180, 98, 22, 107, 22, 21, 42, 157, 2, 89, + ]), + CompressedRistretto([ + 218, 128, 134, 39, 115, 53, 139, 70, 111, 250, 223, 224, 179, 41, 58, 179, 217, + 253, 83, 197, 234, 108, 149, 83, 88, 245, 104, 50, 45, 175, 106, 87, + ]), + CompressedRistretto([ + 232, 130, 177, 49, 1, 107, 82, 193, 211, 51, 112, 128, 24, 124, 247, 104, 66, 62, + 252, 203, 181, 23, 187, 73, 90, 184, 18, 196, 22, 15, 244, 78, + ]), + CompressedRistretto([ + 246, 71, 70, 211, 201, 43, 19, 5, 14, 216, 216, 2, 54, 167, 240, 0, 124, 59, 63, + 150, 47, 91, 167, 147, 209, 154, 96, 30, 187, 29, 244, 3, + ]), + CompressedRistretto([ + 68, 245, 53, 32, 146, 110, 200, 31, 189, 90, 56, 120, 69, 190, 183, 223, 133, 169, + 106, 36, 236, 225, 135, 56, 189, 207, 166, 167, 130, 42, 23, 109, + ]), + CompressedRistretto([ + 144, 50, 147, 216, 242, 40, 126, 190, 16, 226, 55, 77, 193, 165, 62, 11, 200, 135, + 229, 146, 105, 159, 2, 208, 119, 213, 38, 60, 221, 85, 96, 28, + ]), + CompressedRistretto([ + 2, 98, 42, 206, 143, 115, 3, 163, 28, 175, 198, 63, 143, 196, 143, 220, 22, 225, + 200, 200, 210, 52, 178, 240, 214, 104, 82, 130, 169, 7, 96, 49, + ]), + CompressedRistretto([ + 32, 112, 111, 215, 136, 178, 114, 10, 30, 210, 165, 218, 212, 149, 43, 1, 244, 19, + 188, 240, 231, 86, 77, 232, 205, 200, 22, 104, 158, 45, 185, 95, + ]), + CompressedRistretto([ + 188, 232, 63, 139, 165, 221, 47, 165, 114, 134, 76, 36, 186, 24, 16, 249, 82, 43, + 198, 0, 74, 254, 149, 135, 122, 199, 50, 65, 202, 253, 171, 66, + ]), + CompressedRistretto([ + 228, 84, 158, 225, 107, 154, 160, 48, 153, 202, 32, 140, 103, 173, 175, 202, 250, + 76, 63, 62, 78, 83, 3, 222, 96, 38, 227, 202, 143, 248, 68, 96, + ]), + CompressedRistretto([ + 170, 82, 224, 0, 223, 46, 22, 245, 95, 177, 3, 47, 195, 59, 196, 39, 66, 218, 214, + 189, 90, 143, 192, 190, 1, 103, 67, 108, 89, 72, 80, 31, + ]), + CompressedRistretto([ + 70, 55, 107, 128, 244, 9, 178, 157, 194, 181, 246, 240, 197, 37, 145, 153, 8, 150, + 229, 113, 111, 65, 71, 124, 211, 0, 133, 171, 127, 16, 48, 30, + ]), + CompressedRistretto([ + 224, 196, 24, 247, 200, 217, 196, 205, 215, 57, 91, 147, 234, 18, 79, 58, 217, 144, + 33, 187, 104, 29, 252, 51, 2, 169, 217, 154, 46, 83, 230, 78, + ]), ]; let mut bp = RistrettoPoint::identity(); - for i in 0..16 { - assert_eq!(bp.compress(), compressed[i]); - bp = &bp + &constants::RISTRETTO_BASEPOINT_POINT; + for point in compressed { + assert_eq!(bp.compress(), point); + bp += constants::RISTRETTO_BASEPOINT_POINT; } } @@ -1247,19 +1464,18 @@ mod test { fn four_torsion_basepoint() { let bp = constants::RISTRETTO_BASEPOINT_POINT; let bp_coset = bp.coset4(); - for i in 0..4 { - assert_eq!(bp, RistrettoPoint(bp_coset[i])); + for point in bp_coset { + assert_eq!(bp, RistrettoPoint(point)); } } #[test] fn four_torsion_random() { let mut rng = OsRng; - let B = &constants::RISTRETTO_BASEPOINT_TABLE; - let P = B * &Scalar::random(&mut rng); + let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng)); let P_coset = P.coset4(); - for i in 0..4 { - assert_eq!(P, RistrettoPoint(P_coset[i])); + for point in P_coset { + assert_eq!(P, RistrettoPoint(point)); } } @@ -1271,41 +1487,137 @@ mod test { // ristretto.sage does not mask the high bit of a field element. When the high bit is set, // the ristretto.sage elligator implementation gives different results, since it takes a // different field element as input. - let bytes: [[u8;32]; 16] = [ - [184, 249, 135, 49, 253, 123, 89, 113, 67, 160, 6, 239, 7, 105, 211, 41, 192, 249, 185, 57, 9, 102, 70, 198, 15, 127, 7, 26, 160, 102, 134, 71], - [229, 14, 241, 227, 75, 9, 118, 60, 128, 153, 226, 21, 183, 217, 91, 136, 98, 0, 231, 156, 124, 77, 82, 139, 142, 134, 164, 169, 169, 62, 250, 52], - [115, 109, 36, 220, 180, 223, 99, 6, 204, 169, 19, 29, 169, 68, 84, 23, 21, 109, 189, 149, 127, 205, 91, 102, 172, 35, 112, 35, 134, 69, 186, 34], - [16, 49, 96, 107, 171, 199, 164, 9, 129, 16, 64, 62, 241, 63, 132, 173, 209, 160, 112, 215, 105, 50, 157, 81, 253, 105, 1, 154, 229, 25, 120, 83], - [156, 131, 161, 162, 236, 251, 5, 187, 167, 171, 17, 178, 148, 210, 90, 207, 86, 21, 79, 161, 167, 215, 234, 1, 136, 242, 182, 248, 38, 85, 79, 86], - [251, 177, 124, 54, 18, 101, 75, 235, 245, 186, 19, 46, 133, 157, 229, 64, 10, 136, 181, 185, 78, 144, 254, 167, 137, 49, 107, 10, 61, 10, 21, 25], - [232, 193, 20, 68, 240, 77, 186, 77, 183, 40, 44, 86, 150, 31, 198, 212, 76, 81, 3, 217, 197, 8, 126, 128, 126, 152, 164, 208, 153, 44, 189, 77], - [173, 229, 149, 177, 37, 230, 30, 69, 61, 56, 172, 190, 219, 115, 167, 194, 71, 134, 59, 75, 28, 244, 118, 26, 162, 97, 64, 16, 15, 189, 30, 64], - [106, 71, 61, 107, 250, 117, 42, 151, 91, 202, 212, 100, 52, 188, 190, 21, 125, 218, 31, 18, 253, 241, 160, 133, 57, 242, 3, 164, 189, 68, 111, 75], - [112, 204, 182, 90, 220, 198, 120, 73, 173, 107, 193, 17, 227, 40, 162, 36, 150, 141, 235, 55, 172, 183, 12, 39, 194, 136, 43, 153, 244, 118, 91, 89], - [111, 24, 203, 123, 254, 189, 11, 162, 51, 196, 163, 136, 204, 143, 10, 222, 33, 112, 81, 205, 34, 35, 8, 66, 90, 6, 164, 58, 170, 177, 34, 25], - [225, 183, 30, 52, 236, 82, 6, 183, 109, 25, 227, 181, 25, 82, 41, 193, 80, 77, 161, 80, 242, 203, 79, 204, 136, 245, 131, 110, 237, 106, 3, 58], - [207, 246, 38, 56, 30, 86, 176, 90, 27, 200, 61, 42, 221, 27, 56, 210, 79, 178, 189, 120, 68, 193, 120, 167, 77, 185, 53, 197, 124, 128, 191, 126], - [1, 136, 215, 80, 240, 46, 63, 147, 16, 244, 230, 207, 82, 189, 74, 50, 106, 169, 138, 86, 30, 131, 214, 202, 166, 125, 251, 228, 98, 24, 36, 21], - [210, 207, 228, 56, 155, 116, 207, 54, 84, 195, 251, 215, 249, 199, 116, 75, 109, 239, 196, 251, 194, 246, 252, 228, 70, 146, 156, 35, 25, 39, 241, 4], - [34, 116, 123, 9, 8, 40, 93, 189, 9, 103, 57, 103, 66, 227, 3, 2, 157, 107, 134, 219, 202, 74, 230, 154, 78, 107, 219, 195, 214, 14, 84, 80], + let bytes: [[u8; 32]; 16] = [ + [ + 184, 249, 135, 49, 253, 123, 89, 113, 67, 160, 6, 239, 7, 105, 211, 41, 192, 249, + 185, 57, 9, 102, 70, 198, 15, 127, 7, 26, 160, 102, 134, 71, + ], + [ + 229, 14, 241, 227, 75, 9, 118, 60, 128, 153, 226, 21, 183, 217, 91, 136, 98, 0, + 231, 156, 124, 77, 82, 139, 142, 134, 164, 169, 169, 62, 250, 52, + ], + [ + 115, 109, 36, 220, 180, 223, 99, 6, 204, 169, 19, 29, 169, 68, 84, 23, 21, 109, + 189, 149, 127, 205, 91, 102, 172, 35, 112, 35, 134, 69, 186, 34, + ], + [ + 16, 49, 96, 107, 171, 199, 164, 9, 129, 16, 64, 62, 241, 63, 132, 173, 209, 160, + 112, 215, 105, 50, 157, 81, 253, 105, 1, 154, 229, 25, 120, 83, + ], + [ + 156, 131, 161, 162, 236, 251, 5, 187, 167, 171, 17, 178, 148, 210, 90, 207, 86, 21, + 79, 161, 167, 215, 234, 1, 136, 242, 182, 248, 38, 85, 79, 86, + ], + [ + 251, 177, 124, 54, 18, 101, 75, 235, 245, 186, 19, 46, 133, 157, 229, 64, 10, 136, + 181, 185, 78, 144, 254, 167, 137, 49, 107, 10, 61, 10, 21, 25, + ], + [ + 232, 193, 20, 68, 240, 77, 186, 77, 183, 40, 44, 86, 150, 31, 198, 212, 76, 81, 3, + 217, 197, 8, 126, 128, 126, 152, 164, 208, 153, 44, 189, 77, + ], + [ + 173, 229, 149, 177, 37, 230, 30, 69, 61, 56, 172, 190, 219, 115, 167, 194, 71, 134, + 59, 75, 28, 244, 118, 26, 162, 97, 64, 16, 15, 189, 30, 64, + ], + [ + 106, 71, 61, 107, 250, 117, 42, 151, 91, 202, 212, 100, 52, 188, 190, 21, 125, 218, + 31, 18, 253, 241, 160, 133, 57, 242, 3, 164, 189, 68, 111, 75, + ], + [ + 112, 204, 182, 90, 220, 198, 120, 73, 173, 107, 193, 17, 227, 40, 162, 36, 150, + 141, 235, 55, 172, 183, 12, 39, 194, 136, 43, 153, 244, 118, 91, 89, + ], + [ + 111, 24, 203, 123, 254, 189, 11, 162, 51, 196, 163, 136, 204, 143, 10, 222, 33, + 112, 81, 205, 34, 35, 8, 66, 90, 6, 164, 58, 170, 177, 34, 25, + ], + [ + 225, 183, 30, 52, 236, 82, 6, 183, 109, 25, 227, 181, 25, 82, 41, 193, 80, 77, 161, + 80, 242, 203, 79, 204, 136, 245, 131, 110, 237, 106, 3, 58, + ], + [ + 207, 246, 38, 56, 30, 86, 176, 90, 27, 200, 61, 42, 221, 27, 56, 210, 79, 178, 189, + 120, 68, 193, 120, 167, 77, 185, 53, 197, 124, 128, 191, 126, + ], + [ + 1, 136, 215, 80, 240, 46, 63, 147, 16, 244, 230, 207, 82, 189, 74, 50, 106, 169, + 138, 86, 30, 131, 214, 202, 166, 125, 251, 228, 98, 24, 36, 21, + ], + [ + 210, 207, 228, 56, 155, 116, 207, 54, 84, 195, 251, 215, 249, 199, 116, 75, 109, + 239, 196, 251, 194, 246, 252, 228, 70, 146, 156, 35, 25, 39, 241, 4, + ], + [ + 34, 116, 123, 9, 8, 40, 93, 189, 9, 103, 57, 103, 66, 227, 3, 2, 157, 107, 134, + 219, 202, 74, 230, 154, 78, 107, 219, 195, 214, 14, 84, 80, + ], ]; let encoded_images: [CompressedRistretto; 16] = [ - CompressedRistretto([176, 157, 237, 97, 66, 29, 140, 166, 168, 94, 26, 157, 212, 216, 229, 160, 195, 246, 232, 239, 169, 112, 63, 193, 64, 32, 152, 69, 11, 190, 246, 86]), - CompressedRistretto([234, 141, 77, 203, 181, 225, 250, 74, 171, 62, 15, 118, 78, 212, 150, 19, 131, 14, 188, 238, 194, 244, 141, 138, 166, 162, 83, 122, 228, 201, 19, 26]), - CompressedRistretto([232, 231, 51, 92, 5, 168, 80, 36, 173, 179, 104, 68, 186, 149, 68, 40, 140, 170, 27, 103, 99, 140, 21, 242, 43, 62, 250, 134, 208, 255, 61, 89]), - CompressedRistretto([208, 120, 140, 129, 177, 179, 237, 159, 252, 160, 28, 13, 206, 5, 211, 241, 192, 218, 1, 97, 130, 241, 20, 169, 119, 46, 246, 29, 79, 80, 77, 84]), - CompressedRistretto([202, 11, 236, 145, 58, 12, 181, 157, 209, 6, 213, 88, 75, 147, 11, 119, 191, 139, 47, 142, 33, 36, 153, 193, 223, 183, 178, 8, 205, 120, 248, 110]), - CompressedRistretto([26, 66, 231, 67, 203, 175, 116, 130, 32, 136, 62, 253, 215, 46, 5, 214, 166, 248, 108, 237, 216, 71, 244, 173, 72, 133, 82, 6, 143, 240, 104, 41]), - CompressedRistretto([40, 157, 102, 96, 201, 223, 200, 197, 150, 181, 106, 83, 103, 126, 143, 33, 145, 230, 78, 6, 171, 146, 210, 143, 112, 5, 245, 23, 183, 138, 18, 120]), - CompressedRistretto([220, 37, 27, 203, 239, 196, 176, 131, 37, 66, 188, 243, 185, 250, 113, 23, 167, 211, 154, 243, 168, 215, 54, 171, 159, 36, 195, 81, 13, 150, 43, 43]), - CompressedRistretto([232, 121, 176, 222, 183, 196, 159, 90, 238, 193, 105, 52, 101, 167, 244, 170, 121, 114, 196, 6, 67, 152, 80, 185, 221, 7, 83, 105, 176, 208, 224, 121]), - CompressedRistretto([226, 181, 183, 52, 241, 163, 61, 179, 221, 207, 220, 73, 245, 242, 25, 236, 67, 84, 179, 222, 167, 62, 167, 182, 32, 9, 92, 30, 165, 127, 204, 68]), - CompressedRistretto([226, 119, 16, 242, 200, 139, 240, 87, 11, 222, 92, 146, 156, 243, 46, 119, 65, 59, 1, 248, 92, 183, 50, 175, 87, 40, 206, 53, 208, 220, 148, 13]), - CompressedRistretto([70, 240, 79, 112, 54, 157, 228, 146, 74, 122, 216, 88, 232, 62, 158, 13, 14, 146, 115, 117, 176, 222, 90, 225, 244, 23, 94, 190, 150, 7, 136, 96]), - CompressedRistretto([22, 71, 241, 103, 45, 193, 195, 144, 183, 101, 154, 50, 39, 68, 49, 110, 51, 44, 62, 0, 229, 113, 72, 81, 168, 29, 73, 106, 102, 40, 132, 24]), - CompressedRistretto([196, 133, 107, 11, 130, 105, 74, 33, 204, 171, 133, 221, 174, 193, 241, 36, 38, 179, 196, 107, 219, 185, 181, 253, 228, 47, 155, 42, 231, 73, 41, 78]), - CompressedRistretto([58, 255, 225, 197, 115, 208, 160, 143, 39, 197, 82, 69, 143, 235, 92, 170, 74, 40, 57, 11, 171, 227, 26, 185, 217, 207, 90, 185, 197, 190, 35, 60]), - CompressedRistretto([88, 43, 92, 118, 223, 136, 105, 145, 238, 186, 115, 8, 214, 112, 153, 253, 38, 108, 205, 230, 157, 130, 11, 66, 101, 85, 253, 110, 110, 14, 148, 112]), + CompressedRistretto([ + 176, 157, 237, 97, 66, 29, 140, 166, 168, 94, 26, 157, 212, 216, 229, 160, 195, + 246, 232, 239, 169, 112, 63, 193, 64, 32, 152, 69, 11, 190, 246, 86, + ]), + CompressedRistretto([ + 234, 141, 77, 203, 181, 225, 250, 74, 171, 62, 15, 118, 78, 212, 150, 19, 131, 14, + 188, 238, 194, 244, 141, 138, 166, 162, 83, 122, 228, 201, 19, 26, + ]), + CompressedRistretto([ + 232, 231, 51, 92, 5, 168, 80, 36, 173, 179, 104, 68, 186, 149, 68, 40, 140, 170, + 27, 103, 99, 140, 21, 242, 43, 62, 250, 134, 208, 255, 61, 89, + ]), + CompressedRistretto([ + 208, 120, 140, 129, 177, 179, 237, 159, 252, 160, 28, 13, 206, 5, 211, 241, 192, + 218, 1, 97, 130, 241, 20, 169, 119, 46, 246, 29, 79, 80, 77, 84, + ]), + CompressedRistretto([ + 202, 11, 236, 145, 58, 12, 181, 157, 209, 6, 213, 88, 75, 147, 11, 119, 191, 139, + 47, 142, 33, 36, 153, 193, 223, 183, 178, 8, 205, 120, 248, 110, + ]), + CompressedRistretto([ + 26, 66, 231, 67, 203, 175, 116, 130, 32, 136, 62, 253, 215, 46, 5, 214, 166, 248, + 108, 237, 216, 71, 244, 173, 72, 133, 82, 6, 143, 240, 104, 41, + ]), + CompressedRistretto([ + 40, 157, 102, 96, 201, 223, 200, 197, 150, 181, 106, 83, 103, 126, 143, 33, 145, + 230, 78, 6, 171, 146, 210, 143, 112, 5, 245, 23, 183, 138, 18, 120, + ]), + CompressedRistretto([ + 220, 37, 27, 203, 239, 196, 176, 131, 37, 66, 188, 243, 185, 250, 113, 23, 167, + 211, 154, 243, 168, 215, 54, 171, 159, 36, 195, 81, 13, 150, 43, 43, + ]), + CompressedRistretto([ + 232, 121, 176, 222, 183, 196, 159, 90, 238, 193, 105, 52, 101, 167, 244, 170, 121, + 114, 196, 6, 67, 152, 80, 185, 221, 7, 83, 105, 176, 208, 224, 121, + ]), + CompressedRistretto([ + 226, 181, 183, 52, 241, 163, 61, 179, 221, 207, 220, 73, 245, 242, 25, 236, 67, 84, + 179, 222, 167, 62, 167, 182, 32, 9, 92, 30, 165, 127, 204, 68, + ]), + CompressedRistretto([ + 226, 119, 16, 242, 200, 139, 240, 87, 11, 222, 92, 146, 156, 243, 46, 119, 65, 59, + 1, 248, 92, 183, 50, 175, 87, 40, 206, 53, 208, 220, 148, 13, + ]), + CompressedRistretto([ + 70, 240, 79, 112, 54, 157, 228, 146, 74, 122, 216, 88, 232, 62, 158, 13, 14, 146, + 115, 117, 176, 222, 90, 225, 244, 23, 94, 190, 150, 7, 136, 96, + ]), + CompressedRistretto([ + 22, 71, 241, 103, 45, 193, 195, 144, 183, 101, 154, 50, 39, 68, 49, 110, 51, 44, + 62, 0, 229, 113, 72, 81, 168, 29, 73, 106, 102, 40, 132, 24, + ]), + CompressedRistretto([ + 196, 133, 107, 11, 130, 105, 74, 33, 204, 171, 133, 221, 174, 193, 241, 36, 38, + 179, 196, 107, 219, 185, 181, 253, 228, 47, 155, 42, 231, 73, 41, 78, + ]), + CompressedRistretto([ + 58, 255, 225, 197, 115, 208, 160, 143, 39, 197, 82, 69, 143, 235, 92, 170, 74, 40, + 57, 11, 171, 227, 26, 185, 217, 207, 90, 185, 197, 190, 35, 60, + ]), + CompressedRistretto([ + 88, 43, 92, 118, 223, 136, 105, 145, 238, 186, 115, 8, 214, 112, 153, 253, 38, 108, + 205, 230, 157, 130, 11, 66, 101, 85, 253, 110, 110, 14, 148, 112, + ]), ]; for i in 0..16 { let r_0 = FieldElement::from_bytes(&bytes[i]); @@ -1314,12 +1626,179 @@ mod test { } } + // Known answer tests for the one-way mapping function in the Ristretto RFC + #[test] + fn one_way_map() { + // These inputs are from + // https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-ristretto255-decaf448-04#appendix-A.3 + let test_vectors: &[([u8; 64], CompressedRistretto)] = &[ + ( + [ + 0x5d, 0x1b, 0xe0, 0x9e, 0x3d, 0x0c, 0x82, 0xfc, 0x53, 0x81, 0x12, 0x49, 0x0e, + 0x35, 0x70, 0x19, 0x79, 0xd9, 0x9e, 0x06, 0xca, 0x3e, 0x2b, 0x5b, 0x54, 0xbf, + 0xfe, 0x8b, 0x4d, 0xc7, 0x72, 0xc1, 0x4d, 0x98, 0xb6, 0x96, 0xa1, 0xbb, 0xfb, + 0x5c, 0xa3, 0x2c, 0x43, 0x6c, 0xc6, 0x1c, 0x16, 0x56, 0x37, 0x90, 0x30, 0x6c, + 0x79, 0xea, 0xca, 0x77, 0x05, 0x66, 0x8b, 0x47, 0xdf, 0xfe, 0x5b, 0xb6, + ], + CompressedRistretto([ + 0x30, 0x66, 0xf8, 0x2a, 0x1a, 0x74, 0x7d, 0x45, 0x12, 0x0d, 0x17, 0x40, 0xf1, + 0x43, 0x58, 0x53, 0x1a, 0x8f, 0x04, 0xbb, 0xff, 0xe6, 0xa8, 0x19, 0xf8, 0x6d, + 0xfe, 0x50, 0xf4, 0x4a, 0x0a, 0x46, + ]), + ), + ( + [ + 0xf1, 0x16, 0xb3, 0x4b, 0x8f, 0x17, 0xce, 0xb5, 0x6e, 0x87, 0x32, 0xa6, 0x0d, + 0x91, 0x3d, 0xd1, 0x0c, 0xce, 0x47, 0xa6, 0xd5, 0x3b, 0xee, 0x92, 0x04, 0xbe, + 0x8b, 0x44, 0xf6, 0x67, 0x8b, 0x27, 0x01, 0x02, 0xa5, 0x69, 0x02, 0xe2, 0x48, + 0x8c, 0x46, 0x12, 0x0e, 0x92, 0x76, 0xcf, 0xe5, 0x46, 0x38, 0x28, 0x6b, 0x9e, + 0x4b, 0x3c, 0xdb, 0x47, 0x0b, 0x54, 0x2d, 0x46, 0xc2, 0x06, 0x8d, 0x38, + ], + CompressedRistretto([ + 0xf2, 0x6e, 0x5b, 0x6f, 0x7d, 0x36, 0x2d, 0x2d, 0x2a, 0x94, 0xc5, 0xd0, 0xe7, + 0x60, 0x2c, 0xb4, 0x77, 0x3c, 0x95, 0xa2, 0xe5, 0xc3, 0x1a, 0x64, 0xf1, 0x33, + 0x18, 0x9f, 0xa7, 0x6e, 0xd6, 0x1b, + ]), + ), + ( + [ + 0x84, 0x22, 0xe1, 0xbb, 0xda, 0xab, 0x52, 0x93, 0x8b, 0x81, 0xfd, 0x60, 0x2e, + 0xff, 0xb6, 0xf8, 0x91, 0x10, 0xe1, 0xe5, 0x72, 0x08, 0xad, 0x12, 0xd9, 0xad, + 0x76, 0x7e, 0x2e, 0x25, 0x51, 0x0c, 0x27, 0x14, 0x07, 0x75, 0xf9, 0x33, 0x70, + 0x88, 0xb9, 0x82, 0xd8, 0x3d, 0x7f, 0xcf, 0x0b, 0x2f, 0xa1, 0xed, 0xff, 0xe5, + 0x19, 0x52, 0xcb, 0xe7, 0x36, 0x5e, 0x95, 0xc8, 0x6e, 0xaf, 0x32, 0x5c, + ], + CompressedRistretto([ + 0x00, 0x6c, 0xcd, 0x2a, 0x9e, 0x68, 0x67, 0xe6, 0xa2, 0xc5, 0xce, 0xa8, 0x3d, + 0x33, 0x02, 0xcc, 0x9d, 0xe1, 0x28, 0xdd, 0x2a, 0x9a, 0x57, 0xdd, 0x8e, 0xe7, + 0xb9, 0xd7, 0xff, 0xe0, 0x28, 0x26, + ]), + ), + ( + [ + 0xac, 0x22, 0x41, 0x51, 0x29, 0xb6, 0x14, 0x27, 0xbf, 0x46, 0x4e, 0x17, 0xba, + 0xee, 0x8d, 0xb6, 0x59, 0x40, 0xc2, 0x33, 0xb9, 0x8a, 0xfc, 0xe8, 0xd1, 0x7c, + 0x57, 0xbe, 0xeb, 0x78, 0x76, 0xc2, 0x15, 0x0d, 0x15, 0xaf, 0x1c, 0xb1, 0xfb, + 0x82, 0x4b, 0xbd, 0x14, 0x95, 0x5f, 0x2b, 0x57, 0xd0, 0x8d, 0x38, 0x8a, 0xab, + 0x43, 0x1a, 0x39, 0x1c, 0xfc, 0x33, 0xd5, 0xba, 0xfb, 0x5d, 0xbb, 0xaf, + ], + CompressedRistretto([ + 0xf8, 0xf0, 0xc8, 0x7c, 0xf2, 0x37, 0x95, 0x3c, 0x58, 0x90, 0xae, 0xc3, 0x99, + 0x81, 0x69, 0x00, 0x5d, 0xae, 0x3e, 0xca, 0x1f, 0xbb, 0x04, 0x54, 0x8c, 0x63, + 0x59, 0x53, 0xc8, 0x17, 0xf9, 0x2a, + ]), + ), + ( + [ + 0x16, 0x5d, 0x69, 0x7a, 0x1e, 0xf3, 0xd5, 0xcf, 0x3c, 0x38, 0x56, 0x5b, 0xee, + 0xfc, 0xf8, 0x8c, 0x0f, 0x28, 0x2b, 0x8e, 0x7d, 0xbd, 0x28, 0x54, 0x4c, 0x48, + 0x34, 0x32, 0xf1, 0xce, 0xc7, 0x67, 0x5d, 0xeb, 0xea, 0x8e, 0xbb, 0x4e, 0x5f, + 0xe7, 0xd6, 0xf6, 0xe5, 0xdb, 0x15, 0xf1, 0x55, 0x87, 0xac, 0x4d, 0x4d, 0x4a, + 0x1d, 0xe7, 0x19, 0x1e, 0x0c, 0x1c, 0xa6, 0x66, 0x4a, 0xbc, 0xc4, 0x13, + ], + CompressedRistretto([ + 0xae, 0x81, 0xe7, 0xde, 0xdf, 0x20, 0xa4, 0x97, 0xe1, 0x0c, 0x30, 0x4a, 0x76, + 0x5c, 0x17, 0x67, 0xa4, 0x2d, 0x6e, 0x06, 0x02, 0x97, 0x58, 0xd2, 0xd7, 0xe8, + 0xef, 0x7c, 0xc4, 0xc4, 0x11, 0x79, + ]), + ), + ( + [ + 0xa8, 0x36, 0xe6, 0xc9, 0xa9, 0xca, 0x9f, 0x1e, 0x8d, 0x48, 0x62, 0x73, 0xad, + 0x56, 0xa7, 0x8c, 0x70, 0xcf, 0x18, 0xf0, 0xce, 0x10, 0xab, 0xb1, 0xc7, 0x17, + 0x2d, 0xdd, 0x60, 0x5d, 0x7f, 0xd2, 0x97, 0x98, 0x54, 0xf4, 0x7a, 0xe1, 0xcc, + 0xf2, 0x04, 0xa3, 0x31, 0x02, 0x09, 0x5b, 0x42, 0x00, 0xe5, 0xbe, 0xfc, 0x04, + 0x65, 0xac, 0xcc, 0x26, 0x31, 0x75, 0x48, 0x5f, 0x0e, 0x17, 0xea, 0x5c, + ], + CompressedRistretto([ + 0xe2, 0x70, 0x56, 0x52, 0xff, 0x9f, 0x5e, 0x44, 0xd3, 0xe8, 0x41, 0xbf, 0x1c, + 0x25, 0x1c, 0xf7, 0xdd, 0xdb, 0x77, 0xd1, 0x40, 0x87, 0x0d, 0x1a, 0xb2, 0xed, + 0x64, 0xf1, 0xa9, 0xce, 0x86, 0x28, + ]), + ), + ( + [ + 0x2c, 0xdc, 0x11, 0xea, 0xeb, 0x95, 0xda, 0xf0, 0x11, 0x89, 0x41, 0x7c, 0xdd, + 0xdb, 0xf9, 0x59, 0x52, 0x99, 0x3a, 0xa9, 0xcb, 0x9c, 0x64, 0x0e, 0xb5, 0x05, + 0x8d, 0x09, 0x70, 0x2c, 0x74, 0x62, 0x2c, 0x99, 0x65, 0xa6, 0x97, 0xa3, 0xb3, + 0x45, 0xec, 0x24, 0xee, 0x56, 0x33, 0x5b, 0x55, 0x6e, 0x67, 0x7b, 0x30, 0xe6, + 0xf9, 0x0a, 0xc7, 0x7d, 0x78, 0x10, 0x64, 0xf8, 0x66, 0xa3, 0xc9, 0x82, + ], + CompressedRistretto([ + 0x80, 0xbd, 0x07, 0x26, 0x25, 0x11, 0xcd, 0xde, 0x48, 0x63, 0xf8, 0xa7, 0x43, + 0x4c, 0xef, 0x69, 0x67, 0x50, 0x68, 0x1c, 0xb9, 0x51, 0x0e, 0xea, 0x55, 0x70, + 0x88, 0xf7, 0x6d, 0x9e, 0x50, 0x65, + ]), + ), + ( + [ + 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ], + CompressedRistretto([ + 0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb, + 0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79, + 0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f, + ]), + ), + ( + [ + 0xed, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + ], + CompressedRistretto([ + 0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb, + 0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79, + 0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f, + ]), + ), + ( + [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + ], + CompressedRistretto([ + 0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb, + 0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79, + 0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f, + ]), + ), + ( + [ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, + ], + CompressedRistretto([ + 0x30, 0x42, 0x82, 0x79, 0x10, 0x23, 0xb7, 0x31, 0x28, 0xd2, 0x77, 0xbd, 0xcb, + 0x5c, 0x77, 0x46, 0xef, 0x2e, 0xac, 0x08, 0xdd, 0xe9, 0xf2, 0x98, 0x33, 0x79, + 0xcb, 0x8e, 0x5e, 0xf0, 0x51, 0x7f, + ]), + ), + ]; + // Check that onewaymap(input) == output for all the above vectors + for (input, output) in test_vectors { + let Q = RistrettoPoint::from_uniform_bytes(input); + assert_eq!(&Q.compress(), output); + } + } + #[test] fn random_roundtrip() { let mut rng = OsRng; - let B = &constants::RISTRETTO_BASEPOINT_TABLE; for _ in 0..100 { - let P = B * &Scalar::random(&mut rng); + let P = RistrettoPoint::mul_base(&Scalar::random(&mut rng)); let compressed_P = P.compress(); let Q = compressed_P.decompress().unwrap(); assert_eq!(P, Q); @@ -1327,11 +1806,14 @@ mod test { } #[test] + #[cfg(all(feature = "alloc", feature = "rand_core"))] fn double_and_compress_1024_random_points() { let mut rng = OsRng; - let points: Vec = - (0..1024).map(|_| RistrettoPoint::random(&mut rng)).collect(); + let mut points: Vec = (0..1024) + .map(|_| RistrettoPoint::random(&mut rng)) + .collect(); + points[500] = RistrettoPoint::identity(); let compressed = RistrettoPoint::double_and_compress_batch(&points); @@ -1341,11 +1823,10 @@ mod test { } #[test] + #[cfg(feature = "alloc")] fn vartime_precomputed_vs_nonprecomputed_multiscalar() { let mut rng = rand::thread_rng(); - let B = &::constants::RISTRETTO_BASEPOINT_TABLE; - let static_scalars = (0..128) .map(|_| Scalar::random(&mut rng)) .collect::>(); @@ -1360,8 +1841,14 @@ mod test { .map(|s| s * s) .sum(); - let static_points = static_scalars.iter().map(|s| s * B).collect::>(); - let dynamic_points = dynamic_scalars.iter().map(|s| s * B).collect::>(); + let static_points = static_scalars + .iter() + .map(RistrettoPoint::mul_base) + .collect::>(); + let dynamic_points = dynamic_scalars + .iter() + .map(RistrettoPoint::mul_base) + .collect::>(); let precomputation = VartimeRistrettoPrecomputation::new(static_points.iter()); @@ -1371,13 +1858,13 @@ mod test { &dynamic_points, ); - use traits::VartimeMultiscalarMul; + use crate::traits::VartimeMultiscalarMul; let Q = RistrettoPoint::vartime_multiscalar_mul( static_scalars.iter().chain(dynamic_scalars.iter()), static_points.iter().chain(dynamic_points.iter()), ); - let R = &check_scalar * B; + let R = RistrettoPoint::mul_base(&check_scalar); assert_eq!(P.compress(), R.compress()); assert_eq!(Q.compress(), R.compress()); diff --git a/src/scalar.rs b/curve25519-dalek/src/scalar.rs similarity index 53% rename from src/scalar.rs rename to curve25519-dalek/src/scalar.rs index 5be650b7e..def7cecc7 100644 --- a/src/scalar.rs +++ b/curve25519-dalek/src/scalar.rs @@ -36,8 +36,8 @@ //! ``` //! use curve25519_dalek::scalar::Scalar; //! -//! let one_as_bytes: [u8; 32] = Scalar::one().to_bytes(); -//! let a: Option = Scalar::from_canonical_bytes(one_as_bytes); +//! let one_as_bytes: [u8; 32] = Scalar::ONE.to_bytes(); +//! let a: Option = Scalar::from_canonical_bytes(one_as_bytes).into(); //! //! assert!(a.is_some()); //! ``` @@ -54,7 +54,7 @@ //! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, //! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, //! ]; -//! let a: Option = Scalar::from_canonical_bytes(l_plus_two_bytes); +//! let a: Option = Scalar::from_canonical_bytes(l_plus_two_bytes).into(); //! //! assert!(a.is_none()); //! ``` @@ -76,24 +76,20 @@ //! ]; //! let a: Scalar = Scalar::from_bytes_mod_order(l_plus_two_bytes); //! -//! let two: Scalar = Scalar::one() + Scalar::one(); +//! let two: Scalar = Scalar::ONE + Scalar::ONE; //! //! assert!(a == two); //! ``` //! //! There is also a constructor that reduces a \\(512\\)-bit integer, -//! [`Scalar::from_bytes_mod_order_wide`](struct.Scalar.html#method.from_bytes_mod_order_wide). +//! [`Scalar::from_bytes_mod_order_wide`]. //! //! To construct a `Scalar` as the hash of some input data, use -//! [`Scalar::hash_from_bytes`](struct.Scalar.html#method.hash_from_bytes), -//! which takes a buffer, or -//! [`Scalar::from_hash`](struct.Scalar.html#method.from_hash), -//! which allows an IUF API. +//! [`Scalar::hash_from_bytes`], which takes a buffer, or +//! [`Scalar::from_hash`], which allows an IUF API. //! -//! ``` -//! # extern crate curve25519_dalek; -//! # extern crate sha2; -//! # +#![cfg_attr(feature = "digest", doc = "```")] +#![cfg_attr(not(feature = "digest"), doc = "```ignore")] //! # fn main() { //! use sha2::{Digest, Sha512}; //! use curve25519_dalek::scalar::Scalar; @@ -111,36 +107,11 @@ //! # } //! ``` //! -//! Finally, to create a `Scalar` with a specific bit-pattern -//! (e.g., for compatibility with X/Ed25519 -//! ["clamping"](https://github.com/isislovecruft/ed25519-dalek/blob/f790bd2ce/src/ed25519.rs#L349)), -//! use [`Scalar::from_bits`](struct.Scalar.html#method.from_bits). This -//! constructs a scalar with exactly the bit pattern given, without any -//! assurances as to reduction modulo the group order: -//! -//! ``` -//! use curve25519_dalek::scalar::Scalar; -//! -//! let l_plus_two_bytes: [u8; 32] = [ -//! 0xef, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, -//! 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, -//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -//! 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, -//! ]; -//! let a: Scalar = Scalar::from_bits(l_plus_two_bytes); -//! -//! let two: Scalar = Scalar::one() + Scalar::one(); -//! -//! assert!(a != two); // the scalar is not reduced (mod l)… -//! assert!(! a.is_canonical()); // …and therefore is not canonical. -//! assert!(a.reduce() == two); // if we were to reduce it manually, it would be. -//! ``` -//! -//! The resulting `Scalar` has exactly the specified bit pattern, -//! **except for the highest bit, which will be set to 0**. +//! See also `Scalar::hash_from_bytes` and `Scalar::from_hash` that +//! reduces a \\(512\\)-bit integer, if the optional `digest` feature +//! has been enabled. use core::borrow::Borrow; -use core::cmp::{Eq, PartialEq}; use core::fmt::Debug; use core::iter::{Product, Sum}; use core::ops::Index; @@ -149,65 +120,121 @@ use core::ops::{Add, AddAssign}; use core::ops::{Mul, MulAssign}; use core::ops::{Sub, SubAssign}; -#[allow(unused_imports)] -use prelude::*; +use cfg_if::cfg_if; + +#[cfg(feature = "group")] +use group::ff::{Field, FromUniformBytes, PrimeField}; +#[cfg(feature = "group-bits")] +use group::ff::{FieldBits, PrimeFieldBits}; -use rand_core::{CryptoRng, RngCore}; +#[cfg(any(test, feature = "group"))] +use rand_core::RngCore; +#[cfg(any(test, feature = "rand_core"))] +use rand_core::CryptoRngCore; + +#[cfg(feature = "digest")] use digest::generic_array::typenum::U64; +#[cfg(feature = "digest")] use digest::Digest; use subtle::Choice; use subtle::ConditionallySelectable; use subtle::ConstantTimeEq; +use subtle::CtOption; +#[cfg(feature = "zeroize")] use zeroize::Zeroize; -use backend; -use constants; - -/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. -/// -/// This is a type alias for one of the scalar types in the `backend` -/// module. -#[cfg(feature = "fiat_u32_backend")] -type UnpackedScalar = backend::serial::fiat_u32::scalar::Scalar29; -#[cfg(feature = "fiat_u64_backend")] -type UnpackedScalar = backend::serial::fiat_u64::scalar::Scalar52; - -/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. -/// -/// This is a type alias for one of the scalar types in the `backend` -/// module. -#[cfg(feature = "u64_backend")] -type UnpackedScalar = backend::serial::u64::scalar::Scalar52; - -/// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. -/// -/// This is a type alias for one of the scalar types in the `backend` -/// module. -#[cfg(feature = "u32_backend")] -type UnpackedScalar = backend::serial::u32::scalar::Scalar29; -#[cfg(feature = "u32e_backend")] -type UnpackedScalar = backend::serial::u32e::scalar::Scalar29; - +use crate::backend; +use crate::constants; + +cfg_if! { + if #[cfg(curve25519_dalek_backend = "u32e_backend")] { + /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. + /// + /// This is a type alias for one of the scalar types in the `backend` + /// module. + type UnpackedScalar = backend::serial::u32e::scalar::Scalar29; + } + else if #[cfg(curve25519_dalek_backend = "fiat")] { + /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. + /// + /// This is a type alias for one of the scalar types in the `backend` + /// module. + #[cfg(curve25519_dalek_bits = "32")] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", curve25519_dalek_bits = "32"))) + )] + type UnpackedScalar = backend::serial::fiat_u32::scalar::Scalar29; + + /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. + /// + /// This is a type alias for one of the scalar types in the `backend` + /// module. + #[cfg(curve25519_dalek_bits = "64")] + #[cfg_attr( + docsrs, + doc(cfg(all(feature = "fiat_backend", curve25519_dalek_bits = "64"))) + )] + type UnpackedScalar = backend::serial::fiat_u64::scalar::Scalar52; + } else if #[cfg(curve25519_dalek_bits = "64")] { + /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. + /// + /// This is a type alias for one of the scalar types in the `backend` + /// module. + #[cfg_attr(docsrs, doc(cfg(curve25519_dalek_bits = "64")))] + type UnpackedScalar = backend::serial::u64::scalar::Scalar52; + } else { + /// An `UnpackedScalar` represents an element of the field GF(l), optimized for speed. + /// + /// This is a type alias for one of the scalar types in the `backend` + /// module. + #[cfg_attr(docsrs, doc(cfg(curve25519_dalek_bits = "64")))] + type UnpackedScalar = backend::serial::u32::scalar::Scalar29; + } +} -/// The `Scalar` struct holds an integer \\(s < 2\^{255} \\) which -/// represents an element of \\(\mathbb Z / \ell\\). +/// The `Scalar` struct holds an element of \\(\mathbb Z / \ell\mathbb Z \\). +#[allow(clippy::derived_hash_with_manual_eq)] #[derive(Copy, Clone, Hash)] pub struct Scalar { /// `bytes` is a little-endian byte encoding of an integer representing a scalar modulo the /// group order. /// - /// # Invariant + /// # Invariant #1 + /// + /// The integer representing this scalar is less than \\(2\^{255}\\). That is, the most + /// significant bit of `bytes[31]` is 0. + /// + /// This is required for `EdwardsPoint` variable- and fixed-base multiplication, because most + /// integers above 2^255 are unrepresentable in our radix-16 NAF (see [`Self::as_radix_16`]). + /// The invariant is also required because our `MontgomeryPoint` multiplication assumes the MSB + /// is 0 (see `MontgomeryPoint::mul`). /// - /// The integer representing this scalar must be bounded above by \\(2\^{255}\\), or - /// equivalently the high bit of `bytes[31]` must be zero. + /// # Invariant #2 (weak) + /// + /// The integer representing this scalar is less than \\(2\^{255} - 19 \\), i.e., it represents + /// a canonical representative of an element of \\( \mathbb Z / \ell\mathbb Z \\). This is + /// stronger than invariant #1. It also sometimes has to be broken. + /// + /// This invariant is deliberately broken in the implementation of `EdwardsPoint::{mul_clamped, + /// mul_base_clamped}`, `MontgomeryPoint::{mul_clamped, mul_base_clamped}`, and + /// `BasepointTable::mul_base_clamped`. This is not an issue though. As mentioned above, + /// scalar-point multiplication is defined for any choice of `bytes` that satisfies invariant + /// #1. Since clamping guarantees invariant #1 is satisfied, these operations are well defined. + /// + /// Note: Scalar-point mult is the _only_ thing you can do safely with an unreduced scalar. + /// Scalar-scalar addition and subtraction are NOT correct when using unreduced scalars. + /// Multiplication is correct, but this is only due to a quirk of our implementation, and not + /// guaranteed to hold in general in the future. + /// + /// Note: It is not possible to construct an unreduced `Scalar` from the public API unless the + /// `legacy_compatibility` is enabled (thus making `Scalar::from_bits` public). Thus, for all + /// public non-legacy uses, invariant #2 + /// always holds. /// - /// This ensures that there is room for a carry bit when computing a NAF representation. - // - // XXX This is pub(crate) so we can write literal constants. If const fns were stable, we could - // make the Scalar constructors const fns and use those instead. pub(crate) bytes: [u8; 32], } @@ -216,7 +243,7 @@ impl Scalar { /// modulo the group order \\( \ell \\). pub fn from_bytes_mod_order(bytes: [u8; 32]) -> Scalar { // Temporarily allow s_unreduced.bytes > 2^255 ... - let s_unreduced = Scalar{bytes}; + let s_unreduced = Scalar { bytes }; // Then reduce mod the group order and return the reduced representative. let s = s_unreduced.reduce(); @@ -236,28 +263,28 @@ impl Scalar { /// # Return /// /// - `Some(s)`, where `s` is the `Scalar` corresponding to `bytes`, - /// if `bytes` is a canonical byte representation; + /// if `bytes` is a canonical byte representation modulo the group order \\( \ell \\); /// - `None` if `bytes` is not a canonical byte representation. - pub fn from_canonical_bytes(bytes: [u8; 32]) -> Option { - // Check that the high bit is not set - if (bytes[31] >> 7) != 0u8 { return None; } - let candidate = Scalar::from_bits(bytes); - - if candidate.is_canonical() { - Some(candidate) - } else { - None - } - } - - /// Construct a `Scalar` from the low 255 bits of a 256-bit integer. - /// - /// This function is intended for applications like X25519 which - /// require specific bit-patterns when performing scalar - /// multiplication. + pub fn from_canonical_bytes(bytes: [u8; 32]) -> CtOption { + let high_bit_unset = (bytes[31] >> 7).ct_eq(&0); + let candidate = Scalar { bytes }; + CtOption::new(candidate, high_bit_unset & candidate.is_canonical()) + } + + /// Construct a `Scalar` from the low 255 bits of a 256-bit integer. This breaks the invariant + /// that scalars are always reduced. Scalar-scalar arithmetic, i.e., addition, subtraction, + /// multiplication, **does not work** on scalars produced from this function. You may only use + /// the output of this function for `EdwardsPoint::mul`, `MontgomeryPoint::mul`, and + /// `EdwardsPoint::vartime_double_scalar_mul_basepoint`. **Do not use this function** unless + /// you absolutely have to. + #[cfg(feature = "legacy_compatibility")] + #[deprecated( + since = "4.0.0", + note = "This constructor outputs scalars with undefined scalar-scalar arithmetic. See docs." + )] pub const fn from_bits(bytes: [u8; 32]) -> Scalar { - let mut s = Scalar{bytes}; - // Ensure that s < 2^255 by masking the high bit + let mut s = Scalar { bytes }; + // Ensure invariant #1 holds. That is, make s < 2^255 by masking the high bit. s.bytes[31] &= 0b0111_1111; s @@ -265,7 +292,7 @@ impl Scalar { } impl Debug for Scalar { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "Scalar{{\n\tbytes: {:?},\n}}", &self.bytes) } } @@ -273,7 +300,7 @@ impl Debug for Scalar { impl Eq for Scalar {} impl PartialEq for Scalar { fn eq(&self, other: &Self) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 + self.ct_eq(other).into() } } @@ -321,15 +348,9 @@ impl<'a, 'b> Add<&'b Scalar> for &'a Scalar { type Output = Scalar; #[allow(non_snake_case)] fn add(self, _rhs: &'b Scalar) -> Scalar { - // The UnpackedScalar::add function produces reduced outputs - // if the inputs are reduced. However, these inputs may not - // be reduced -- they might come from Scalar::from_bits. So - // after computing the sum, we explicitly reduce it mod l - // before repacking. - let sum = UnpackedScalar::add(&self.unpack(), &_rhs.unpack()); - let sum_R = UnpackedScalar::mul_internal(&sum, &constants::R); - let sum_mod_l = UnpackedScalar::montgomery_reduce(&sum_R); - sum_mod_l.pack() + // The UnpackedScalar::add function produces reduced outputs if the inputs are reduced. By + // Scalar invariant #1, this is always the case. + UnpackedScalar::add(&self.unpack(), &_rhs.unpack()).pack() } } @@ -347,16 +368,9 @@ impl<'a, 'b> Sub<&'b Scalar> for &'a Scalar { type Output = Scalar; #[allow(non_snake_case)] fn sub(self, rhs: &'b Scalar) -> Scalar { - // The UnpackedScalar::sub function requires reduced inputs - // and produces reduced output. However, these inputs may not - // be reduced -- they might come from Scalar::from_bits. So - // we explicitly reduce the inputs. - let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R); - let self_mod_l = UnpackedScalar::montgomery_reduce(&self_R); - let rhs_R = UnpackedScalar::mul_internal(&rhs.unpack(), &constants::R); - let rhs_mod_l = UnpackedScalar::montgomery_reduce(&rhs_R); - - UnpackedScalar::sub(&self_mod_l, &rhs_mod_l).pack() + // The UnpackedScalar::sub function produces reduced outputs if the inputs are reduced. By + // Scalar invariant #1, this is always the case. + UnpackedScalar::sub(&self.unpack(), &rhs.unpack()).pack() } } @@ -368,11 +382,11 @@ impl<'a> Neg for &'a Scalar { fn neg(self) -> Scalar { let self_R = UnpackedScalar::mul_internal(&self.unpack(), &constants::R); let self_mod_l = UnpackedScalar::montgomery_reduce(&self_R); - UnpackedScalar::sub(&UnpackedScalar::zero(), &self_mod_l).pack() + UnpackedScalar::sub(&UnpackedScalar::ZERO, &self_mod_l).pack() } } -impl<'a> Neg for Scalar { +impl Neg for Scalar { type Output = Scalar; fn neg(self) -> Scalar { -&self @@ -382,6 +396,7 @@ impl<'a> Neg for Scalar { impl ConditionallySelectable for Scalar { fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { bytes[i] = u8::conditional_select(&a.bytes[i], &b.bytes[i], choice); } @@ -389,15 +404,17 @@ impl ConditionallySelectable for Scalar { } } -#[cfg(feature = "serde")] -use serde::{self, Serialize, Deserialize, Serializer, Deserializer}; #[cfg(feature = "serde")] use serde::de::Visitor; +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl Serialize for Scalar { fn serialize(&self, serializer: S) -> Result - where S: Serializer + where + S: Serializer, { use serde::ser::SerializeTuple; let mut tup = serializer.serialize_tuple(32)?; @@ -409,31 +426,37 @@ impl Serialize for Scalar { } #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] impl<'de> Deserialize<'de> for Scalar { fn deserialize(deserializer: D) -> Result - where D: Deserializer<'de> + where + D: Deserializer<'de>, { struct ScalarVisitor; impl<'de> Visitor<'de> for ScalarVisitor { type Value = Scalar; - fn expecting(&self, formatter: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - formatter.write_str("a valid point in Edwards y + sign format") + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str( + "a sequence of 32 bytes whose little-endian interpretation is less than the \ + basepoint order ℓ", + ) } fn visit_seq(self, mut seq: A) -> Result - where A: serde::de::SeqAccess<'de> + where + A: serde::de::SeqAccess<'de>, { let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] for i in 0..32 { - bytes[i] = seq.next_element()? - .ok_or(serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + bytes[i] = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; } - Scalar::from_canonical_bytes(bytes) - .ok_or(serde::de::Error::custom( - &"scalar was not canonically encoded" - )) + Option::from(Scalar::from_canonical_bytes(bytes)) + .ok_or_else(|| serde::de::Error::custom("scalar was not canonically encoded")) } } @@ -443,31 +466,31 @@ impl<'de> Deserialize<'de> for Scalar { impl Product for Scalar where - T: Borrow + T: Borrow, { fn product(iter: I) -> Self where - I: Iterator + I: Iterator, { - iter.fold(Scalar::one(), |acc, item| acc * item.borrow()) + iter.fold(Scalar::ONE, |acc, item| acc * item.borrow()) } } impl Sum for Scalar where - T: Borrow + T: Borrow, { fn sum(iter: I) -> Self where - I: Iterator + I: Iterator, { - iter.fold(Scalar::zero(), |acc, item| acc + item.borrow()) + iter.fold(Scalar::ZERO, |acc, item| acc + item.borrow()) } } impl Default for Scalar { fn default() -> Scalar { - Scalar::zero() + Scalar::ZERO } } @@ -475,25 +498,25 @@ impl From for Scalar { fn from(x: u8) -> Scalar { let mut s_bytes = [0u8; 32]; s_bytes[0] = x; - Scalar{ bytes: s_bytes } + Scalar { bytes: s_bytes } } } impl From for Scalar { fn from(x: u16) -> Scalar { - use byteorder::{ByteOrder, LittleEndian}; let mut s_bytes = [0u8; 32]; - LittleEndian::write_u16(&mut s_bytes, x); - Scalar{ bytes: s_bytes } + let x_bytes = x.to_le_bytes(); + s_bytes[0..x_bytes.len()].copy_from_slice(&x_bytes); + Scalar { bytes: s_bytes } } } impl From for Scalar { fn from(x: u32) -> Scalar { - use byteorder::{ByteOrder, LittleEndian}; let mut s_bytes = [0u8; 32]; - LittleEndian::write_u32(&mut s_bytes, x); - Scalar{ bytes: s_bytes } + let x_bytes = x.to_le_bytes(); + s_bytes[0..x_bytes.len()].copy_from_slice(&x_bytes); + Scalar { bytes: s_bytes } } } @@ -520,22 +543,23 @@ impl From for Scalar { /// assert!(fourtytwo == six * seven); /// ``` fn from(x: u64) -> Scalar { - use byteorder::{ByteOrder, LittleEndian}; let mut s_bytes = [0u8; 32]; - LittleEndian::write_u64(&mut s_bytes, x); - Scalar{ bytes: s_bytes } + let x_bytes = x.to_le_bytes(); + s_bytes[0..x_bytes.len()].copy_from_slice(&x_bytes); + Scalar { bytes: s_bytes } } } impl From for Scalar { fn from(x: u128) -> Scalar { - use byteorder::{ByteOrder, LittleEndian}; let mut s_bytes = [0u8; 32]; - LittleEndian::write_u128(&mut s_bytes, x); - Scalar{ bytes: s_bytes } + let x_bytes = x.to_le_bytes(); + s_bytes[0..x_bytes.len()].copy_from_slice(&x_bytes); + Scalar { bytes: s_bytes } } } +#[cfg(feature = "zeroize")] impl Zeroize for Scalar { fn zeroize(&mut self) { self.bytes.zeroize(); @@ -543,22 +567,32 @@ impl Zeroize for Scalar { } impl Scalar { + /// The scalar \\( 0 \\). + pub const ZERO: Self = Self { bytes: [0u8; 32] }; + + /// The scalar \\( 1 \\). + pub const ONE: Self = Self { + bytes: [ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + + #[cfg(any(test, feature = "rand_core"))] /// Return a `Scalar` chosen uniformly at random using a user-provided RNG. /// /// # Inputs /// - /// * `rng`: any RNG which implements the `RngCore + CryptoRng` interface. + /// * `rng`: any RNG which implements `CryptoRngCore` + /// (i.e. `CryptoRng` + `RngCore`) interface. /// /// # Returns /// - /// A random scalar within ℤ/lℤ. + /// A random scalar within \\(\mathbb{Z} / \ell\mathbb{Z}\\). /// /// # Example /// /// ``` - /// extern crate rand_core; - /// # extern crate curve25519_dalek; - /// # /// # fn main() { /// use curve25519_dalek::scalar::Scalar; /// @@ -567,12 +601,13 @@ impl Scalar { /// let mut csprng = OsRng; /// let a: Scalar = Scalar::random(&mut csprng); /// # } - pub fn random(rng: &mut R) -> Self { + pub fn random(rng: &mut R) -> Self { let mut scalar_bytes = [0u8; 64]; rng.fill_bytes(&mut scalar_bytes); Scalar::from_bytes_mod_order_wide(&scalar_bytes) } + #[cfg(feature = "digest")] /// Hash a slice of bytes into a scalar. /// /// Takes a type parameter `D`, which is any `Digest` producing 64 @@ -582,11 +617,9 @@ impl Scalar { /// /// # Example /// - /// ``` - /// # extern crate curve25519_dalek; + #[cfg_attr(feature = "digest", doc = "```")] + #[cfg_attr(not(feature = "digest"), doc = "```ignore")] /// # use curve25519_dalek::scalar::Scalar; - /// extern crate sha2; - /// /// use sha2::Sha512; /// /// # // Need fn main() here in comment so the doctest compiles @@ -597,13 +630,15 @@ impl Scalar { /// # } /// ``` pub fn hash_from_bytes(input: &[u8]) -> Scalar - where D: Digest + Default + where + D: Digest + Default, { let mut hash = D::default(); hash.update(input); Scalar::from_hash(hash) } + #[cfg(feature = "digest")] /// Construct a scalar from an existing `Digest` instance. /// /// Use this instead of `hash_from_bytes` if it is more convenient @@ -613,9 +648,8 @@ impl Scalar { /// # Example /// /// ``` - /// # extern crate curve25519_dalek; /// # use curve25519_dalek::scalar::Scalar; - /// extern crate sha2; + /// use curve25519_dalek::digest::Update; /// /// use sha2::Digest; /// use sha2::Sha512; @@ -632,14 +666,18 @@ impl Scalar { /// let s = Scalar::from_hash(h); /// /// println!("{:?}", s.to_bytes()); - /// assert!(s == Scalar::from_bits([ 21, 88, 208, 252, 63, 122, 210, 152, - /// 154, 38, 15, 23, 16, 167, 80, 150, - /// 192, 221, 77, 226, 62, 25, 224, 148, - /// 239, 48, 176, 10, 185, 69, 168, 11, ])); + /// assert_eq!( + /// s.to_bytes(), + /// [ 21, 88, 208, 252, 63, 122, 210, 152, + /// 154, 38, 15, 23, 16, 167, 80, 150, + /// 192, 221, 77, 226, 62, 25, 224, 148, + /// 239, 48, 176, 10, 185, 69, 168, 11, ], + /// ); /// # } /// ``` pub fn from_hash(hash: D) -> Scalar - where D: Digest + where + D: Digest, { let mut output = [0u8; 64]; output.copy_from_slice(hash.finalize().as_slice()); @@ -653,11 +691,11 @@ impl Scalar { /// ``` /// use curve25519_dalek::scalar::Scalar; /// - /// let s: Scalar = Scalar::zero(); + /// let s: Scalar = Scalar::ZERO; /// /// assert!(s.to_bytes() == [0u8; 32]); /// ``` - pub fn to_bytes(&self) -> [u8; 32] { + pub const fn to_bytes(&self) -> [u8; 32] { self.bytes } @@ -668,29 +706,14 @@ impl Scalar { /// ``` /// use curve25519_dalek::scalar::Scalar; /// - /// let s: Scalar = Scalar::zero(); + /// let s: Scalar = Scalar::ZERO; /// /// assert!(s.as_bytes() == &[0u8; 32]); /// ``` - pub fn as_bytes(&self) -> &[u8; 32] { + pub const fn as_bytes(&self) -> &[u8; 32] { &self.bytes } - /// Construct the scalar \\( 0 \\). - pub fn zero() -> Self { - Scalar { bytes: [0u8; 32]} - } - - /// Construct the scalar \\( 1 \\). - pub fn one() -> Self { - Scalar { - bytes: [ - 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - } - } - /// Given a nonzero `Scalar`, compute its multiplicative inverse. /// /// # Warning @@ -726,7 +749,7 @@ impl Scalar { /// let inv_X: Scalar = X.invert(); /// assert!(XINV == inv_X); /// let should_be_one: Scalar = &inv_X * &X; - /// assert!(should_be_one == Scalar::one()); + /// assert!(should_be_one == Scalar::ONE); /// ``` pub fn invert(&self) -> Scalar { self.unpack().invert().pack() @@ -750,7 +773,6 @@ impl Scalar { /// # Example /// /// ``` - /// # extern crate curve25519_dalek; /// # use curve25519_dalek::scalar::Scalar; /// # fn main() { /// let mut scalars = [ @@ -778,18 +800,13 @@ impl Scalar { // externally, but there's no corresponding distinction for // field elements. - use zeroize::Zeroizing; - let n = inputs.len(); - let one: UnpackedScalar = Scalar::one().unpack().to_montgomery(); + let one: UnpackedScalar = Scalar::ONE.unpack().as_montgomery(); - // Place scratch storage in a Zeroizing wrapper to wipe it when - // we pass out of scope. - let scratch_vec = vec![one; n]; - let mut scratch = Zeroizing::new(scratch_vec); + let mut scratch = vec![one; n]; // Keep an accumulator of all of the previous products - let mut acc = Scalar::one().unpack().to_montgomery(); + let mut acc = Scalar::ONE.unpack().as_montgomery(); // Pass through the input vector, recording the previous // products in the scratch space @@ -798,13 +815,13 @@ impl Scalar { // Avoid unnecessary Montgomery multiplication in second pass by // keeping inputs in Montgomery form - let tmp = input.unpack().to_montgomery(); + let tmp = input.unpack().as_montgomery(); *input = tmp.pack(); acc = UnpackedScalar::montgomery_mul(&acc, &tmp); } // acc is nonzero iff all inputs are nonzero - debug_assert!(acc.pack() != Scalar::zero()); + debug_assert!(acc.pack() != Scalar::ZERO); // Compute the inverse of all products acc = acc.montgomery_invert().from_montgomery(); @@ -816,23 +833,25 @@ impl Scalar { // in place for (input, scratch) in inputs.iter_mut().rev().zip(scratch.iter().rev()) { let tmp = UnpackedScalar::montgomery_mul(&acc, &input.unpack()); - *input = UnpackedScalar::montgomery_mul(&acc, &scratch).pack(); + *input = UnpackedScalar::montgomery_mul(&acc, scratch).pack(); acc = tmp; } + #[cfg(feature = "zeroize")] + Zeroize::zeroize(&mut scratch); + ret } - /// Get the bits of the scalar. - #[cfg(not(feature = "betrusted"))] - pub(crate) fn bits(&self) -> [i8; 256] { - let mut bits = [0i8; 256]; - for i in 0..256 { - // As i runs from 0..256, the bottom 3 bits index the bit, - // while the upper bits index the byte. - bits[i] = ((self.bytes[i>>3] >> (i&7)) & 1u8) as i8; - } - bits + /// Get the bits of the scalar, in little-endian order + #[cfg(not(curve25519_dalek_backend = "u32e_backend"))] + pub(crate) fn bits_le(&self) -> impl DoubleEndedIterator + '_ { + (0..256).map(|i| { + // As i runs from 0..256, the bottom 3 bits index the bit, while the upper bits index + // the byte. Since self.bytes is little-endian at the byte level, this iterator is + // little-endian on the bit level + ((self.bytes[i >> 3] >> (i & 7)) & 1u8) == 1 + }) } /// Compute a width-\\(w\\) "Non-Adjacent Form" of this scalar. @@ -848,7 +867,7 @@ impl Scalar { /// /// The length of the NAF is at most one more than the length of /// the binary representation of \\(k\\). This is why the - /// `Scalar` type maintains an invariant that the top bit is + /// `Scalar` type maintains an invariant (invariant #1) that the top bit is /// \\(0\\), so that the NAF of a scalar has at most 256 digits. /// /// Intuitively, this is like a binary expansion, except that we @@ -873,7 +892,7 @@ impl Scalar { /// /// Here \\( \bar x = x \operatorname{mods} 2^w \\) means the /// \\( \bar x \\) with \\( \bar x \equiv x \pmod{2^w} \\) and - /// \\( -2^{w-1} \leq \bar x < 2^w \\). + /// \\( -2^{w-1} \leq \bar x < 2^{w-1} \\). /// /// We implement this by scanning across the bits of \\(k\\) from /// least-significant bit to most-significant-bit. @@ -909,16 +928,14 @@ impl Scalar { /// initially, we don't need to emit anything. pub(crate) fn non_adjacent_form(&self, w: usize) -> [i8; 256] { // required by the NAF definition - debug_assert!( w >= 2 ); + debug_assert!(w >= 2); // required so that the NAF digits fit in i8 - debug_assert!( w <= 8 ); - - use byteorder::{ByteOrder, LittleEndian}; + debug_assert!(w <= 8); let mut naf = [0i8; 256]; let mut x_u64 = [0u64; 5]; - LittleEndian::read_u64_into(&self.bytes, &mut x_u64[0..4]); + read_le_u64_into(&self.bytes, &mut x_u64[0..4]); let width = 1 << w; let window_mask = width - 1; @@ -929,14 +946,13 @@ impl Scalar { // Construct a buffer of bits of the scalar, starting at bit `pos` let u64_idx = pos / 64; let bit_idx = pos % 64; - let bit_buf: u64; - if bit_idx < 64 - w { + let bit_buf: u64 = if bit_idx < 64 - w { // This window's bits are contained in a single u64 - bit_buf = x_u64[u64_idx] >> bit_idx; + x_u64[u64_idx] >> bit_idx } else { // Combine the current u64's bits with the bits from the next u64 - bit_buf = (x_u64[u64_idx] >> bit_idx) | (x_u64[1+u64_idx] << (64 - bit_idx)); - } + (x_u64[u64_idx] >> bit_idx) | (x_u64[1 + u64_idx] << (64 - bit_idx)) + }; // Add the carry into the current window let window = carry + (bit_buf & window_mask); @@ -950,7 +966,7 @@ impl Scalar { continue; } - if window < width/2 { + if window < width / 2 { carry = 0; naf[pos] = window as i8; } else { @@ -970,28 +986,37 @@ impl Scalar { /// a = a\_0 + a\_1 16\^1 + \cdots + a_{63} 16\^{63}, /// $$ /// with \\(-8 \leq a_i < 8\\) for \\(0 \leq i < 63\\) and \\(-8 \leq a_{63} \leq 8\\). - pub(crate) fn to_radix_16(&self) -> [i8; 64] { + /// + /// The largest value that can be decomposed like this is just over \\(2^{255}\\). Thus, in + /// order to not error, the top bit MUST NOT be set, i.e., `Self` MUST be less than + /// \\(2^{255}\\). + pub(crate) fn as_radix_16(&self) -> [i8; 64] { debug_assert!(self[31] <= 127); let mut output = [0i8; 64]; // Step 1: change radix. // Convert from radix 256 (bytes) to radix 16 (nibbles) + #[allow(clippy::identity_op)] #[inline(always)] - fn bot_half(x: u8) -> u8 { (x >> 0) & 15 } + fn bot_half(x: u8) -> u8 { + (x >> 0) & 15 + } #[inline(always)] - fn top_half(x: u8) -> u8 { (x >> 4) & 15 } + fn top_half(x: u8) -> u8 { + (x >> 4) & 15 + } for i in 0..32 { - output[2*i ] = bot_half(self[i]) as i8; - output[2*i+1] = top_half(self[i]) as i8; + output[2 * i] = bot_half(self[i]) as i8; + output[2 * i + 1] = top_half(self[i]) as i8; } // Precondition note: since self[31] <= 127, output[63] <= 7 // Step 2: recenter coefficients from [0,16) to [-8,8) for i in 0..63 { - let carry = (output[i] + 8) >> 4; - output[i ] -= carry << 4; - output[i+1] += carry; + let carry = (output[i] + 8) >> 4; + output[i] -= carry << 4; + output[i + 1] += carry; } // Precondition note: output[63] is not recentered. It // increases by carry <= 1. Thus output[63] <= 8. @@ -999,35 +1024,36 @@ impl Scalar { output } - /// Returns a size hint indicating how many entries of the return - /// value of `to_radix_2w` are nonzero. - #[cfg(all(not(feature = "betrusted"), not(feature = "u32e_backend")))] - pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { - debug_assert!(w >= 4); - debug_assert!(w <= 8); + #[cfg(any(feature = "alloc", all(test, feature = "precomputed-tables")))] + /// Returns a size hint indicating how many entries of the return + /// value of `to_radix_2w` are nonzero. + pub(crate) fn to_radix_2w_size_hint(w: usize) -> usize { + debug_assert!(w >= 4); + debug_assert!(w <= 8); - let digits_count = match w { - 4 => (256 + w - 1)/w as usize, - 5 => (256 + w - 1)/w as usize, - 6 => (256 + w - 1)/w as usize, - 7 => (256 + w - 1)/w as usize, - // See comment in to_radix_2w on handling the terminal carry. - 8 => (256 + w - 1)/w + 1 as usize, - _ => panic!("invalid radix parameter"), - }; + let digits_count = match w { + 4..=7 => (256 + w - 1) / w, + // See comment in to_radix_2w on handling the terminal carry. + 8 => (256 + w - 1) / w + 1_usize, + _ => panic!("invalid radix parameter"), + }; - debug_assert!(digits_count <= 64); - digits_count - } + debug_assert!(digits_count <= 64); + digits_count + } - /// Creates a representation of a Scalar in radix 32, 64, 128 or 256 for use with the Pippenger algorithm. - /// For lower radix, use `to_radix_16`, which is used by the Straus multi-scalar multiplication. - /// Higher radixes are not supported to save cache space. Radix 256 is near-optimal even for very - /// large inputs. + /// Creates a representation of a Scalar in radix \\( 2^w \\) with \\(w = 4, 5, 6, 7, 8\\) for + /// use with the Pippenger algorithm. Higher radixes are not supported to save cache space. + /// Radix 256 is near-optimal even for very large inputs. /// - /// Radix below 32 or above 256 is prohibited. + /// Radix below 16 or above 256 is prohibited. /// This method returns digits in a fixed-sized array, excess digits are zeroes. /// + /// For radix 16, `Self` must be less than \\(2^{255}\\). This is because most integers larger + /// than \\(2^{255}\\) are unrepresentable in the form described below for \\(w = 4\\). This + /// would be true for \\(w = 8\\) as well, but it is compensated for by increasing the size + /// hint by 1. + /// /// ## Scalar representation /// /// Radix \\(2\^w\\), with \\(n = ceil(256/w)\\) coefficients in \\([-(2\^w)/2,(2\^w)/2)\\), @@ -1037,62 +1063,61 @@ impl Scalar { /// $$ /// with \\(-2\^w/2 \leq a_i < 2\^w/2\\) for \\(0 \leq i < (n-1)\\) and \\(-2\^w/2 \leq a_{n-1} \leq 2\^w/2\\). /// - pub(crate) fn to_radix_2w(&self, w: usize) -> [i8; 64] { + #[cfg(any(feature = "alloc", feature = "precomputed-tables"))] + pub(crate) fn as_radix_2w(&self, w: usize) -> [i8; 64] { debug_assert!(w >= 4); debug_assert!(w <= 8); if w == 4 { - return self.to_radix_16(); + return self.as_radix_16(); } - use byteorder::{ByteOrder, LittleEndian}; - // Scalar formatted as four `u64`s with carry bit packed into the highest bit. let mut scalar64x4 = [0u64; 4]; - LittleEndian::read_u64_into(&self.bytes, &mut scalar64x4[0..4]); + read_le_u64_into(&self.bytes, &mut scalar64x4[0..4]); let radix: u64 = 1 << w; let window_mask: u64 = radix - 1; let mut carry = 0u64; let mut digits = [0i8; 64]; - let digits_count = (256 + w - 1)/w as usize; + let digits_count = (256 + w - 1) / w; + #[allow(clippy::needless_range_loop)] for i in 0..digits_count { // Construct a buffer of bits of the scalar, starting at `bit_offset`. - let bit_offset = i*w; + let bit_offset = i * w; let u64_idx = bit_offset / 64; let bit_idx = bit_offset % 64; // Read the bits from the scalar - let bit_buf: u64; - if bit_idx < 64 - w || u64_idx == 3 { + let bit_buf: u64 = if bit_idx < 64 - w || u64_idx == 3 { // This window's bits are contained in a single u64, // or it's the last u64 anyway. - bit_buf = scalar64x4[u64_idx] >> bit_idx; + scalar64x4[u64_idx] >> bit_idx } else { // Combine the current u64's bits with the bits from the next u64 - bit_buf = (scalar64x4[u64_idx] >> bit_idx) | (scalar64x4[1+u64_idx] << (64 - bit_idx)); - } + (scalar64x4[u64_idx] >> bit_idx) | (scalar64x4[1 + u64_idx] << (64 - bit_idx)) + }; // Read the actual coefficient value from the window let coef = carry + (bit_buf & window_mask); // coef = [0, 2^r) - // Recenter coefficients from [0,2^w) to [-2^w/2, 2^w/2) - carry = (coef + (radix/2) as u64) >> w; + // Recenter coefficients from [0,2^w) to [-2^w/2, 2^w/2) + carry = (coef + (radix / 2)) >> w; digits[i] = ((coef as i64) - (carry << w) as i64) as i8; } - // When w < 8, we can fold the final carry onto the last digit d, + // When 4 < w < 8, we can fold the final carry onto the last digit d, // because d < 2^w/2 so d + carry*2^w = d + 1*2^w < 2^(w+1) < 2^8. // // When w = 8, we can't fit carry*2^w into an i8. This should // not happen anyways, because the final carry will be 0 for - // reduced scalars, but the Scalar invariant allows 255-bit scalars. + // reduced scalars, but Scalar invariant #1 allows 255-bit scalars. // To handle this, we expand the size_hint by 1 when w=8, // and accumulate the final carry onto another digit. match w { 8 => digits[digits_count] += carry as i8, - _ => digits[digits_count-1] += (carry << w) as i8, + _ => digits[digits_count - 1] += (carry << w) as i8, } digits @@ -1105,47 +1130,35 @@ impl Scalar { /// Reduce this `Scalar` modulo \\(\ell\\). #[allow(non_snake_case)] - pub fn reduce(&self) -> Scalar { + fn reduce(&self) -> Scalar { let x = self.unpack(); let xR = UnpackedScalar::mul_internal(&x, &constants::R); let x_mod_l = UnpackedScalar::montgomery_reduce(&xR); x_mod_l.pack() } - /// Check whether this `Scalar` is the canonical representative mod \\(\ell\\). - /// - /// This is intended for uses like input validation, where variable-time code is acceptable. - /// - /// ``` - /// # extern crate curve25519_dalek; - /// # extern crate subtle; - /// # use curve25519_dalek::scalar::Scalar; - /// # use subtle::ConditionallySelectable; - /// # fn main() { - /// // 2^255 - 1, since `from_bits` clears the high bit - /// let _2_255_minus_1 = Scalar::from_bits([0xff;32]); - /// assert!(!_2_255_minus_1.is_canonical()); - /// - /// let reduced = _2_255_minus_1.reduce(); - /// assert!(reduced.is_canonical()); - /// # } - /// ``` - pub fn is_canonical(&self) -> bool { - *self == self.reduce() + /// Check whether this `Scalar` is the canonical representative mod \\(\ell\\). This is not + /// public because any `Scalar` that is publicly observed is reduced, by scalar invariant #2. + fn is_canonical(&self) -> Choice { + self.ct_eq(&self.reduce()) } } impl UnpackedScalar { /// Pack the limbs of this `UnpackedScalar` into a `Scalar`. fn pack(&self) -> Scalar { - Scalar{ bytes: self.to_bytes() } + Scalar { + bytes: self.as_bytes(), + } } /// Inverts an UnpackedScalar in Montgomery form. + #[rustfmt::skip] // keep alignment of addition chain and squarings + #[allow(clippy::just_underscores_and_digits)] pub fn montgomery_invert(&self) -> UnpackedScalar { // Uses the addition chain from // https://briansmith.org/ecc-inversion-addition-chains-01#curve25519_scalar_inversion - let _1 = self; + let _1 = *self; let _10 = _1.montgomery_square(); let _100 = _10.montgomery_square(); let _11 = UnpackedScalar::montgomery_mul(&_10, &_1); @@ -1199,119 +1212,302 @@ impl UnpackedScalar { /// Inverts an UnpackedScalar not in Montgomery form. pub fn invert(&self) -> UnpackedScalar { - self.to_montgomery().montgomery_invert().from_montgomery() + self.as_montgomery().montgomery_invert().from_montgomery() + } +} + +#[cfg(feature = "group")] +impl Field for Scalar { + const ZERO: Self = Self::ZERO; + const ONE: Self = Self::ONE; + + fn random(mut rng: impl RngCore) -> Self { + // NOTE: this is duplicated due to different `rng` bounds + let mut scalar_bytes = [0u8; 64]; + rng.fill_bytes(&mut scalar_bytes); + Self::from_bytes_mod_order_wide(&scalar_bytes) + } + + fn square(&self) -> Self { + self * self + } + + fn double(&self) -> Self { + self + self + } + + fn invert(&self) -> CtOption { + CtOption::new(self.invert(), !self.is_zero()) + } + + fn sqrt_ratio(num: &Self, div: &Self) -> (Choice, Self) { + group::ff::helpers::sqrt_ratio_generic(num, div) + } + + fn sqrt(&self) -> CtOption { + group::ff::helpers::sqrt_tonelli_shanks( + self, + [ + 0xcb02_4c63_4b9e_ba7d, + 0x029b_df3b_d45e_f39a, + 0x0000_0000_0000_0000, + 0x0200_0000_0000_0000, + ], + ) + } +} + +#[cfg(feature = "group")] +impl PrimeField for Scalar { + type Repr = [u8; 32]; + + fn from_repr(repr: Self::Repr) -> CtOption { + Self::from_canonical_bytes(repr) + } + + fn from_repr_vartime(repr: Self::Repr) -> Option { + // Check that the high bit is not set + if (repr[31] >> 7) != 0u8 { + return None; + } + + let candidate = Scalar { bytes: repr }; + + if candidate == candidate.reduce() { + Some(candidate) + } else { + None + } + } + + fn to_repr(&self) -> Self::Repr { + self.to_bytes() + } + + fn is_odd(&self) -> Choice { + Choice::from(self.as_bytes()[0] & 1) + } + + const MODULUS: &'static str = + "0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed"; + const NUM_BITS: u32 = 253; + const CAPACITY: u32 = 252; + + const TWO_INV: Self = Self { + bytes: [ + 0xf7, 0xe9, 0x7a, 0x2e, 0x8d, 0x31, 0x09, 0x2c, 0x6b, 0xce, 0x7b, 0x51, 0xef, 0x7c, + 0x6f, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x08, + ], + }; + const MULTIPLICATIVE_GENERATOR: Self = Self { + bytes: [ + 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; + const S: u32 = 2; + const ROOT_OF_UNITY: Self = Self { + bytes: [ + 0xd4, 0x07, 0xbe, 0xeb, 0xdf, 0x75, 0x87, 0xbe, 0xfe, 0x83, 0xce, 0x42, 0x53, 0x56, + 0xf0, 0x0e, 0x7a, 0xc2, 0xc1, 0xab, 0x60, 0x6d, 0x3d, 0x7d, 0xe7, 0x81, 0x79, 0xe0, + 0x10, 0x73, 0x4a, 0x09, + ], + }; + const ROOT_OF_UNITY_INV: Self = Self { + bytes: [ + 0x19, 0xcc, 0x37, 0x71, 0x3a, 0xed, 0x8a, 0x99, 0xd7, 0x18, 0x29, 0x60, 0x8b, 0xa3, + 0xee, 0x05, 0x86, 0x3d, 0x3e, 0x54, 0x9f, 0x92, 0xc2, 0x82, 0x18, 0x7e, 0x86, 0x1f, + 0xef, 0x8c, 0xb5, 0x06, + ], + }; + const DELTA: Self = Self { + bytes: [ + 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, + ], + }; +} + +#[cfg(feature = "group-bits")] +impl PrimeFieldBits for Scalar { + type ReprBits = [u8; 32]; + + fn to_le_bits(&self) -> FieldBits { + self.to_repr().into() + } + + fn char_le_bits() -> FieldBits { + constants::BASEPOINT_ORDER_PRIVATE.to_bytes().into() + } +} + +#[cfg(feature = "group")] +impl FromUniformBytes<64> for Scalar { + fn from_uniform_bytes(bytes: &[u8; 64]) -> Self { + Scalar::from_bytes_mod_order_wide(bytes) } } +/// Read one or more u64s stored as little endian bytes. +/// +/// ## Panics +/// Panics if `src.len() != 8 * dst.len()`. +fn read_le_u64_into(src: &[u8], dst: &mut [u64]) { + assert!( + src.len() == 8 * dst.len(), + "src.len() = {}, dst.len() = {}", + src.len(), + dst.len() + ); + for (bytes, val) in src.chunks(8).zip(dst.iter_mut()) { + *val = u64::from_le_bytes( + bytes + .try_into() + .expect("Incorrect src length, should be 8 * dst.len()"), + ); + } +} + +/// _Clamps_ the given little-endian representation of a 32-byte integer. Clamping the value puts +/// it in the range: +/// +/// **n ∈ 2^254 + 8\*{0, 1, 2, 3, . . ., 2^251 − 1}** +/// +/// # Explanation of clamping +/// +/// For Curve25519, h = 8, and multiplying by 8 is the same as a binary left-shift by 3 bits. +/// If you take a secret scalar value between 2^251 and 2^252 – 1 and left-shift by 3 bits +/// then you end up with a 255-bit number with the most significant bit set to 1 and +/// the least-significant three bits set to 0. +/// +/// The Curve25519 clamping operation takes **an arbitrary 256-bit random value** and +/// clears the most-significant bit (making it a 255-bit number), sets the next bit, and then +/// clears the 3 least-significant bits. In other words, it directly creates a scalar value that is +/// in the right form and pre-multiplied by the cofactor. +/// +/// See [here](https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/) for +/// more details. +#[must_use] +pub const fn clamp_integer(mut bytes: [u8; 32]) -> [u8; 32] { + bytes[0] &= 0b1111_1000; + bytes[31] &= 0b0111_1111; + bytes[31] |= 0b0100_0000; + bytes +} + #[cfg(test)] -mod test { +pub(crate) mod test { use super::*; - use constants; + + #[cfg(feature = "alloc")] + use alloc::vec::Vec; /// x = 2238329342913194256032495932344128051776374960164957527413114840482143558222 - pub static X: Scalar = Scalar{ + pub static X: Scalar = Scalar { bytes: [ - 0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, - 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2, 0x7d, 0x52, - 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, - 0xd4, 0x49, 0xf4, 0xa8, 0x79, 0xd9, 0xf2, 0x04, + 0x4e, 0x5a, 0xb4, 0x34, 0x5d, 0x47, 0x08, 0x84, 0x59, 0x13, 0xb4, 0x64, 0x1b, 0xc2, + 0x7d, 0x52, 0x52, 0xa5, 0x85, 0x10, 0x1b, 0xcc, 0x42, 0x44, 0xd4, 0x49, 0xf4, 0xa8, + 0x79, 0xd9, 0xf2, 0x04, ], }; /// 1/x = 6859937278830797291664592131120606308688036382723378951768035303146619657244 - pub static XINV: Scalar = Scalar{ + pub static XINV: Scalar = Scalar { bytes: [ - 0x1c, 0xdc, 0x17, 0xfc, 0xe0, 0xe9, 0xa5, 0xbb, - 0xd9, 0x24, 0x7e, 0x56, 0xbb, 0x01, 0x63, 0x47, - 0xbb, 0xba, 0x31, 0xed, 0xd5, 0xa9, 0xbb, 0x96, - 0xd5, 0x0b, 0xcd, 0x7a, 0x3f, 0x96, 0x2a, 0x0f, + 0x1c, 0xdc, 0x17, 0xfc, 0xe0, 0xe9, 0xa5, 0xbb, 0xd9, 0x24, 0x7e, 0x56, 0xbb, 0x01, + 0x63, 0x47, 0xbb, 0xba, 0x31, 0xed, 0xd5, 0xa9, 0xbb, 0x96, 0xd5, 0x0b, 0xcd, 0x7a, + 0x3f, 0x96, 0x2a, 0x0f, ], }; /// y = 2592331292931086675770238855846338635550719849568364935475441891787804997264 - pub static Y: Scalar = Scalar{ + pub static Y: Scalar = Scalar { bytes: [ - 0x90, 0x76, 0x33, 0xfe, 0x1c, 0x4b, 0x66, 0xa4, - 0xa2, 0x8d, 0x2d, 0xd7, 0x67, 0x83, 0x86, 0xc3, - 0x53, 0xd0, 0xde, 0x54, 0x55, 0xd4, 0xfc, 0x9d, - 0xe8, 0xef, 0x7a, 0xc3, 0x1f, 0x35, 0xbb, 0x05, + 0x90, 0x76, 0x33, 0xfe, 0x1c, 0x4b, 0x66, 0xa4, 0xa2, 0x8d, 0x2d, 0xd7, 0x67, 0x83, + 0x86, 0xc3, 0x53, 0xd0, 0xde, 0x54, 0x55, 0xd4, 0xfc, 0x9d, 0xe8, 0xef, 0x7a, 0xc3, + 0x1f, 0x35, 0xbb, 0x05, ], }; - /// x*y = 5690045403673944803228348699031245560686958845067437804563560795922180092780 - static X_TIMES_Y: Scalar = Scalar{ + /// The largest scalar that satisfies invariant #1, i.e., the largest scalar with the top bit + /// set to 0. Since this scalar violates invariant #2, i.e., it's greater than the modulus `l`, + /// addition and subtraction are broken. The only thing you can do with this is scalar-point + /// multiplication (and actually also scalar-scalar multiplication, but that's just a quirk of + /// our implementation). + pub(crate) static LARGEST_UNREDUCED_SCALAR: Scalar = Scalar { bytes: [ - 0x6c, 0x33, 0x74, 0xa1, 0x89, 0x4f, 0x62, 0x21, - 0x0a, 0xaa, 0x2f, 0xe1, 0x86, 0xa6, 0xf9, 0x2c, - 0xe0, 0xaa, 0x75, 0xc2, 0x77, 0x95, 0x81, 0xc2, - 0x95, 0xfc, 0x08, 0x17, 0x9a, 0x73, 0x94, 0x0c, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, ], }; - /// sage: l = 2^252 + 27742317777372353535851937790883648493 - /// sage: big = 2^256 - 1 - /// sage: repr((big % l).digits(256)) - static CANONICAL_2_256_MINUS_1: Scalar = Scalar{ + /// x*y = 5690045403673944803228348699031245560686958845067437804563560795922180092780 + static X_TIMES_Y: Scalar = Scalar { bytes: [ - 28, 149, 152, 141, 116, 49, 236, 214, - 112, 207, 125, 115, 244, 91, 239, 198, - 254, 255, 255, 255, 255, 255, 255, 255, - 255, 255, 255, 255, 255, 255, 255, 15, + 0x6c, 0x33, 0x74, 0xa1, 0x89, 0x4f, 0x62, 0x21, 0x0a, 0xaa, 0x2f, 0xe1, 0x86, 0xa6, + 0xf9, 0x2c, 0xe0, 0xaa, 0x75, 0xc2, 0x77, 0x95, 0x81, 0xc2, 0x95, 0xfc, 0x08, 0x17, + 0x9a, 0x73, 0x94, 0x0c, ], }; - static A_SCALAR: Scalar = Scalar{ + /// sage: l = 2^252 + 27742317777372353535851937790883648493 + /// sage: big = 2^256 - 1 + /// sage: repr((big % l).digits(256)) + static CANONICAL_2_256_MINUS_1: Scalar = Scalar { bytes: [ - 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, - 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d, - 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, - 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09, + 28, 149, 152, 141, 116, 49, 236, 214, 112, 207, 125, 115, 244, 91, 239, 198, 254, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 15, ], }; - static A_NAF: [i8; 256] = - [0,13,0,0,0,0,0,0,0,7,0,0,0,0,0,0,-9,0,0,0,0,-11,0,0,0,0,3,0,0,0,0,1, - 0,0,0,0,9,0,0,0,0,-5,0,0,0,0,0,0,3,0,0,0,0,11,0,0,0,0,11,0,0,0,0,0, - -9,0,0,0,0,0,-3,0,0,0,0,9,0,0,0,0,0,1,0,0,0,0,0,0,-1,0,0,0,0,0,9,0, - 0,0,0,-15,0,0,0,0,-7,0,0,0,0,-9,0,0,0,0,0,5,0,0,0,0,13,0,0,0,0,0,-3,0, - 0,0,0,-11,0,0,0,0,-7,0,0,0,0,-13,0,0,0,0,11,0,0,0,0,-9,0,0,0,0,0,1,0,0, - 0,0,0,-15,0,0,0,0,1,0,0,0,0,7,0,0,0,0,0,0,0,0,5,0,0,0,0,0,13,0,0,0, - 0,0,0,11,0,0,0,0,0,15,0,0,0,0,0,-9,0,0,0,0,0,0,0,-1,0,0,0,0,0,0,0,7, - 0,0,0,0,0,-15,0,0,0,0,0,15,0,0,0,0,15,0,0,0,0,15,0,0,0,0,0,1,0,0,0,0]; - - static LARGEST_ED25519_S: Scalar = Scalar { + static A_SCALAR: Scalar = Scalar { bytes: [ - 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, + 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, + 0x26, 0x4d, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0x58, 0x9e, 0x7b, 0x7f, + 0x23, 0x76, 0xef, 0x09, ], }; - static CANONICAL_LARGEST_ED25519_S_PLUS_ONE: Scalar = Scalar { + static A_NAF: [i8; 256] = [ + 0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, -11, 0, 0, 0, 0, 3, 0, 0, + 0, 0, 1, 0, 0, 0, 0, 9, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 11, 0, 0, 0, 0, + 11, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, + 0, -1, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, -15, 0, 0, 0, 0, -7, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 5, + 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, -11, 0, 0, 0, 0, -7, 0, 0, 0, 0, -13, 0, 0, + 0, 0, 11, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, -15, 0, 0, 0, 0, 1, 0, 0, 0, 0, + 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 15, + 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, -15, 0, + 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, + ]; + + const BASEPOINT_ORDER_MINUS_ONE: Scalar = Scalar { bytes: [ - 0x7e, 0x34, 0x47, 0x75, 0x47, 0x4a, 0x7f, 0x97, - 0x23, 0xb6, 0x3a, 0x8b, 0xe9, 0x2a, 0xe7, 0x6d, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, + 0xec, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, + 0xde, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x10, ], }; - static CANONICAL_LARGEST_ED25519_S_MINUS_ONE: Scalar = Scalar { - bytes: [ - 0x7c, 0x34, 0x47, 0x75, 0x47, 0x4a, 0x7f, 0x97, - 0x23, 0xb6, 0x3a, 0x8b, 0xe9, 0x2a, 0xe7, 0x6d, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x0f, - ], - }; + /// The largest clamped integer + static LARGEST_CLAMPED_INTEGER: [u8; 32] = clamp_integer(LARGEST_UNREDUCED_SCALAR.bytes); #[test] fn fuzzer_testcase_reduction() { // LE bytes of 24519928653854221733733552434404946937899825954937634815 - let a_bytes = [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + let a_bytes = [ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ]; // LE bytes of 4975441334397345751130612518500927154628011511324180036903450236863266160640 - let b_bytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 210, 210, 210, 255, 255, 255, 255, 10]; + let b_bytes = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 210, 210, + 210, 255, 255, 255, 255, 10, + ]; // LE bytes of 6432735165214683820902750800207468552549813371247423777071615116673864412038 - let c_bytes = [134, 171, 119, 216, 180, 128, 178, 62, 171, 132, 32, 62, 34, 119, 104, 193, 47, 215, 181, 250, 14, 207, 172, 93, 75, 207, 211, 103, 144, 204, 56, 14]; + let c_bytes = [ + 134, 171, 119, 216, 180, 128, 178, 62, 171, 132, 32, 62, 34, 119, 104, 193, 47, 215, + 181, 250, 14, 207, 172, 93, 75, 207, 211, 103, 144, 204, 56, 14, + ]; let a = Scalar::from_bytes_mod_order(a_bytes); let b = Scalar::from_bytes_mod_order(b_bytes); @@ -1327,8 +1523,8 @@ mod test { tmp[0..32].copy_from_slice(&b_bytes[..]); let also_b = Scalar::from_bytes_mod_order_wide(&tmp); - let expected_c = &a * &b; - let also_expected_c = &also_a * &also_b; + let expected_c = a * b; + let also_expected_c = also_a * also_b; assert_eq!(c, expected_c); assert_eq!(c, also_expected_c); @@ -1346,7 +1542,7 @@ mod test { let naf = x.non_adjacent_form(w); // Reconstruct the scalar from the computed NAF - let mut y = Scalar::zero(); + let mut y = Scalar::ZERO; for i in (0..256).rev() { y += y; let digit = if naf[i] < 0 { @@ -1387,7 +1583,7 @@ mod test { #[test] fn scalar_mul_by_one() { - let test_scalar = &X * &Scalar::one(); + let test_scalar = X * Scalar::ONE; for i in 0..32 { assert!(test_scalar[i] == X[i]); } @@ -1395,106 +1591,43 @@ mod test { #[test] fn add_reduces() { - // Check that the addition works - assert_eq!( - (LARGEST_ED25519_S + Scalar::one()).reduce(), - CANONICAL_LARGEST_ED25519_S_PLUS_ONE - ); - // Check that the addition reduces - assert_eq!( - LARGEST_ED25519_S + Scalar::one(), - CANONICAL_LARGEST_ED25519_S_PLUS_ONE - ); + // Check that addition wraps around the modulus + assert_eq!(BASEPOINT_ORDER_MINUS_ONE + Scalar::ONE, Scalar::ZERO); } #[test] fn sub_reduces() { - // Check that the subtraction works - assert_eq!( - (LARGEST_ED25519_S - Scalar::one()).reduce(), - CANONICAL_LARGEST_ED25519_S_MINUS_ONE - ); - // Check that the subtraction reduces - assert_eq!( - LARGEST_ED25519_S - Scalar::one(), - CANONICAL_LARGEST_ED25519_S_MINUS_ONE - ); - } - - #[test] - fn quarkslab_scalar_overflow_does_not_occur() { - // Check that manually-constructing large Scalars with - // from_bits cannot produce incorrect results. - // - // The from_bits function is required to implement X/Ed25519, - // while all other methods of constructing a Scalar produce - // reduced Scalars. However, this "invariant loophole" allows - // constructing large scalars which are not reduced mod l. - // - // This issue was discovered independently by both Jack - // "str4d" Grigg (issue #238), who noted that reduction was - // not performed on addition, and Laurent Grémy & Nicolas - // Surbayrole of Quarkslab, who noted that it was possible to - // cause an overflow and compute incorrect results. - // - // This test is adapted from the one suggested by Quarkslab. - - let large_bytes = [ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7f, - ]; - - let a = Scalar::from_bytes_mod_order(large_bytes); - let b = Scalar::from_bits(large_bytes); - - assert_eq!(a, b.reduce()); - - let a_3 = a + a + a; - let b_3 = b + b + b; - - assert_eq!(a_3, b_3); - - let neg_a = -a; - let neg_b = -b; - - assert_eq!(neg_a, neg_b); - - let minus_a_3 = Scalar::zero() - a - a - a; - let minus_b_3 = Scalar::zero() - b - b - b; - - assert_eq!(minus_a_3, minus_b_3); - assert_eq!(minus_a_3, -a_3); - assert_eq!(minus_b_3, -b_3); + // Check that subtraction wraps around the modulus + assert_eq!(Scalar::ZERO - Scalar::ONE, BASEPOINT_ORDER_MINUS_ONE); } #[test] fn impl_add() { let two = Scalar::from(2u64); - let one = Scalar::one(); - let should_be_two = &one + &one; + let one = Scalar::ONE; + let should_be_two = one + one; assert_eq!(should_be_two, two); } #[allow(non_snake_case)] #[test] fn impl_mul() { - let should_be_X_times_Y = &X * &Y; + let should_be_X_times_Y = X * Y; assert_eq!(should_be_X_times_Y, X_TIMES_Y); } #[allow(non_snake_case)] #[test] + #[cfg(feature = "alloc")] fn impl_product() { // Test that product works for non-empty iterators - let X_Y_vector = vec![X, Y]; + let X_Y_vector = [X, Y]; let should_be_X_times_Y: Scalar = X_Y_vector.iter().product(); assert_eq!(should_be_X_times_Y, X_TIMES_Y); // Test that product works for the empty iterator - let one = Scalar::one(); - let empty_vector = vec![]; + let one = Scalar::ONE; + let empty_vector = []; let should_be_one: Scalar = empty_vector.iter().product(); assert_eq!(should_be_one, one); @@ -1502,7 +1635,7 @@ mod test { let xs = [Scalar::from(2u64); 10]; let ys = [Scalar::from(3u64); 10]; // now zs is an iterator with Item = Scalar - let zs = xs.iter().zip(ys.iter()).map(|(x,y)| x * y); + let zs = xs.iter().zip(ys.iter()).map(|(x, y)| x * y); let x_prod: Scalar = xs.iter().product(); let y_prod: Scalar = ys.iter().product(); @@ -1512,21 +1645,20 @@ mod test { assert_eq!(y_prod, Scalar::from(59049u64)); assert_eq!(z_prod, Scalar::from(60466176u64)); assert_eq!(x_prod * y_prod, z_prod); - } #[test] + #[cfg(feature = "alloc")] fn impl_sum() { - // Test that sum works for non-empty iterators let two = Scalar::from(2u64); - let one_vector = vec![Scalar::one(), Scalar::one()]; + let one_vector = [Scalar::ONE, Scalar::ONE]; let should_be_two: Scalar = one_vector.iter().sum(); assert_eq!(should_be_two, two); // Test that sum works for the empty iterator - let zero = Scalar::zero(); - let empty_vector = vec![]; + let zero = Scalar::ZERO; + let empty_vector = []; let should_be_zero: Scalar = empty_vector.iter().sum(); assert_eq!(should_be_zero, zero); @@ -1534,7 +1666,7 @@ mod test { let xs = [Scalar::from(1u64); 10]; let ys = [Scalar::from(2u64); 10]; // now zs is an iterator with Item = Scalar - let zs = xs.iter().zip(ys.iter()).map(|(x,y)| x + y); + let zs = xs.iter().zip(ys.iter()).map(|(x, y)| x + y); let x_sum: Scalar = xs.iter().sum(); let y_sum: Scalar = ys.iter().sum(); @@ -1548,7 +1680,7 @@ mod test { #[test] fn square() { - let expected = &X * &X; + let expected = X * X; let actual = X.unpack().square().pack(); for i in 0..32 { assert!(expected[i] == actual[i]); @@ -1566,17 +1698,15 @@ mod test { let mut bignum = [0u8; 64]; // set bignum = x + 2^256x for i in 0..32 { - bignum[ i] = X[i]; - bignum[32+i] = X[i]; + bignum[i] = X[i]; + bignum[32 + i] = X[i]; } // 3958878930004874126169954872055634648693766179881526445624823978500314864344 // = x + 2^256x (mod l) - let reduced = Scalar{ + let reduced = Scalar { bytes: [ - 216, 154, 179, 139, 210, 121, 2, 71, - 69, 99, 158, 216, 23, 173, 63, 100, - 204, 0, 91, 50, 219, 153, 57, 249, - 28, 82, 31, 197, 100, 165, 192, 8, + 216, 154, 179, 139, 210, 121, 2, 71, 69, 99, 158, 216, 23, 173, 63, 100, 204, 0, + 91, 50, 219, 153, 57, 249, 28, 82, 31, 197, 100, 165, 192, 8, ], }; let test_red = Scalar::from_bytes_mod_order_wide(&bignum); @@ -1590,8 +1720,8 @@ mod test { fn invert() { let inv_X = X.invert(); assert_eq!(inv_X, XINV); - let should_be_one = &inv_X * &X; - assert_eq!(should_be_one, Scalar::one()); + let should_be_one = inv_X * X; + assert_eq!(should_be_one, Scalar::ONE); } // Negating a scalar twice should result in the original scalar. @@ -1607,7 +1737,7 @@ mod test { #[test] fn to_bytes_from_bytes_roundtrips() { let unpacked = X.unpack(); - let bytes = unpacked.to_bytes(); + let bytes = unpacked.as_bytes(); let should_be_unpacked = UnpackedScalar::from_bytes(&bytes); assert_eq!(should_be_unpacked.0, unpacked.0); @@ -1619,17 +1749,15 @@ mod test { // set bignum = x + 2^256x for i in 0..32 { - bignum[ i] = X[i]; - bignum[32+i] = X[i]; + bignum[i] = X[i]; + bignum[32 + i] = X[i]; } // x + 2^256x (mod l) // = 3958878930004874126169954872055634648693766179881526445624823978500314864344 - let expected = Scalar{ + let expected = Scalar { bytes: [ - 216, 154, 179, 139, 210, 121, 2, 71, - 69, 99, 158, 216, 23, 173, 63, 100, - 204, 0, 91, 50, 219, 153, 57, 249, - 28, 82, 31, 197, 100, 165, 192, 8 + 216, 154, 179, 139, 210, 121, 2, 71, 69, 99, 158, 216, 23, 173, 63, 100, 204, 0, + 91, 50, 219, 153, 57, 249, 28, 82, 31, 197, 100, 165, 192, 8, ], }; let reduced = Scalar::from_bytes_mod_order_wide(&bignum); @@ -1638,8 +1766,8 @@ mod test { assert_eq!(reduced.bytes, expected.bytes); // (x + 2^256x) * R - let interim = UnpackedScalar::mul_internal(&UnpackedScalar::from_bytes_wide(&bignum), - &constants::R); + let interim = + UnpackedScalar::mul_internal(&UnpackedScalar::from_bytes_wide(&bignum), &constants::R); // ((x + 2^256x) * R) / R (mod l) let montgomery_reduced = UnpackedScalar::montgomery_reduce(&interim); @@ -1651,7 +1779,10 @@ mod test { #[test] fn canonical_decoding() { // canonical encoding of 1667457891 - let canonical_bytes = [99, 99, 99, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,]; + let canonical_bytes = [ + 99, 99, 99, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, + ]; // encoding of // 7265385991361016183439748078976496179028704920197054998554201349516117938192 @@ -1660,11 +1791,20 @@ mod test { let non_canonical_bytes_because_unreduced = [16; 32]; // encoding with high bit set, to check that the parser isn't pre-masking the high bit - let non_canonical_bytes_because_highbit = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128]; + let non_canonical_bytes_because_highbit = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 128, + ]; - assert!( Scalar::from_canonical_bytes(canonical_bytes).is_some() ); - assert!( Scalar::from_canonical_bytes(non_canonical_bytes_because_unreduced).is_none() ); - assert!( Scalar::from_canonical_bytes(non_canonical_bytes_because_highbit).is_none() ); + assert!(bool::from( + Scalar::from_canonical_bytes(canonical_bytes).is_some() + )); + assert!(bool::from( + Scalar::from_canonical_bytes(non_canonical_bytes_because_unreduced).is_none() + )); + assert!(bool::from( + Scalar::from_canonical_bytes(non_canonical_bytes_because_highbit).is_none() + )); } #[test] @@ -1679,31 +1819,36 @@ mod test { assert_eq!(encoded.len(), 32); // Check that the encoding itself matches the usual one - assert_eq!( - X, - bincode::deserialize(X.as_bytes()).unwrap(), - ); + assert_eq!(X, bincode::deserialize(X.as_bytes()).unwrap(),); } - #[cfg(debug_assertions)] + #[cfg(all(debug_assertions, feature = "alloc"))] #[test] #[should_panic] fn batch_invert_with_a_zero_input_panics() { - let mut xs = vec![Scalar::one(); 16]; - xs[3] = Scalar::zero(); + let mut xs = vec![Scalar::ONE; 16]; + xs[3] = Scalar::ZERO; // This should panic in debug mode. Scalar::batch_invert(&mut xs); } #[test] + #[cfg(feature = "alloc")] fn batch_invert_empty() { - assert_eq!(Scalar::one(), Scalar::batch_invert(&mut [])); + assert_eq!(Scalar::ONE, Scalar::batch_invert(&mut [])); } #[test] + #[cfg(feature = "alloc")] fn batch_invert_consistency() { let mut x = Scalar::from(1u64); - let mut v1: Vec<_> = (0..16).map(|_| {let tmp = x; x = x + x; tmp}).collect(); + let mut v1: Vec<_> = (0..16) + .map(|_| { + let tmp = x; + x = x + x; + tmp + }) + .collect(); let v2 = v1.clone(); let expected: Scalar = v1.iter().product(); @@ -1712,17 +1857,18 @@ mod test { assert_eq!(ret, expected); for (a, b) in v1.iter().zip(v2.iter()) { - assert_eq!(a * b, Scalar::one()); + assert_eq!(a * b, Scalar::ONE); } } + #[cfg(feature = "precomputed-tables")] fn test_pippenger_radix_iter(scalar: Scalar, w: usize) { let digits_count = Scalar::to_radix_2w_size_hint(w); - let digits = scalar.to_radix_2w(w); + let digits = scalar.as_radix_2w(w); - let radix = Scalar::from((1< impls for Scalar + #[test] + fn test_scalar_from_int() { + let s1 = Scalar::ONE; + + // For `x` in `u8`, `u16`, `u32`, `u64`, and `u128`, check that + // `Scalar::from(x + 1) == Scalar::from(x) + Scalar::from(1)` + + let x = 0x23u8; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + + let x = 0x2323u16; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + + let x = 0x2323_2323u32; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + + let x = 0x2323_2323_2323_2323u64; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + + let x = 0x2323_2323_2323_2323_2323_2323_2323_2323u128; + let sx = Scalar::from(x); + assert_eq!(sx + s1, Scalar::from(x + 1)); + } + + #[cfg(feature = "group")] + #[test] + fn ff_constants() { + assert_eq!(Scalar::from(2u64) * Scalar::TWO_INV, Scalar::ONE); + + assert_eq!( + Scalar::ROOT_OF_UNITY * Scalar::ROOT_OF_UNITY_INV, + Scalar::ONE, + ); + + // ROOT_OF_UNITY^{2^s} mod m == 1 + assert_eq!( + Scalar::ROOT_OF_UNITY.pow(&[1u64 << Scalar::S, 0, 0, 0]), + Scalar::ONE, + ); + + // DELTA^{t} mod m == 1 + assert_eq!( + Scalar::DELTA.pow(&[ + 0x9604_98c6_973d_74fb, + 0x0537_be77_a8bd_e735, + 0x0000_0000_0000_0000, + 0x0400_0000_0000_0000, + ]), + Scalar::ONE, + ); + } + + #[cfg(feature = "group")] + #[test] + fn ff_impls() { + assert!(bool::from(Scalar::ZERO.is_even())); + assert!(bool::from(Scalar::ONE.is_odd())); + assert!(bool::from(Scalar::from(2u64).is_even())); + assert!(bool::from(Scalar::DELTA.is_even())); + + assert!(bool::from(Field::invert(&Scalar::ZERO).is_none())); + assert_eq!(Field::invert(&X).unwrap(), XINV); + + let x_sq = X.square(); + // We should get back either the positive or negative root. + assert!([X, -X].contains(&x_sq.sqrt().unwrap())); + + assert_eq!(Scalar::from_repr_vartime(X.to_repr()), Some(X)); + assert_eq!(Scalar::from_repr_vartime([0xff; 32]), None); + + assert_eq!(Scalar::from_repr(X.to_repr()).unwrap(), X); + assert!(bool::from(Scalar::from_repr([0xff; 32]).is_none())); + } + + #[test] + #[should_panic] + fn test_read_le_u64_into_should_panic_on_bad_input() { + let mut dst = [0_u64; 1]; + // One byte short + read_le_u64_into(&[0xFE, 0xEF, 0x10, 0x01, 0x1F, 0xF1, 0x0F], &mut dst); + } + + #[test] + fn test_scalar_clamp() { + let input = A_SCALAR.bytes; + let expected = [ + 0x18, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d, 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, + 0x26, 0x4d, 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1, 0x58, 0x9e, 0x7b, 0x7f, + 0x23, 0x76, 0xef, 0x49, + ]; + let actual = clamp_integer(input); + assert_eq!(actual, expected); + + let expected = [ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0x40, + ]; + let actual = clamp_integer([0; 32]); + assert_eq!(expected, actual); + let expected = [ + 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0x7f, + ]; + let actual = clamp_integer([0xff; 32]); + assert_eq!(actual, expected); + + assert_eq!( + LARGEST_CLAMPED_INTEGER, + clamp_integer(LARGEST_CLAMPED_INTEGER) + ); + } + + // Check that a * b == a.reduce() * a.reduce() for ANY scalars a,b, even ones that violate + // invariant #1, i.e., a,b > 2^255. Old versions of ed25519-dalek did multiplication where a + // was reduced and b was clamped and unreduced. This checks that that was always well-defined. + #[test] + fn test_mul_reduction_invariance() { + let mut rng = rand::thread_rng(); + + for _ in 0..10 { + // Also define c that's clamped. We'll make sure that clamping doesn't affect + // computation + let (a, b, c) = { + let mut a_bytes = [0u8; 32]; + let mut b_bytes = [0u8; 32]; + let mut c_bytes = [0u8; 32]; + rng.fill_bytes(&mut a_bytes); + rng.fill_bytes(&mut b_bytes); + rng.fill_bytes(&mut c_bytes); + ( + Scalar { bytes: a_bytes }, + Scalar { bytes: b_bytes }, + Scalar { + bytes: clamp_integer(c_bytes), + }, + ) + }; + + // Make sure this is the same product no matter how you cut it + let reduced_mul_ab = a.reduce() * b.reduce(); + let reduced_mul_ac = a.reduce() * c.reduce(); + assert_eq!(a * b, reduced_mul_ab); + assert_eq!(a.reduce() * b, reduced_mul_ab); + assert_eq!(a * b.reduce(), reduced_mul_ab); + assert_eq!(a * c, reduced_mul_ac); + assert_eq!(a.reduce() * c, reduced_mul_ac); + assert_eq!(a * c.reduce(), reduced_mul_ac); + } + } } diff --git a/src/traits.rs b/curve25519-dalek/src/traits.rs similarity index 89% rename from src/traits.rs rename to curve25519-dalek/src/traits.rs index d127b3ed2..322787db5 100644 --- a/src/traits.rs +++ b/curve25519-dalek/src/traits.rs @@ -15,9 +15,8 @@ use core::borrow::Borrow; -use subtle; - -use scalar::Scalar; +use crate::scalar::{clamp_integer, Scalar}; +use subtle::ConstantTimeEq; // ------------------------------------------------------------------------ // Public Traits @@ -41,10 +40,10 @@ pub trait IsIdentity { /// constructor. impl IsIdentity for T where - T: subtle::ConstantTimeEq + Identity, + T: ConstantTimeEq + Identity, { fn is_identity(&self) -> bool { - self.ct_eq(&T::identity()).unwrap_u8() == 1u8 + self.ct_eq(&T::identity()).into() } } @@ -60,7 +59,19 @@ pub trait BasepointTable { fn basepoint(&self) -> Self::Point; /// Multiply a `scalar` by this precomputed basepoint table, in constant time. - fn basepoint_mul(&self, scalar: &Scalar) -> Self::Point; + fn mul_base(&self, scalar: &Scalar) -> Self::Point; + + /// Multiply `clamp_integer(bytes)` by this precomputed basepoint table, in constant time. For + /// a description of clamping, see [`clamp_integer`]. + fn mul_base_clamped(&self, bytes: [u8; 32]) -> Self::Point { + // Basepoint multiplication is defined for all values of `bytes` up to and including + // 2^255 - 1. The limit comes from the fact that scalar.as_radix_16() doesn't work for + // most scalars larger than 2^255. + let s = Scalar { + bytes: clamp_integer(bytes), + }; + self.mul_base(&s) + } } /// A trait for constant-time multiscalar multiplication without precomputation. @@ -84,6 +95,8 @@ pub trait MultiscalarMul { /// iterators returning either `Scalar`s or `&Scalar`s. /// /// ``` + /// # #[cfg(feature = "alloc")] + /// # { /// use curve25519_dalek::constants; /// use curve25519_dalek::traits::MultiscalarMul; /// use curve25519_dalek::ristretto::RistrettoPoint; @@ -110,6 +123,7 @@ pub trait MultiscalarMul { /// // Note: minus_abc.into_iter(): Iterator /// /// assert_eq!(A1.compress(), (-A2).compress()); + /// # } /// ``` fn multiscalar_mul(scalars: I, points: J) -> Self::Point where @@ -136,6 +150,8 @@ pub trait VartimeMultiscalarMul { /// inlining point decompression into the multiscalar call, /// avoiding the need for temporary buffers. /// ``` + /// #[cfg(feature = "alloc")] + /// # { /// use curve25519_dalek::constants; /// use curve25519_dalek::traits::VartimeMultiscalarMul; /// use curve25519_dalek::ristretto::RistrettoPoint; @@ -175,6 +191,7 @@ pub trait VartimeMultiscalarMul { /// ); /// /// assert_eq!(A3, Some(A1+A1)); + /// # } /// ``` fn optional_multiscalar_mul(scalars: I, points: J) -> Option where @@ -199,6 +216,8 @@ pub trait VartimeMultiscalarMul { /// iterators returning either `Scalar`s or `&Scalar`s. /// /// ``` + /// #[cfg(feature = "alloc")] + /// # { /// use curve25519_dalek::constants; /// use curve25519_dalek::traits::VartimeMultiscalarMul; /// use curve25519_dalek::ristretto::RistrettoPoint; @@ -225,6 +244,7 @@ pub trait VartimeMultiscalarMul { /// // Note: minus_abc.into_iter(): Iterator /// /// assert_eq!(A1.compress(), (-A2).compress()); + /// # } /// ``` fn vartime_multiscalar_mul(scalars: I, points: J) -> Self::Point where @@ -238,7 +258,7 @@ pub trait VartimeMultiscalarMul { scalars, points.into_iter().map(|P| Some(P.borrow().clone())), ) - .unwrap() + .expect("should return some point") } } @@ -254,15 +274,15 @@ pub trait VartimeMultiscalarMul { /// /// This trait has three methods for performing this computation: /// -/// * [`vartime_multiscalar_mul`], which handles the special case -/// where \\(n = 0\\) and there are no dynamic points; +/// * [`Self::vartime_multiscalar_mul`], which handles the special case where +/// \\(n = 0\\) and there are no dynamic points; /// -/// * [`vartime_mixed_multiscalar_mul`], which takes the dynamic -/// points as already-validated `Point`s and is infallible; +/// * [`Self::vartime_mixed_multiscalar_mul`], which takes the dynamic points as +/// already-validated `Point`s and is infallible; /// -/// * [`optional_mixed_multiscalar_mul`], which takes the dynamic -/// points as `Option`s and returns an `Option`, -/// allowing decompression to be composed into the input iterators. +/// * [`Self::optional_mixed_multiscalar_mul`], which takes the dynamic points +/// as `Option`s and returns an `Option`, allowing decompression +/// to be composed into the input iterators. /// /// All methods require that the lengths of the input iterators be /// known and matching, as if they were `ExactSizeIterator`s. (It @@ -344,7 +364,7 @@ pub trait VartimePrecomputedMultiscalarMul: Sized { dynamic_scalars, dynamic_points.into_iter().map(|P| Some(P.borrow().clone())), ) - .unwrap() + .expect("should return some point") } /// Given `static_scalars`, an iterator of public scalars @@ -388,6 +408,7 @@ pub trait VartimePrecomputedMultiscalarMul: Sized { /// This trait is only for debugging/testing, since it should be /// impossible for a `curve25519-dalek` user to construct an invalid /// point. +#[allow(dead_code)] pub(crate) trait ValidityCheck { /// Checks whether the point is on the curve. Not CT. fn is_valid(&self) -> bool; diff --git a/curve25519-dalek/src/window.rs b/curve25519-dalek/src/window.rs new file mode 100644 index 000000000..43c4b3abb --- /dev/null +++ b/curve25519-dalek/src/window.rs @@ -0,0 +1,276 @@ +// -*- mode: rust; -*- +// +// This file is part of curve25519-dalek. +// Copyright (c) 2016-2021 isis lovecruft +// Copyright (c) 2016-2019 Henry de Valence +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - Henry de Valence + +//! Code for fixed- and sliding-window functionality + +#![allow(non_snake_case)] + +use core::fmt::Debug; + +use cfg_if::cfg_if; + +use subtle::Choice; +use subtle::ConditionallyNegatable; +use subtle::ConditionallySelectable; +use subtle::ConstantTimeEq; + +use crate::traits::Identity; + +use crate::backend::serial::curve_models::AffineNielsPoint; +use crate::backend::serial::curve_models::ProjectiveNielsPoint; +use crate::edwards::EdwardsPoint; + +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + +macro_rules! impl_lookup_table { + (Name = $name:ident, Size = $size:expr, SizeNeg = $neg:expr, SizeRange = $range:expr, ConversionRange = $conv_range:expr) => { + /// A lookup table of precomputed multiples of a point \\(P\\), used to + /// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\). + /// + /// The computation of \\( xP \\) is done in constant time by the `select` function. + /// + /// Since `LookupTable` does not implement `Index`, it's more difficult + /// to accidentally use the table directly. Unfortunately the table is + /// only `pub(crate)` so that we can write hardcoded constants, so it's + /// still technically possible. It would be nice to prevent direct + /// access to the table. + #[derive(Copy, Clone)] + pub struct $name(pub(crate) [T; $size]); + + impl $name + where + T: Identity + ConditionallySelectable + ConditionallyNegatable, + { + /// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time. + pub fn select(&self, x: i8) -> T { + debug_assert!(x >= $neg); + debug_assert!(x as i16 <= $size as i16); // XXX We have to convert to i16s here for the radix-256 case.. this is wrong. + + // Compute xabs = |x| + let xmask = x as i16 >> 7; + let xabs = (x as i16 + xmask) ^ xmask; + + // Set t = 0 * P = identity + let mut t = T::identity(); + for j in $range { + // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. + let c = (xabs as u16).ct_eq(&(j as u16)); + t.conditional_assign(&self.0[j - 1], c); + } + // Now t == |x| * P. + + let neg_mask = Choice::from((xmask & 1) as u8); + t.conditional_negate(neg_mask); + // Now t == x * P. + + t + } + } + + impl Default for $name { + fn default() -> $name { + $name([T::default(); $size]) + } + } + + impl Debug for $name { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}(", stringify!($name))?; + + for x in self.0.iter() { + write!(f, "{:?}", x)?; + } + + write!(f, ")") + } + } + + impl<'a> From<&'a EdwardsPoint> for $name { + fn from(P: &'a EdwardsPoint) -> Self { + let mut points = [P.as_projective_niels(); $size]; + for j in $conv_range { + points[j + 1] = (P + &points[j]).as_extended().as_projective_niels(); + } + $name(points) + } + } + + impl<'a> From<&'a EdwardsPoint> for $name { + fn from(P: &'a EdwardsPoint) -> Self { + let mut points = [P.as_affine_niels(); $size]; + // XXX batch inversion would be good if perf mattered here + for j in $conv_range { + points[j + 1] = (P + &points[j]).as_extended().as_affine_niels() + } + $name(points) + } + } + + #[cfg(feature = "zeroize")] + impl Zeroize for $name + where + T: Copy + Default + Zeroize, + { + fn zeroize(&mut self) { + self.0.iter_mut().zeroize(); + } + } + }; +} // End macro_rules! impl_lookup_table + +// The first one has to be named "LookupTable" because it's used as a constructor for consts. +// This is radix-16 +impl_lookup_table! { + Name = LookupTable, + Size = 8, + SizeNeg = -8, + SizeRange = 1..9, + ConversionRange = 0..7 +} + +// The rest only get used to make basepoint tables +cfg_if! { + if #[cfg(feature = "precomputed-tables")] { + // radix-32 + impl_lookup_table! { + Name = LookupTableRadix32, + Size = 16, + SizeNeg = -16, + SizeRange = 1..17, + ConversionRange = 0..15 + } + // radix-64 + impl_lookup_table! { + Name = LookupTableRadix64, + Size = 32, + SizeNeg = -32, + SizeRange = 1..33, + ConversionRange = 0..31 + } + // radix-128 + impl_lookup_table! { + Name = LookupTableRadix128, + Size = 64, + SizeNeg = -64, + SizeRange = 1..65, + ConversionRange = 0..63 + } + // radix-256 + impl_lookup_table! { + Name = LookupTableRadix256, + Size = 128, + SizeNeg = -128, + SizeRange = 1..129, + ConversionRange = 0..127 + } + + // For homogeneity we then alias it to "LookupTableRadix16". + pub(crate) type LookupTableRadix16 = LookupTable; + } +} + +/// Holds odd multiples 1A, 3A, ..., 15A of a point A. +#[derive(Copy, Clone)] +pub(crate) struct NafLookupTable5(pub(crate) [T; 8]); + +impl NafLookupTable5 { + /// Given public, odd \\( x \\) with \\( 0 < x < 2^4 \\), return \\(xA\\). + pub fn select(&self, x: usize) -> T { + debug_assert_eq!(x & 1, 1); + debug_assert!(x < 16); + + self.0[x / 2] + } +} + +impl Debug for NafLookupTable5 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "NafLookupTable5({:?})", self.0) + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.as_projective_niels(); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.as_affine_niels(); 8]; + let A2 = A.double(); + for i in 0..7 { + Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_affine_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] + NafLookupTable5(Ai) + } +} + +/// Holds stuff up to 8. The only time we use tables this big is for precomputed basepoint tables +/// and multiscalar multiplication (which requires alloc). +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +#[derive(Copy, Clone)] +pub(crate) struct NafLookupTable8(pub(crate) [T; 64]); + +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +impl NafLookupTable8 { + pub fn select(&self, x: usize) -> T { + debug_assert_eq!(x & 1, 1); + debug_assert!(x < 128); + + self.0[x / 2] + } +} + +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +impl Debug for NafLookupTable8 { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + writeln!(f, "NafLookupTable8([")?; + for i in 0..64 { + writeln!(f, "\t{:?},", &self.0[i])?; + } + write!(f, "])") + } +} + +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.as_projective_niels(); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_projective_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} + +#[cfg(any(feature = "precomputed-tables", feature = "alloc"))] +impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { + fn from(A: &'a EdwardsPoint) -> Self { + let mut Ai = [A.as_affine_niels(); 64]; + let A2 = A.double(); + for i in 0..63 { + Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_affine_niels(); + } + // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] + NafLookupTable8(Ai) + } +} diff --git a/curve25519-dalek/tests/build_tests.sh b/curve25519-dalek/tests/build_tests.sh new file mode 100755 index 000000000..ac6e7819d --- /dev/null +++ b/curve25519-dalek/tests/build_tests.sh @@ -0,0 +1,88 @@ +#!/bin/bash + +function match_and_report() { + PATTERN=$1 + FILE=$2 + + if grep -q "$PATTERN" "$FILE"; then + echo build OK "$FILE" : "$PATTERN" + else + echo build ERROR "$FILE" : "$PATTERN" + echo ">>>>>>>>>>>>>>>>>>>>>>>>>>" + cat "$FILE" + echo "<<<<<<<<<<<<<<<<<<<<<<<<<<" + exit 1 + fi +} + +# Assuming naively 64 bit host +cargo clean +OUT=build_1.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'simd'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# Override to 32 bits assuming naively 64 bit build host +cargo clean +OUT=build_2.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# Override to 64 bits on 32 bit target +cargo clean +OUT=build_3.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_bits=\"64\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# 32 bit target default +cargo clean +OUT=build_4.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target i686-unknown-linux-gnu > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# wasm 32 bit target default +cargo clean +OUT=build_5.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# wasm 32 bit target default +# Attempted override w/ "simd" should result "serial" addition +cargo clean +OUT=build_5_1.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"simd\"" cargo build --target wasm32-unknown-unknown > "$OUT" 2>&1 +# This overide must fail the compilation since "simd" is not available +# See: issues/532 +match_and_report "Could not override curve25519_dalek_backend to simd" "$OUT" + +# fiat override with default 64 bit naive host assumption +cargo clean +OUT=build_6.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"fiat\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'fiat'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# fiat 32 bit override +cargo clean +OUT=build_7.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"fiat\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'fiat'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" + +# serial override with default 64 bit naive host assumption +cargo clean +OUT=build_8.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"serial\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '64'" "$OUT" + +# serial 32 bit override +cargo clean +OUT=build_9.txt +env RUSTFLAGS="--cfg curve25519_dalek_diagnostics=\"build\" --cfg curve25519_dalek_backend=\"serial\" --cfg curve25519_dalek_bits=\"32\"" cargo build > "$OUT" 2>&1 +match_and_report "curve25519_dalek_backend is 'serial'" "$OUT" +match_and_report "curve25519_dalek_bits is '32'" "$OUT" diff --git a/vendor/ristretto.sage b/curve25519-dalek/vendor/ristretto.sage similarity index 100% rename from vendor/ristretto.sage rename to curve25519-dalek/vendor/ristretto.sage diff --git a/docs/assets/rustdoc-include-katex-header.html b/docs/assets/rustdoc-include-katex-header.html deleted file mode 100644 index bc4e3d8a9..000000000 --- a/docs/assets/rustdoc-include-katex-header.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/ed25519-dalek/.gitignore b/ed25519-dalek/.gitignore new file mode 100644 index 000000000..778540f75 --- /dev/null +++ b/ed25519-dalek/.gitignore @@ -0,0 +1,12 @@ +target + +.cargo + +*~ +\#* +.\#* +*.swp +*.orig +*.bak + +*.s diff --git a/ed25519-dalek/.travis.yml b/ed25519-dalek/.travis.yml new file mode 100644 index 000000000..72f94de7d --- /dev/null +++ b/ed25519-dalek/.travis.yml @@ -0,0 +1,33 @@ +language: rust + +rust: + - stable + - beta + - nightly + +env: + - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='' + +matrix: + include: + # We use the 64-bit optimised curve backend by default, so also test with + # the 32-bit backend (this also exercises testing with `no_std`): + - rust: nightly + env: TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend alloc' + # Also test the batch feature: + - rust: nightly + env: TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u64_backend alloc batch' + # Test any nightly gated features on nightly: + - rust: nightly + env: TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='nightly' + # Test serde support on stable, assuming that if it works there it'll work everywhere: + - rust: stable + env: TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='serde' + +script: + - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS + +notifications: + slack: + rooms: + - dalek-cryptography:Xxv9WotKYWdSoKlgKNqXiHoD#dalek-bots diff --git a/ed25519-dalek/CHANGELOG.md b/ed25519-dalek/CHANGELOG.md new file mode 100644 index 000000000..9d1b65e6b --- /dev/null +++ b/ed25519-dalek/CHANGELOG.md @@ -0,0 +1,52 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +Entries are listed in reverse chronological order per undeprecated major series. + +# Unreleased + +# 2.x series + +## 2.1.1 + +* Fix nightly SIMD build + +## 2.1.0 + +* Add `SigningKey::to_scalar_bytes` for getting the unclamped scalar from a signing key +* Loosened `signature` dependency to allow version 2.2 + +## 2.0.0 + +### Breaking changes + +* Bump MSRV from 1.41 to 1.60.0 +* Bump Rust edition +* Bump `signature` dependency to 2.0 +* Make `digest` an optional dependency +* Make `zeroize` an optional dependency +* Make `rand_core` an optional dependency +* [curve25519 backends] are now automatically selected +* [curve25519 backends] are now overridable via cfg instead of using additive features +* Make all batch verification deterministic remove `batch_deterministic` (PR [#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) +* Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` +* Remove default-public `ExpandedSecretKey` API (PR [#205](https://github.com/dalek-cryptography/ed25519-dalek/pull/205)) +* Make `hazmat` feature to expose `ExpandedSecretKey`, `raw_sign()`, `raw_sign_prehashed()`, `raw_verify()`, and `raw_verify_prehashed()` + +[curve25519 backends]: https://github.com/dalek-cryptography/curve25519-dalek/#backends + +### Other changes + +* Add `Context` type for prehashed signing +* Add `VerifyingKey::{verify_prehash_strict, is_weak}` +* Add `pkcs` feature to support PKCS #8 (de)serialization of `SigningKey` and `VerifyingKey` +* Add `fast` feature to include basepoint tables +* Add tests for validation criteria +* Impl `DigestSigner`/`DigestVerifier` for `SigningKey`/`VerifyingKey`, respectively +* Impl `Hash` for `VerifyingKey` +* Impl `Clone`, `Drop`, and `ZeroizeOnDrop` for `SigningKey` +* Remove `rand` dependency +* Improve key deserialization diagnostics diff --git a/ed25519-dalek/Cargo.toml b/ed25519-dalek/Cargo.toml new file mode 100644 index 000000000..626b8da92 --- /dev/null +++ b/ed25519-dalek/Cargo.toml @@ -0,0 +1,78 @@ +[package] +name = "ed25519-dalek" +version = "2.1.1" +edition = "2021" +authors = [ + "isis lovecruft ", + "Tony Arcieri ", + "Michael Rosenberg " +] +readme = "README.md" +license = "BSD-3-Clause" +repository = "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/ed25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" +documentation = "https://docs.rs/ed25519-dalek" +keywords = ["cryptography", "ed25519", "curve25519", "signature", "ECC"] +categories = ["cryptography", "no-std"] +description = "Fast and efficient ed25519 EdDSA key generations, signing, and verification in pure Rust." +exclude = [ ".gitignore", "TESTVECTORS", "VALIDATIONVECTORS", "res/*" ] +rust-version = "1.60" + +[package.metadata.docs.rs] +rustdoc-args = [ + "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", + "--cfg", "docsrs", +] +features = ["batch", "digest", "hazmat", "pem", "serde"] + +[dependencies] +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest"] } +ed25519 = { version = ">=2.2, <2.3", default-features = false } +signature = { version = ">=2.0, <2.3", optional = true, default-features = false } +sha2 = { version = "0.10", default-features = false } +subtle = { version = "2.3.0", default-features = false } + +# optional features +merlin = { version = "3", default-features = false, optional = true } +rand_core = { version = "0.6.4", default-features = false, optional = true } +serde = { version = "1.0", default-features = false, optional = true } +zeroize = { version = "1.5", default-features = false, optional = true } + +[dev-dependencies] +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false, features = ["digest", "rand_core"] } +x25519-dalek = { version = "2", path = "../x25519-dalek", default-features = false, features = ["static_secrets"] } +blake2 = "0.10" +sha3 = "0.10" +hex = "0.4" +bincode = "1.0" +serde_json = "1.0" +criterion = { version = "0.5", features = ["html_reports"] } +hex-literal = "0.4" +rand = "0.8" +rand_core = { version = "0.6.4", default-features = false } +serde = { version = "1.0", features = ["derive"] } +toml = { version = "0.7" } + +[[bench]] +name = "ed25519_benchmarks" +harness = false +required-features = ["rand_core"] + +[features] +default = ["fast", "std", "zeroize"] +alloc = ["curve25519-dalek/alloc", "ed25519/alloc", "serde?/alloc", "zeroize/alloc"] +std = ["alloc", "ed25519/std", "serde?/std", "sha2/std"] + +asm = ["sha2/asm"] +batch = ["alloc", "merlin", "rand_core"] +fast = ["curve25519-dalek/precomputed-tables"] +digest = ["signature/digest"] +# Exposes the hazmat module +hazmat = [] +# Turns off stricter checking for scalar malleability in signatures +legacy_compatibility = ["curve25519-dalek/legacy_compatibility"] +pkcs8 = ["ed25519/pkcs8"] +pem = ["alloc", "ed25519/pem", "pkcs8"] +rand_core = ["dep:rand_core"] +serde = ["dep:serde", "ed25519/serde"] +zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] diff --git a/ed25519-dalek/LICENSE b/ed25519-dalek/LICENSE new file mode 100644 index 000000000..acf8498e2 --- /dev/null +++ b/ed25519-dalek/LICENSE @@ -0,0 +1,28 @@ +Copyright (c) 2017-2019 isis agora lovecruft. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/ed25519-dalek/README.md b/ed25519-dalek/README.md new file mode 100644 index 000000000..dbb14b00b --- /dev/null +++ b/ed25519-dalek/README.md @@ -0,0 +1,178 @@ +# ed25519-dalek [![](https://img.shields.io/crates/v/ed25519-dalek.svg)](https://crates.io/crates/ed25519-dalek) [![](https://docs.rs/ed25519-dalek/badge.svg)](https://docs.rs/ed25519-dalek) [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/ed25519-dalek.yml) + +Fast and efficient Rust implementation of ed25519 key generation, signing, and +verification. + +# Use + +To import `ed25519-dalek`, add the following to the dependencies section of +your project's `Cargo.toml`: +```toml +ed25519-dalek = "2" +``` + +# Feature Flags + +This crate is `#[no_std]` compatible with `default-features = false`. + +| Feature | Default? | Description | +| :--- | :--- | :--- | +| `alloc` | ✓ | When `pkcs8` is enabled, implements `EncodePrivateKey`/`EncodePublicKey` for `SigningKey`/`VerifyingKey`, respectively. | +| `std` | ✓ | Implements `std::error::Error` for `SignatureError`. Also enables `alloc`. | +| `zeroize` | ✓ | Implements `Zeroize` and `ZeroizeOnDrop` for `SigningKey` | +| `rand_core` | | Enables `SigningKey::generate` | +| `batch` | | Enables `verify_batch` for verifying many signatures quickly. Also enables `rand_core`. | +| `digest` | | Enables `Context`, `SigningKey::{with_context, sign_prehashed}` and `VerifyingKey::{with_context, verify_prehashed, verify_prehashed_strict}` for Ed25519ph prehashed signatures | +| `asm` | | Enables assembly optimizations in the SHA-512 compression functions | +| `pkcs8` | | Enables [PKCS#8](https://en.wikipedia.org/wiki/PKCS_8) serialization/deserialization for `SigningKey` and `VerifyingKey` | +| `pem` | | Enables PEM serialization support for PKCS#8 private keys and SPKI public keys. Also enables `alloc`. | +| `legacy_compatibility` | | **Unsafe:** Disables certain signature checks. See [below](#malleability-and-the-legacy_compatibility-feature) | +| `hazmat` | | **Unsafe:** Exposes the `hazmat` module for raw signing/verifying. Misuse of these functions will expose the private key, as in the [signing oracle attack](https://github.com/MystenLabs/ed25519-unsafe-libs). | + +# Major Changes + +See [CHANGELOG.md](CHANGELOG.md) for a list of changes made in past versions of this crate. + +## Breaking Changes in 2.0.0 + +* Bump MSRV from 1.41 to 1.60.0 +* Bump Rust edition +* Bump `signature` dependency to 2.0 +* Make `digest` an optional dependency +* Make `zeroize` an optional dependency +* Make `rand_core` an optional dependency +* Adopt [curve25519-backend selection](https://github.com/dalek-cryptography/curve25519-dalek/#backends) over features +* Make all batch verification deterministic remove `batch_deterministic` ([#256](https://github.com/dalek-cryptography/ed25519-dalek/pull/256)) +* Remove `ExpandedSecretKey` API ([#205](https://github.com/dalek-cryptography/ed25519-dalek/pull/205)) +* Rename `Keypair` → `SigningKey` and `PublicKey` → `VerifyingKey` +* Make `hazmat` feature to expose, `ExpandedSecretKey`, `raw_sign()`, `raw_sign_prehashed()`, `raw_verify()`, and `raw_verify_prehashed()` + +# Documentation + +Documentation is available [here](https://docs.rs/ed25519-dalek). + +# Compatibility Policies + +All on-by-default features of this library are covered by [semantic versioning](https://semver.org/spec/v2.0.0.html) (SemVer). +SemVer exemptions are outlined below for MSRV and public API. + +## Minimum Supported Rust Version + +| Releases | MSRV | +| :--- | :--- | +| 2.x | 1.60 | +| 1.x | 1.41 | + +From 2.x onwards, MSRV changes will be accompanied by a minor version bump. + +## Public API SemVer Exemptions + +Breaking changes to SemVer-exempted components affecting the public API will be accompanied by some version bump. + +Below are the specific policies: + +| Releases | Public API Component(s) | Policy | +| :--- | :--- | :--- | +| 2.x | Dependencies `digest`, `pkcs8` and `rand_core` | Minor SemVer bump | + +# Safety + +`ed25519-dalek` is designed to prevent misuse. Signing is constant-time, all signing keys are zeroed when they go out of scope (unless `zeroize` is disabled), detached public keys [cannot](https://github.com/MystenLabs/ed25519-unsafe-libs/blob/main/README.md) be used for signing, and extra functions like [`VerifyingKey::verify_strict`](#weak-key-forgery-and-verify_strict) are made available to avoid known gotchas. + +Further, this crate has no—and in fact forbids—unsafe code. You can opt in to using some highly optimized unsafe code that resides in `curve25519-dalek`, though. See [below](#microarchitecture-specific-backends) for more information on backend selection. + +# Performance + +Performance is a secondary goal behind correctness, safety, and clarity, but we +aim to be competitive with other implementations. + +## Benchmarks + +Benchmarks are run using [criterion.rs](https://github.com/japaric/criterion.rs): + +```sh +cargo bench --features "batch" +# Uses avx2 or ifma only if compiled for an appropriate target. +export RUSTFLAGS='-C target_cpu=native' +cargo +nightly bench --features "batch" +``` + +On an Intel 10700K running at stock comparing between the `curve25519-dalek` backends. + +| Benchmark | u64 | simd +avx2 | fiat | +| :--- | :---- | :--- | :--- | +| signing | 15.017 µs | 13.906 µs -7.3967% | 15.877 μs +5.7268% | +| signature verification | 40.144 µs | 25.963 µs -35.603% | 42.118 μs +4.9173% | +| strict signature verification | 41.334 µs | 27.874 µs -32.660% | 43.985 μs +6.4136% | +| batch signature verification/4 | 109.44 µs | 81.778 µs -25.079% | 117.80 μs +7.6389% | +| batch signature verification/8 | 182.75 µs | 138.40 µs -23.871% | 195.86 μs +7.1737% | +| batch signature verification/16 | 328.67 µs | 251.39 µs -23.744% | 351.55 μs +6.9614% | +| batch signature verification/32 | 619.49 µs | 477.36 µs -23.053% | 669.41 μs +8.0582% | +| batch signature verification/64 | 1.2136 ms | 936.85 µs -22.543% | 1.3028 ms +7.3500% | +| batch signature verification/96 | 1.8677 ms | 1.2357 ms -33.936% | 2.0552 ms +10.039% | +| batch signature verification/128| 2.3281 ms | 1.5795 ms -31.996% | 2.5596 ms +9.9437% | +| batch signature verification/256| 4.1868 ms | 2.8864 ms -31.061% | 4.6494 μs +11.049% | +| keypair generation | 13.973 µs | 13.108 µs -6.5062% | 15.099 μs +8.0584% | + +## Batch Performance + +If your protocol or application is able to batch signatures for verification, +the [`verify_batch`][func_verify_batch] function has greatly improved performance. + +As you can see, there's an optimal batch size for each machine, so you'll likely +want to test the benchmarks on your target CPU to discover the best size. + +## (Micro)Architecture Specific Backends + +A _backend_ refers to an implementation of elliptic curve and scalar arithmetic. Different backends have different use cases. For example, if you demand formally verified code, you want to use the `fiat` backend (as it was generated from [Fiat Crypto][fiat]). + +Backend selection details and instructions can be found in the [curve25519-dalek docs](https://github.com/dalek-cryptography/curve25519-dalek#backends). + +# Contributing + +See [CONTRIBUTING.md](../CONTRIBUTING.md) + +# Batch Signature Verification + +The standard variants of batch signature verification (i.e. many signatures made with potentially many different public keys over potentially many different messages) is available via the `batch` feature. It uses deterministic randomness, i.e., it hashes the inputs (using [`merlin`](https://merlin.cool/), which handles transcript item separation) and uses the result to generate random coefficients. Batch verification requires allocation, so this won't function in heapless settings. + +# Validation Criteria + +The _validation criteria_ of a signature scheme are the criteria that signatures and public keys must satisfy in order to be accepted. Unfortunately, Ed25519 has some underspecified parts, leading to different validation criteria across implementations. For a very good overview of this, see [Henry's post][validation]. + +In this section, we mention some specific details about our validation criteria, and how to navigate them. + +## Malleability and the `legacy_compatibility` Feature + +A signature scheme is considered to produce _malleable signatures_ if a passive attacker with knowledge of a public key _A_, message _m_, and valid signature _σ'_ can produce a distinct _σ'_ such that _σ'_ is a valid signature of _m_ with respect to _A_. A scheme is only malleable if the attacker can do this _without_ knowledge of the private key corresponding to _A_. + +`ed25519-dalek` is not a malleable signature scheme. + +Some other Ed25519 implementations are malleable, though, such as [libsodium with `ED25519_COMPAT` enabled](https://github.com/jedisct1/libsodium/blob/24211d370a9335373f0715664271dfe203c7c2cd/src/libsodium/crypto_sign/ed25519/ref10/open.c#L30), [ed25519-donna](https://github.com/floodyberry/ed25519-donna/blob/8757bd4cd209cb032853ece0ce413f122eef212c/ed25519.c#L100), [NaCl's ref10 impl](https://github.com/floodyberry/ed25519-donna/blob/8757bd4cd209cb032853ece0ce413f122eef212c/fuzz/ed25519-ref10.c#L4627), and probably a lot more. +If you need to interoperate with such implementations and accept otherwise invalid signatures, you can enable the `legacy_compatibility` flag. **Do not enable `legacy_compatibility`** if you don't have to, because it will make your signatures malleable. + +Note: [CIRCL](https://github.com/cloudflare/circl/blob/fa6e0cca79a443d7be18ed241e779adf9ed2a301/sign/ed25519/ed25519.go#L358) has no scalar range check at all. We do not have a feature flag for interoperating with the larger set of RFC-disallowed signatures that CIRCL accepts. + +## Weak key Forgery and `verify_strict()` + +A _signature forgery_ is what it sounds like: it's when an attacker, given a public key _A_, creates a signature _σ_ and message _m_ such that _σ_ is a valid signature of _m_ with respect to _A_. Since this is the core security definition of any signature scheme, Ed25519 signatures cannot be forged. + +However, there's a much looser kind of forgery that Ed25519 permits, which we call _weak key forgery_. An attacker can produce a special public key _A_ (which we call a _weak_ public key) and a signature _σ_ such that _σ_ is a valid signature of _any_ message _m_, with respect to _A_, with high probability. This attack is acknowledged in the [Ed25519 paper](https://ed25519.cr.yp.to/ed25519-20110926.pdf), and caused an exploitable bug in the Scuttlebutt protocol ([paper](https://eprint.iacr.org/2019/526.pdf), section 7.1). The [`VerifyingKey::verify()`][method_verify] function permits weak keys. + +We provide [`VerifyingKey::verify_strict`][method_verify_strict] (and [`verify_strict_prehashed`][method_verify_strict_ph]) to help users avoid these scenarios. These functions perform an extra check on _A_, ensuring it's not a weak public key. In addition, we provide the [`VerifyingKey::is_weak`][method_is_weak] to allow users to perform this check before attempting signature verification. + +## Batch verification + +As mentioned above, weak public keys can be used to produce signatures for unknown messages with high probability. This means that sometimes a weak forgery attempt will fail. In fact, it can fail up to 7/8 of the time. If you call `verify()` twice on the same failed forgery, it will return an error both times, as expected. However, if you call `verify_batch()` twice on two distinct otherwise-valid batches, both of which contain the failed forgery, there's a 21% chance that one fails and the other succeeds. + +Why is this? It's because `verify_batch()` does not do the weak key testing of `verify_strict()`, and it multiplies each verification equation by some random coefficient. If the failed forgery gets multiplied by 8, then the weak key (which is a low-order point) becomes 0, and the verification equation on the attempted forgery will succeed. + +Since `verify_batch()` is intended to be high-throughput, we think it's best not to put weak key checks in it. If you want to prevent weird behavior due to weak public keys in your batches, you should call [`VerifyingKey::is_weak`][method_is_weak] on the inputs in advance. + +[fiat]: https://github.com/mit-plv/fiat-crypto +[validation]: https://hdevalence.ca/blog/2020-10-04-its-25519am +[func_verify_batch]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/fn.verify_batch.html +[method_verify]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html#method.verify +[method_verify_strict]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html#method.verify_strict +[method_verify_strict_ph]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html#method.verify_strict_prehashed +[method_is_weak]: https://docs.rs/ed25519-dalek/latest/ed25519_dalek/struct.VerifyingKey.html#method.is_weak diff --git a/ed25519-dalek/TESTVECTORS b/ed25519-dalek/TESTVECTORS new file mode 100644 index 000000000..4234759c5 --- /dev/null +++ b/ed25519-dalek/TESTVECTORS @@ -0,0 +1,128 @@ +9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a:d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a::e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b: +4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c:3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c:72:92a009a9f0d4cab8720e820b5f642540a2b27b5416503f8fb3762223ebdb69da085ac1e43e15996e458f3613d0f11d8c387b2eaeb4302aeeb00d291612bb0c0072: +c5aa8df43f9f837bedb7442f31dcb7b166d38535076f094b85ce3a2e0b4458f7fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025:fc51cd8e6218a1a38da47ed00230f0580816ed13ba3303ac5deb911548908025:af82:6291d657deec24024827e69c3abe01a30ce548a284743a445e3680d7db5ac3ac18ff9b538d16f290ae67f760984dc6594a7c15e9716ed28dc027beceea1ec40aaf82: +0d4a05b07352a5436e180356da0ae6efa0345ff7fb1572575772e8005ed978e9e61a185bcef2613a6c7cb79763ce945d3b245d76114dd440bcf5f2dc1aa57057:e61a185bcef2613a6c7cb79763ce945d3b245d76114dd440bcf5f2dc1aa57057:cbc77b:d9868d52c2bebce5f3fa5a79891970f309cb6591e3e1702a70276fa97c24b3a8e58606c38c9758529da50ee31b8219cba45271c689afa60b0ea26c99db19b00ccbc77b: +6df9340c138cc188b5fe4464ebaa3f7fc206a2d55c3434707e74c9fc04e20ebbc0dac102c4533186e25dc43128472353eaabdb878b152aeb8e001f92d90233a7:c0dac102c4533186e25dc43128472353eaabdb878b152aeb8e001f92d90233a7:5f4c8989:124f6fc6b0d100842769e71bd530664d888df8507df6c56dedfdb509aeb93416e26b918d38aa06305df3095697c18b2aa832eaa52edc0ae49fbae5a85e150c075f4c8989: +b780381a65edf8b78f6945e8dbec7941ac049fd4c61040cf0c324357975a293ce253af0766804b869bb1595be9765b534886bbaab8305bf50dbc7f899bfb5f01:e253af0766804b869bb1595be9765b534886bbaab8305bf50dbc7f899bfb5f01:18b6bec097:b2fc46ad47af464478c199e1f8be169f1be6327c7f9a0a6689371ca94caf04064a01b22aff1520abd58951341603faed768cf78ce97ae7b038abfe456aa17c0918b6bec097: +78ae9effe6f245e924a7be63041146ebc670dbd3060cba67fbc6216febc44546fbcfbfa40505d7f2be444a33d185cc54e16d615260e1640b2b5087b83ee3643d:fbcfbfa40505d7f2be444a33d185cc54e16d615260e1640b2b5087b83ee3643d:89010d855972:6ed629fc1d9ce9e1468755ff636d5a3f40a5d9c91afd93b79d241830f7e5fa29854b8f20cc6eecbb248dbd8d16d14e99752194e4904d09c74d639518839d230089010d855972: +691865bfc82a1e4b574eecde4c7519093faf0cf867380234e3664645c61c5f7998a5e3a36e67aaba89888bf093de1ad963e774013b3902bfab356d8b90178a63:98a5e3a36e67aaba89888bf093de1ad963e774013b3902bfab356d8b90178a63:b4a8f381e70e7a:6e0af2fe55ae377a6b7a7278edfb419bd321e06d0df5e27037db8812e7e3529810fa5552f6c0020985ca17a0e02e036d7b222a24f99b77b75fdd16cb05568107b4a8f381e70e7a: +3b26516fb3dc88eb181b9ed73f0bcd52bcd6b4c788e4bcaf46057fd078bee073f81fb54a825fced95eb033afcd64314075abfb0abd20a970892503436f34b863:f81fb54a825fced95eb033afcd64314075abfb0abd20a970892503436f34b863:4284abc51bb67235:d6addec5afb0528ac17bb178d3e7f2887f9adbb1ad16e110545ef3bc57f9de2314a5c8388f723b8907be0f3ac90c6259bbe885ecc17645df3db7d488f805fa084284abc51bb67235: +edc6f5fbdd1cee4d101c063530a30490b221be68c036f5b07d0f953b745df192c1a49c66e617f9ef5ec66bc4c6564ca33de2a5fb5e1464062e6d6c6219155efd:c1a49c66e617f9ef5ec66bc4c6564ca33de2a5fb5e1464062e6d6c6219155efd:672bf8965d04bc5146:2c76a04af2391c147082e33faacdbe56642a1e134bd388620b852b901a6bc16ff6c9cc9404c41dea12ed281da067a1513866f9d964f8bdd24953856c50042901672bf8965d04bc5146: +4e7d21fb3b1897571a445833be0f9fd41cd62be3aa04040f8934e1fcbdcacd4531b2524b8348f7ab1dfafa675cc538e9a84e3fe5819e27c12ad8bbc1a36e4dff:31b2524b8348f7ab1dfafa675cc538e9a84e3fe5819e27c12ad8bbc1a36e4dff:33d7a786aded8c1bf691:28e4598c415ae9de01f03f9f3fab4e919e8bf537dd2b0cdf6e79b9e6559c9409d9151a4c40f083193937627c369488259e99da5a9f0a87497fa6696a5dd6ce0833d7a786aded8c1bf691: +a980f892db13c99a3e8971e965b2ff3d41eafd54093bc9f34d1fd22d84115bb644b57ee30cdb55829d0a5d4f046baef078f1e97a7f21b62d75f8e96ea139c35f:44b57ee30cdb55829d0a5d4f046baef078f1e97a7f21b62d75f8e96ea139c35f:3486f68848a65a0eb5507d:77d389e599630d934076329583cd4105a649a9292abc44cd28c40000c8e2f5ac7660a81c85b72af8452d7d25c070861dae91601c7803d656531650dd4e5c41003486f68848a65a0eb5507d: +5b5a619f8ce1c66d7ce26e5a2ae7b0c04febcd346d286c929e19d0d5973bfef96fe83693d011d111131c4f3fbaaa40a9d3d76b30012ff73bb0e39ec27ab18257:6fe83693d011d111131c4f3fbaaa40a9d3d76b30012ff73bb0e39ec27ab18257:5a8d9d0a22357e6655f9c785:0f9ad9793033a2fa06614b277d37381e6d94f65ac2a5a94558d09ed6ce922258c1a567952e863ac94297aec3c0d0c8ddf71084e504860bb6ba27449b55adc40e5a8d9d0a22357e6655f9c785: +940c89fe40a81dafbdb2416d14ae469119869744410c3303bfaa0241dac57800a2eb8c0501e30bae0cf842d2bde8dec7386f6b7fc3981b8c57c9792bb94cf2dd:a2eb8c0501e30bae0cf842d2bde8dec7386f6b7fc3981b8c57c9792bb94cf2dd:b87d3813e03f58cf19fd0b6395:d8bb64aad8c9955a115a793addd24f7f2b077648714f49c4694ec995b330d09d640df310f447fd7b6cb5c14f9fe9f490bcf8cfadbfd2169c8ac20d3b8af49a0cb87d3813e03f58cf19fd0b6395: +9acad959d216212d789a119252ebfe0c96512a23c73bd9f3b202292d6916a738cf3af898467a5b7a52d33d53bc037e2642a8da996903fc252217e9c033e2f291:cf3af898467a5b7a52d33d53bc037e2642a8da996903fc252217e9c033e2f291:55c7fa434f5ed8cdec2b7aeac173:6ee3fe81e23c60eb2312b2006b3b25e6838e02106623f844c44edb8dafd66ab0671087fd195df5b8f58a1d6e52af42908053d55c7321010092748795ef94cf0655c7fa434f5ed8cdec2b7aeac173: +d5aeee41eeb0e9d1bf8337f939587ebe296161e6bf5209f591ec939e1440c300fd2a565723163e29f53c9de3d5e8fbe36a7ab66e1439ec4eae9c0a604af291a5:fd2a565723163e29f53c9de3d5e8fbe36a7ab66e1439ec4eae9c0a604af291a5:0a688e79be24f866286d4646b5d81c:f68d04847e5b249737899c014d31c805c5007a62c0a10d50bb1538c5f35503951fbc1e08682f2cc0c92efe8f4985dec61dcbd54d4b94a22547d24451271c8b000a688e79be24f866286d4646b5d81c: +0a47d10452ae2febec518a1c7c362890c3fc1a49d34b03b6467d35c904a8362d34e5a8508c4743746962c066e4badea2201b8ab484de5c4f94476ccd2143955b:34e5a8508c4743746962c066e4badea2201b8ab484de5c4f94476ccd2143955b:c942fa7ac6b23ab7ff612fdc8e68ef39:2a3d27dc40d0a8127949a3b7f908b3688f63b7f14f651aacd715940bdbe27a0809aac142f47ab0e1e44fa490ba87ce5392f33a891539caf1ef4c367cae54500cc942fa7ac6b23ab7ff612fdc8e68ef39: +f8148f7506b775ef46fdc8e8c756516812d47d6cfbfa318c27c9a22641e56f170445e456dacc7d5b0bbed23c8200cdb74bdcb03e4c7b73f0a2b9b46eac5d4372:0445e456dacc7d5b0bbed23c8200cdb74bdcb03e4c7b73f0a2b9b46eac5d4372:7368724a5b0efb57d28d97622dbde725af:3653ccb21219202b8436fb41a32ba2618c4a133431e6e63463ceb3b6106c4d56e1d2ba165ba76eaad3dc39bffb130f1de3d8e6427db5b71938db4e272bc3e20b7368724a5b0efb57d28d97622dbde725af: +77f88691c4eff23ebb7364947092951a5ff3f10785b417e918823a552dab7c7574d29127f199d86a8676aec33b4ce3f225ccb191f52c191ccd1e8cca65213a6b:74d29127f199d86a8676aec33b4ce3f225ccb191f52c191ccd1e8cca65213a6b:bd8e05033f3a8bcdcbf4beceb70901c82e31:fbe929d743a03c17910575492f3092ee2a2bf14a60a3fcacec74a58c7334510fc262db582791322d6c8c41f1700adb80027ecabc14270b703444ae3ee7623e0abd8e05033f3a8bcdcbf4beceb70901c82e31: +ab6f7aee6a0837b334ba5eb1b2ad7fcecfab7e323cab187fe2e0a95d80eff1325b96dca497875bf9664c5e75facf3f9bc54bae913d66ca15ee85f1491ca24d2c:5b96dca497875bf9664c5e75facf3f9bc54bae913d66ca15ee85f1491ca24d2c:8171456f8b907189b1d779e26bc5afbb08c67a:73bca64e9dd0db88138eedfafcea8f5436cfb74bfb0e7733cf349baa0c49775c56d5934e1d38e36f39b7c5beb0a836510c45126f8ec4b6810519905b0ca07c098171456f8b907189b1d779e26bc5afbb08c67a: +8d135de7c8411bbdbd1b31e5dc678f2ac7109e792b60f38cd24936e8a898c32d1ca281938529896535a7714e3584085b86ef9fec723f42819fc8dd5d8c00817f:1ca281938529896535a7714e3584085b86ef9fec723f42819fc8dd5d8c00817f:8ba6a4c9a15a244a9c26bb2a59b1026f21348b49:a1adc2bc6a2d980662677e7fdff6424de7dba50f5795ca90fdf3e96e256f3285cac71d3360482e993d0294ba4ec7440c61affdf35fe83e6e04263937db93f1058ba6a4c9a15a244a9c26bb2a59b1026f21348b49: +0e765d720e705f9366c1ab8c3fa84c9a44370c06969f803296884b2846a652a47fae45dd0a05971026d410bc497af5be7d0827a82a145c203f625dfcb8b03ba8:7fae45dd0a05971026d410bc497af5be7d0827a82a145c203f625dfcb8b03ba8:1d566a6232bbaab3e6d8804bb518a498ed0f904986:bb61cf84de61862207c6a455258bc4db4e15eea0317ff88718b882a06b5cf6ec6fd20c5a269e5d5c805bafbcc579e2590af414c7c227273c102a10070cdfe80f1d566a6232bbaab3e6d8804bb518a498ed0f904986: +db36e326d676c2d19cc8fe0c14b709202ecfc761d27089eb6ea4b1bb021ecfa748359b850d23f0715d94bb8bb75e7e14322eaf14f06f28a805403fbda002fc85:48359b850d23f0715d94bb8bb75e7e14322eaf14f06f28a805403fbda002fc85:1b0afb0ac4ba9ab7b7172cddc9eb42bba1a64bce47d4:b6dcd09989dfbac54322a3ce87876e1d62134da998c79d24b50bd7a6a797d86a0e14dc9d7491d6c14a673c652cfbec9f962a38c945da3b2f0879d0b68a9213001b0afb0ac4ba9ab7b7172cddc9eb42bba1a64bce47d4: +c89955e0f7741d905df0730b3dc2b0ce1a13134e44fef3d40d60c020ef19df77fdb30673402faf1c8033714f3517e47cc0f91fe70cf3836d6c23636e3fd2287c:fdb30673402faf1c8033714f3517e47cc0f91fe70cf3836d6c23636e3fd2287c:507c94c8820d2a5793cbf3442b3d71936f35fe3afef316:7ef66e5e86f2360848e0014e94880ae2920ad8a3185a46b35d1e07dea8fa8ae4f6b843ba174d99fa7986654a0891c12a794455669375bf92af4cc2770b579e0c507c94c8820d2a5793cbf3442b3d71936f35fe3afef316: +4e62627fc221142478aee7f00781f817f662e3b75db29bb14ab47cf8e84104d6b1d39801892027d58a8c64335163195893bfc1b61dbeca3260497e1f30371107:b1d39801892027d58a8c64335163195893bfc1b61dbeca3260497e1f30371107:d3d615a8472d9962bb70c5b5466a3d983a4811046e2a0ef5:836afa764d9c48aa4770a4388b654e97b3c16f082967febca27f2fc47ddfd9244b03cfc729698acf5109704346b60b230f255430089ddc56912399d1122de70ad3d615a8472d9962bb70c5b5466a3d983a4811046e2a0ef5: +6b83d7da8908c3e7205b39864b56e5f3e17196a3fc9c2f5805aad0f5554c142dd0c846f97fe28585c0ee159015d64c56311c886eddcc185d296dbb165d2625d6:d0c846f97fe28585c0ee159015d64c56311c886eddcc185d296dbb165d2625d6:6ada80b6fa84f7034920789e8536b82d5e4678059aed27f71c:16e462a29a6dd498685a3718b3eed00cc1598601ee47820486032d6b9acc9bf89f57684e08d8c0f05589cda2882a05dc4c63f9d0431d6552710812433003bc086ada80b6fa84f7034920789e8536b82d5e4678059aed27f71c: +19a91fe23a4e9e33ecc474878f57c64cf154b394203487a7035e1ad9cd697b0d2bf32ba142ba4622d8f3e29ecd85eea07b9c47be9d64412c9b510b27dd218b23:2bf32ba142ba4622d8f3e29ecd85eea07b9c47be9d64412c9b510b27dd218b23:82cb53c4d5a013bae5070759ec06c3c6955ab7a4050958ec328c:881f5b8c5a030df0f75b6634b070dd27bd1ee3c08738ae349338b3ee6469bbf9760b13578a237d5182535ede121283027a90b5f865d63a6537dca07b44049a0f82cb53c4d5a013bae5070759ec06c3c6955ab7a4050958ec328c: +1d5b8cb6215c18141666baeefcf5d69dad5bea9a3493dddaa357a4397a13d4de94d23d977c33e49e5e4992c68f25ec99a27c41ce6b91f2bfa0cd8292fe962835:94d23d977c33e49e5e4992c68f25ec99a27c41ce6b91f2bfa0cd8292fe962835:a9a8cbb0ad585124e522abbfb40533bdd6f49347b55b18e8558cb0:3acd39bec8c3cd2b44299722b5850a0400c1443590fd4861d59aae7496acb3df73fc3fdf7969ae5f50ba47dddc435246e5fd376f6b891cd4c2caf5d614b6170ca9a8cbb0ad585124e522abbfb40533bdd6f49347b55b18e8558cb0: +6a91b3227c472299089bdce9356e726a40efd840f11002708b7ee55b64105ac29d084aa8b97a6b9bafa496dbc6f76f3306a116c9d917e681520a0f914369427e:9d084aa8b97a6b9bafa496dbc6f76f3306a116c9d917e681520a0f914369427e:5cb6f9aa59b80eca14f6a68fb40cf07b794e75171fba96262c1c6adc:f5875423781b66216cb5e8998de5d9ffc29d1d67107054ace3374503a9c3ef811577f269de81296744bd706f1ac478caf09b54cdf871b3f802bd57f9a6cb91015cb6f9aa59b80eca14f6a68fb40cf07b794e75171fba96262c1c6adc: +93eaa854d791f05372ce72b94fc6503b2ff8ae6819e6a21afe825e27ada9e4fb16cee8a3f2631834c88b670897ff0b08ce90cc147b4593b3f1f403727f7e7ad5:16cee8a3f2631834c88b670897ff0b08ce90cc147b4593b3f1f403727f7e7ad5:32fe27994124202153b5c70d3813fdee9c2aa6e7dc743d4d535f1840a5:d834197c1a3080614e0a5fa0aaaa808824f21c38d692e6ffbd200f7dfb3c8f44402a7382180b98ad0afc8eec1a02acecf3cb7fde627b9f18111f260ab1db9a0732fe27994124202153b5c70d3813fdee9c2aa6e7dc743d4d535f1840a5: +941cac69fb7b1815c57bb987c4d6c2ad2c35d5f9a3182a79d4ba13eab253a8ad23be323c562dfd71ce65f5bba56a74a3a6dfc36b573d2f94f635c7f9b4fd5a5b:23be323c562dfd71ce65f5bba56a74a3a6dfc36b573d2f94f635c7f9b4fd5a5b:bb3172795710fe00054d3b5dfef8a11623582da68bf8e46d72d27cece2aa:0f8fad1e6bde771b4f5420eac75c378bae6db5ac6650cd2bc210c1823b432b48e016b10595458ffab92f7a8989b293ceb8dfed6c243a2038fc06652aaaf16f02bb3172795710fe00054d3b5dfef8a11623582da68bf8e46d72d27cece2aa: +1acdbb793b0384934627470d795c3d1dd4d79cea59ef983f295b9b59179cbb283f60c7541afa76c019cf5aa82dcdb088ed9e4ed9780514aefb379dabc844f31a:3f60c7541afa76c019cf5aa82dcdb088ed9e4ed9780514aefb379dabc844f31a:7cf34f75c3dac9a804d0fcd09eba9b29c9484e8a018fa9e073042df88e3c56:be71ef4806cb041d885effd9e6b0fbb73d65d7cdec47a89c8a994892f4e55a568c4cc78d61f901e80dbb628b86a23ccd594e712b57fa94c2d67ec266348785077cf34f75c3dac9a804d0fcd09eba9b29c9484e8a018fa9e073042df88e3c56: +8ed7a797b9cea8a8370d419136bcdf683b759d2e3c6947f17e13e2485aa9d420b49f3a78b1c6a7fca8f3466f33bc0e929f01fba04306c2a7465f46c3759316d9:b49f3a78b1c6a7fca8f3466f33bc0e929f01fba04306c2a7465f46c3759316d9:a750c232933dc14b1184d86d8b4ce72e16d69744ba69818b6ac33b1d823bb2c3:04266c033b91c1322ceb3446c901ffcf3cc40c4034e887c9597ca1893ba7330becbbd8b48142ef35c012c6ba51a66df9308cb6268ad6b1e4b03e70102495790ba750c232933dc14b1184d86d8b4ce72e16d69744ba69818b6ac33b1d823bb2c3: +f2ab396fe8906e3e5633e99cabcd5b09df0859b516230b1e0450b580b65f616c8ea074245159a116aa7122a25ec16b891d625a68f33660423908f6bdc44f8c1b:8ea074245159a116aa7122a25ec16b891d625a68f33660423908f6bdc44f8c1b:5a44e34b746c5fd1898d552ab354d28fb4713856d7697dd63eb9bd6b99c280e187:a06a23d982d81ab883aae230adbc368a6a9977f003cebb00d4c2e4018490191a84d3a282fdbfb2fc88046e62de43e15fb575336b3c8b77d19ce6a009ce51f50c5a44e34b746c5fd1898d552ab354d28fb4713856d7697dd63eb9bd6b99c280e187: +550a41c013f79bab8f06e43ad1836d51312736a9713806fafe6645219eaa1f9daf6b7145474dc9954b9af93a9cdb34449d5b7c651c824d24e230b90033ce59c0:af6b7145474dc9954b9af93a9cdb34449d5b7c651c824d24e230b90033ce59c0:8bc4185e50e57d5f87f47515fe2b1837d585f0aae9e1ca383b3ec908884bb900ff27:16dc1e2b9fa909eefdc277ba16ebe207b8da5e91143cde78c5047a89f681c33c4e4e3428d5c928095903a811ec002d52a39ed7f8b3fe1927200c6dd0b9ab3e048bc4185e50e57d5f87f47515fe2b1837d585f0aae9e1ca383b3ec908884bb900ff27: +19ac3e272438c72ddf7b881964867cb3b31ff4c793bb7ea154613c1db068cb7ef85b80e050a1b9620db138bfc9e100327e25c257c59217b601f1f6ac9a413d3f:f85b80e050a1b9620db138bfc9e100327e25c257c59217b601f1f6ac9a413d3f:95872d5f789f95484e30cbb0e114028953b16f5c6a8d9f65c003a83543beaa46b38645:ea855d781cbea4682e350173cb89e8619ccfddb97cdce16f9a2f6f6892f46dbe68e04b12b8d88689a7a31670cdff409af98a93b49a34537b6aa009d2eb8b470195872d5f789f95484e30cbb0e114028953b16f5c6a8d9f65c003a83543beaa46b38645: +ca267de96c93c238fafb1279812059ab93ac03059657fd994f8fa5a09239c821017370c879090a81c7f272c2fc80e3aac2bc603fcb379afc98691160ab745b26:017370c879090a81c7f272c2fc80e3aac2bc603fcb379afc98691160ab745b26:e05f71e4e49a72ec550c44a3b85aca8f20ff26c3ee94a80f1b431c7d154ec9603ee02531:ac957f82335aa7141e96b59d63e3ccee95c3a2c47d026540c2af42dc9533d5fd81827d1679ad187aeaf37834915e75b147a9286806c8017516ba43dd051a5e0ce05f71e4e49a72ec550c44a3b85aca8f20ff26c3ee94a80f1b431c7d154ec9603ee02531: +3dff5e899475e7e91dd261322fab09980c52970de1da6e2e201660cc4fce7032f30162bac98447c4042fac05da448034629be2c6a58d30dfd578ba9fb5e3930b:f30162bac98447c4042fac05da448034629be2c6a58d30dfd578ba9fb5e3930b:938f0e77621bf3ea52c7c4911c5157c2d8a2a858093ef16aa9b107e69d98037ba139a3c382:5efe7a92ff9623089b3e3b78f352115366e26ba3fb1a416209bc029e9cadccd9f4affa333555a8f3a35a9d0f7c34b292cae77ec96fa3adfcaadee2d9ced8f805938f0e77621bf3ea52c7c4911c5157c2d8a2a858093ef16aa9b107e69d98037ba139a3c382: +9a6b847864e70cfe8ba6ab22fa0ca308c0cc8bec7141fbcaa3b81f5d1e1cfcfc34ad0fbdb2566507a81c2b1f8aa8f53dccaa64cc87ada91b903e900d07eee930:34ad0fbdb2566507a81c2b1f8aa8f53dccaa64cc87ada91b903e900d07eee930:838367471183c71f7e717724f89d401c3ad9863fd9cc7aa3cf33d3c529860cb581f3093d87da:2ab255169c489c54c732232e37c87349d486b1eba20509dbabe7fed329ef08fd75ba1cd145e67b2ea26cb5cc51cab343eeb085fe1fd7b0ec4c6afcd9b979f905838367471183c71f7e717724f89d401c3ad9863fd9cc7aa3cf33d3c529860cb581f3093d87da: +575be07afca5d063c238cd9b8028772cc49cda34471432a2e166e096e2219efc94e5eb4d5024f49d7ebf79817c8de11497dc2b55622a51ae123ffc749dbb16e0:94e5eb4d5024f49d7ebf79817c8de11497dc2b55622a51ae123ffc749dbb16e0:33e5918b66d33d55fe717ca34383eae78f0af82889caf6696e1ac9d95d1ffb32cba755f9e3503e:58271d44236f3b98c58fd7ae0d2f49ef2b6e3affdb225aa3ba555f0e11cc53c23ad19baf24346590d05d7d5390582082cf94d39cad6530ab93d13efb3927950633e5918b66d33d55fe717ca34383eae78f0af82889caf6696e1ac9d95d1ffb32cba755f9e3503e: +15ffb45514d43444d61fcb105e30e135fd268523dda20b82758b1794231104411772c5abc2d23fd2f9d1c3257be7bc3c1cd79cee40844b749b3a7743d2f964b8:1772c5abc2d23fd2f9d1c3257be7bc3c1cd79cee40844b749b3a7743d2f964b8:da9c5559d0ea51d255b6bd9d7638b876472f942b330fc0e2b30aea68d77368fce4948272991d257e:6828cd7624e793b8a4ceb96d3c2a975bf773e5ff6645f353614058621e58835289e7f31f42dfe6af6d736f2644511e320c0fa698582a79778d18730ed3e8cb08da9c5559d0ea51d255b6bd9d7638b876472f942b330fc0e2b30aea68d77368fce4948272991d257e: +fe0568642943b2e1afbfd1f10fe8df87a4236bea40dce742072cb21886eec1fa299ebd1f13177dbdb66a912bbf712038fdf73b06c3ac020c7b19126755d47f61:299ebd1f13177dbdb66a912bbf712038fdf73b06c3ac020c7b19126755d47f61:c59d0862ec1c9746abcc3cf83c9eeba2c7082a036a8cb57ce487e763492796d47e6e063a0c1feccc2d:d59e6dfcc6d7e3e2c58dec81e985d245e681acf6594a23c59214f7bed8015d813c7682b60b3583440311e72a8665ba2c96dec23ce826e160127e18132b030404c59d0862ec1c9746abcc3cf83c9eeba2c7082a036a8cb57ce487e763492796d47e6e063a0c1feccc2d: +5ecb16c2df27c8cf58e436a9d3affbd58e9538a92659a0f97c4c4f994635a8cada768b20c437dd3aa5f84bb6a077ffa34ab68501c5352b5cc3fdce7fe6c2398d:da768b20c437dd3aa5f84bb6a077ffa34ab68501c5352b5cc3fdce7fe6c2398d:56f1329d9a6be25a6159c72f12688dc8314e85dd9e7e4dc05bbecb7729e023c86f8e0937353f27c7ede9:1c723a20c6772426a670e4d5c4a97c6ebe9147f71bb0a415631e44406e290322e4ca977d348fe7856a8edc235d0fe95f7ed91aefddf28a77e2c7dbfd8f552f0a56f1329d9a6be25a6159c72f12688dc8314e85dd9e7e4dc05bbecb7729e023c86f8e0937353f27c7ede9: +d599d637b3c30a82a9984e2f758497d144de6f06b9fba04dd40fd949039d7c846791d8ce50a44689fc178727c5c3a1c959fbeed74ef7d8e7bd3c1ab4da31c51f:6791d8ce50a44689fc178727c5c3a1c959fbeed74ef7d8e7bd3c1ab4da31c51f:a7c04e8ba75d0a03d8b166ad7a1d77e1b91c7aaf7befdd99311fc3c54a684ddd971d5b3211c3eeaff1e54e:ebf10d9ac7c96108140e7def6fe9533d727646ff5b3af273c1df95762a66f32b65a09634d013f54b5dd6011f91bc336ca8b355ce33f8cfbec2535a4c427f8205a7c04e8ba75d0a03d8b166ad7a1d77e1b91c7aaf7befdd99311fc3c54a684ddd971d5b3211c3eeaff1e54e: +30ab8232fa7018f0ce6c39bd8f782fe2e159758bb0f2f4386c7f28cfd2c85898ecfb6a2bd42f31b61250ba5de7e46b4719afdfbc660db71a7bd1df7b0a3abe37:ecfb6a2bd42f31b61250ba5de7e46b4719afdfbc660db71a7bd1df7b0a3abe37:63b80b7956acbecf0c35e9ab06b914b0c7014fe1a4bbc0217240c1a33095d707953ed77b15d211adaf9b97dc:9af885344cc7239498f712df80bc01b80638291ed4a1d28baa5545017a72e2f65649ccf9603da6eb5bfab9f5543a6ca4a7af3866153c76bf66bf95def615b00c63b80b7956acbecf0c35e9ab06b914b0c7014fe1a4bbc0217240c1a33095d707953ed77b15d211adaf9b97dc: +0ddcdc872c7b748d40efe96c2881ae189d87f56148ed8af3ebbbc80324e38bdd588ddadcbcedf40df0e9697d8bb277c7bb1498fa1d26ce0a835a760b92ca7c85:588ddadcbcedf40df0e9697d8bb277c7bb1498fa1d26ce0a835a760b92ca7c85:65641cd402add8bf3d1d67dbeb6d41debfbef67e4317c35b0a6d5bbbae0e034de7d670ba1413d056f2d6f1de12:c179c09456e235fe24105afa6e8ec04637f8f943817cd098ba95387f9653b2add181a31447d92d1a1ddf1ceb0db62118de9dffb7dcd2424057cbdff5d41d040365641cd402add8bf3d1d67dbeb6d41debfbef67e4317c35b0a6d5bbbae0e034de7d670ba1413d056f2d6f1de12: +89f0d68299ba0a5a83f248ae0c169f8e3849a9b47bd4549884305c9912b46603aba3e795aab2012acceadd7b3bd9daeeed6ff5258bdcd7c93699c2a3836e3832:aba3e795aab2012acceadd7b3bd9daeeed6ff5258bdcd7c93699c2a3836e3832:4f1846dd7ad50e545d4cfbffbb1dc2ff145dc123754d08af4e44ecc0bc8c91411388bc7653e2d893d1eac2107d05:2c691fa8d487ce20d5d2fa41559116e0bbf4397cf5240e152556183541d66cf753582401a4388d390339dbef4d384743caa346f55f8daba68ba7b9131a8a6e0b4f1846dd7ad50e545d4cfbffbb1dc2ff145dc123754d08af4e44ecc0bc8c91411388bc7653e2d893d1eac2107d05: +0a3c1844e2db070fb24e3c95cb1cc6714ef84e2ccd2b9dd2f1460ebf7ecf13b172e409937e0610eb5c20b326dc6ea1bbbc0406701c5cd67d1fbde09192b07c01:72e409937e0610eb5c20b326dc6ea1bbbc0406701c5cd67d1fbde09192b07c01:4c8274d0ed1f74e2c86c08d955bde55b2d54327e82062a1f71f70d536fdc8722cdead7d22aaead2bfaa1ad00b82957:87f7fdf46095201e877a588fe3e5aaf476bd63138d8a878b89d6ac60631b3458b9d41a3c61a588e1db8d29a5968981b018776c588780922f5aa732ba6379dd054c8274d0ed1f74e2c86c08d955bde55b2d54327e82062a1f71f70d536fdc8722cdead7d22aaead2bfaa1ad00b82957: +c8d7a8818b98dfdb20839c871cb5c48e9e9470ca3ad35ba2613a5d3199c8ab2390d2efbba4d43e6b2b992ca16083dbcfa2b322383907b0ee75f3e95845d3c47f:90d2efbba4d43e6b2b992ca16083dbcfa2b322383907b0ee75f3e95845d3c47f:783e33c3acbdbb36e819f544a7781d83fc283d3309f5d3d12c8dcd6b0b3d0e89e38cfd3b4d0885661ca547fb9764abff:fa2e994421aef1d5856674813d05cbd2cf84ef5eb424af6ecd0dc6fdbdc2fe605fe985883312ecf34f59bfb2f1c9149e5b9cc9ecda05b2731130f3ed28ddae0b783e33c3acbdbb36e819f544a7781d83fc283d3309f5d3d12c8dcd6b0b3d0e89e38cfd3b4d0885661ca547fb9764abff: +b482703612d0c586f76cfcb21cfd2103c957251504a8c0ac4c86c9c6f3e429fffd711dc7dd3b1dfb9df9704be3e6b26f587fe7dd7ba456a91ba43fe51aec09ad:fd711dc7dd3b1dfb9df9704be3e6b26f587fe7dd7ba456a91ba43fe51aec09ad:29d77acfd99c7a0070a88feb6247a2bce9984fe3e6fbf19d4045042a21ab26cbd771e184a9a75f316b648c6920db92b87b:58832bdeb26feafc31b46277cf3fb5d7a17dfb7ccd9b1f58ecbe6feb979666828f239ba4d75219260ecac0acf40f0e5e2590f4caa16bbbcd8a155d347967a60729d77acfd99c7a0070a88feb6247a2bce9984fe3e6fbf19d4045042a21ab26cbd771e184a9a75f316b648c6920db92b87b: +84e50dd9a0f197e3893c38dbd91fafc344c1776d3a400e2f0f0ee7aa829eb8a22c50f870ee48b36b0ac2f8a5f336fb090b113050dbcc25e078200a6e16153eea:2c50f870ee48b36b0ac2f8a5f336fb090b113050dbcc25e078200a6e16153eea:f3992cde6493e671f1e129ddca8038b0abdb77bb9035f9f8be54bd5d68c1aeff724ff47d29344391dc536166b8671cbbf123:69e6a4491a63837316e86a5f4ba7cd0d731ecc58f1d0a264c67c89befdd8d3829d8de13b33cc0bf513931715c7809657e2bfb960e5c764c971d733746093e500f3992cde6493e671f1e129ddca8038b0abdb77bb9035f9f8be54bd5d68c1aeff724ff47d29344391dc536166b8671cbbf123: +b322d46577a2a991a4d1698287832a39c487ef776b4bff037a05c7f1812bdeeceb2bcadfd3eec2986baff32b98e7c4dbf03ff95d8ad5ff9aa9506e5472ff845f:eb2bcadfd3eec2986baff32b98e7c4dbf03ff95d8ad5ff9aa9506e5472ff845f:19f1bf5dcf1750c611f1c4a2865200504d82298edd72671f62a7b1471ac3d4a30f7de9e5da4108c52a4ce70a3e114a52a3b3c5:c7b55137317ca21e33489ff6a9bfab97c855dc6f85684a70a9125a261b56d5e6f149c5774d734f2d8debfc77b721896a8267c23768e9badb910eef83ec25880219f1bf5dcf1750c611f1c4a2865200504d82298edd72671f62a7b1471ac3d4a30f7de9e5da4108c52a4ce70a3e114a52a3b3c5: +960cab5034b9838d098d2dcbf4364bec16d388f6376d73a6273b70f82bbc98c05e3c19f2415acf729f829a4ebd5c40e1a6bc9fbca95703a9376087ed0937e51a:5e3c19f2415acf729f829a4ebd5c40e1a6bc9fbca95703a9376087ed0937e51a:f8b21962447b0a8f2e4279de411bea128e0be44b6915e6cda88341a68a0d818357db938eac73e0af6d31206b3948f8c48a447308:27d4c3a1811ef9d4360b3bdd133c2ccc30d02c2f248215776cb07ee4177f9b13fc42dd70a6c2fed8f225c7663c7f182e7ee8eccff20dc7b0e1d5834ec5b1ea01f8b21962447b0a8f2e4279de411bea128e0be44b6915e6cda88341a68a0d818357db938eac73e0af6d31206b3948f8c48a447308: +eb77b2638f23eebc82efe45ee9e5a0326637401e663ed029699b21e6443fb48e9ef27608961ac711de71a6e2d4d4663ea3ecd42fb7e4e8627c39622df4af0bbc:9ef27608961ac711de71a6e2d4d4663ea3ecd42fb7e4e8627c39622df4af0bbc:99e3d00934003ebafc3e9fdb687b0f5ff9d5782a4b1f56b9700046c077915602c3134e22fc90ed7e690fddd4433e2034dcb2dc99ab:18dc56d7bd9acd4f4daa78540b4ac8ff7aa9815f45a0bba370731a14eaabe96df8b5f37dbf8eae4cb15a64b244651e59d6a3d6761d9e3c50f2d0cbb09c05ec0699e3d00934003ebafc3e9fdb687b0f5ff9d5782a4b1f56b9700046c077915602c3134e22fc90ed7e690fddd4433e2034dcb2dc99ab: +b625aa89d3f7308715427b6c39bbac58effd3a0fb7316f7a22b99ee5922f2dc965a99c3e16fea894ec33c6b20d9105e2a04e2764a4769d9bbd4d8bacfeab4a2e:65a99c3e16fea894ec33c6b20d9105e2a04e2764a4769d9bbd4d8bacfeab4a2e:e07241dbd3adbe610bbe4d005dd46732a4c25086ecb8ec29cd7bca116e1bf9f53bfbf3e11fa49018d39ff1154a06668ef7df5c678e6a:01bb901d83b8b682d3614af46a807ba2691358feb775325d3423f549ff0aa5757e4e1a74e9c70f9721d8f354b319d4f4a1d91445c870fd0ffb94fed64664730de07241dbd3adbe610bbe4d005dd46732a4c25086ecb8ec29cd7bca116e1bf9f53bfbf3e11fa49018d39ff1154a06668ef7df5c678e6a: +b1c9f8bd03fe82e78f5c0fb06450f27dacdf716434db268275df3e1dc177af427fc88b1f7b3f11c629be671c21621f5c10672fafc8492da885742059ee6774cf:7fc88b1f7b3f11c629be671c21621f5c10672fafc8492da885742059ee6774cf:331da7a9c1f87b2ac91ee3b86d06c29163c05ed6f8d8a9725b471b7db0d6acec7f0f702487163f5eda020ca5b493f399e1c8d308c3c0c2:4b229951ef262f16978f7914bc672e7226c5f8379d2778c5a2dc0a2650869f7acfbd0bcd30fdb0619bb44fc1ae5939b87cc318133009c20395b6c7eb98107701331da7a9c1f87b2ac91ee3b86d06c29163c05ed6f8d8a9725b471b7db0d6acec7f0f702487163f5eda020ca5b493f399e1c8d308c3c0c2: +6d8cdb2e075f3a2f86137214cb236ceb89a6728bb4a200806bf3557fb78fac6957a04c7a5113cddfe49a4c124691d46c1f9cdc8f343f9dcb72a1330aeca71fda:57a04c7a5113cddfe49a4c124691d46c1f9cdc8f343f9dcb72a1330aeca71fda:7f318dbd121c08bfddfeff4f6aff4e45793251f8abf658403358238984360054f2a862c5bb83ed89025d2014a7a0cee50da3cb0e76bbb6bf:a6cbc947f9c87d1455cf1a708528c090f11ecee4855d1dbaadf47454a4de55fa4ce84b36d73a5b5f8f59298ccf21992df492ef34163d87753b7e9d32f2c3660b7f318dbd121c08bfddfeff4f6aff4e45793251f8abf658403358238984360054f2a862c5bb83ed89025d2014a7a0cee50da3cb0e76bbb6bf: +47adc6d6bf571ee9570ca0f75b604ac43e303e4ab339ca9b53cacc5be45b2ccba3f527a1c1f17dfeed92277347c9f98ab475de1755b0ab546b8a15d01b9bd0be:a3f527a1c1f17dfeed92277347c9f98ab475de1755b0ab546b8a15d01b9bd0be:ce497c5ff5a77990b7d8f8699eb1f5d8c0582f70cb7ac5c54d9d924913278bc654d37ea227590e15202217fc98dac4c0f3be2183d133315739:4e8c318343c306adbba60c92b75cb0569b9219d8a86e5d57752ed235fc109a43c2cf4e942cacf297279fbb28675347e08027722a4eb7395e00a17495d32edf0bce497c5ff5a77990b7d8f8699eb1f5d8c0582f70cb7ac5c54d9d924913278bc654d37ea227590e15202217fc98dac4c0f3be2183d133315739: +3c19b50b0fe47961719c381d0d8da9b9869d312f13e3298b97fb22f0af29cbbe0f7eda091499625e2bae8536ea35cda5483bd16a9c7e416b341d6f2c83343612:0f7eda091499625e2bae8536ea35cda5483bd16a9c7e416b341d6f2c83343612:8ddcd63043f55ec3bfc83dceae69d8f8b32f4cdb6e2aebd94b4314f8fe7287dcb62732c9052e7557fe63534338efb5b6254c5d41d2690cf5144f:efbd41f26a5d62685516f882b6ec74e0d5a71830d203c231248f26e99a9c6578ec900d68cdb8fa7216ad0d24f9ecbc9ffa655351666582f626645395a31fa7048ddcd63043f55ec3bfc83dceae69d8f8b32f4cdb6e2aebd94b4314f8fe7287dcb62732c9052e7557fe63534338efb5b6254c5d41d2690cf5144f: +34e1e9d539107eb86b393a5ccea1496d35bc7d5e9a8c5159d957e4e5852b3eb00ecb2601d5f7047428e9f909883a12420085f04ee2a88b6d95d3d7f2c932bd76:0ecb2601d5f7047428e9f909883a12420085f04ee2a88b6d95d3d7f2c932bd76:a6d4d0542cfe0d240a90507debacabce7cbbd48732353f4fad82c7bb7dbd9df8e7d9a16980a45186d8786c5ef65445bcc5b2ad5f660ffc7c8eaac0:32d22904d3e7012d6f5a441b0b4228064a5cf95b723a66b048a087ecd55920c31c204c3f2006891a85dd1932e3f1d614cfd633b5e63291c6d8166f3011431e09a6d4d0542cfe0d240a90507debacabce7cbbd48732353f4fad82c7bb7dbd9df8e7d9a16980a45186d8786c5ef65445bcc5b2ad5f660ffc7c8eaac0: +49dd473ede6aa3c866824a40ada4996c239a20d84c9365e4f0a4554f8031b9cf788de540544d3feb0c919240b390729be487e94b64ad973eb65b4669ecf23501:788de540544d3feb0c919240b390729be487e94b64ad973eb65b4669ecf23501:3a53594f3fba03029318f512b084a071ebd60baec7f55b028dc73bfc9c74e0ca496bf819dd92ab61cd8b74be3c0d6dcd128efc5ed3342cba124f726c:d2fde02791e720852507faa7c3789040d9ef86646321f313ac557f4002491542dd67d05c6990cdb0d495501fbc5d5188bfbb84dc1bf6098bee0603a47fc2690f3a53594f3fba03029318f512b084a071ebd60baec7f55b028dc73bfc9c74e0ca496bf819dd92ab61cd8b74be3c0d6dcd128efc5ed3342cba124f726c: +331c64da482b6b551373c36481a02d8136ecadbb01ab114b4470bf41607ac57152a00d96a3148b4726692d9eff89160ea9f99a5cc4389f361fed0bb16a42d521:52a00d96a3148b4726692d9eff89160ea9f99a5cc4389f361fed0bb16a42d521:20e1d05a0d5b32cc8150b8116cef39659dd5fb443ab15600f78e5b49c45326d9323f2850a63c3808859495ae273f58a51e9de9a145d774b40ba9d753d3:22c99aa946ead39ac7997562810c01c20b46bd610645bd2d56dcdcbaacc5452c74fbf4b8b1813b0e94c30d808ce5498e61d4f7ccbb4cc5f04dfc6140825a960020e1d05a0d5b32cc8150b8116cef39659dd5fb443ab15600f78e5b49c45326d9323f2850a63c3808859495ae273f58a51e9de9a145d774b40ba9d753d3: +5c0b96f2af8712122cf743c8f8dc77b6cd5570a7de13297bb3dde1886213cce20510eaf57d7301b0e1d527039bf4c6e292300a3a61b4765434f3203c100351b1:0510eaf57d7301b0e1d527039bf4c6e292300a3a61b4765434f3203c100351b1:54e0caa8e63919ca614b2bfd308ccfe50c9ea888e1ee4446d682cb5034627f97b05392c04e835556c31c52816a48e4fb196693206b8afb4408662b3cb575:06e5d8436ac7705b3a90f1631cdd38ec1a3fa49778a9b9f2fa5ebea4e7d560ada7dd26ff42fafa8ba420323742761aca6904940dc21bbef63ff72daab45d430b54e0caa8e63919ca614b2bfd308ccfe50c9ea888e1ee4446d682cb5034627f97b05392c04e835556c31c52816a48e4fb196693206b8afb4408662b3cb575: +bf5ba5d6a49dd5ef7b4d5d7d3e4ecc505c01f6ccee4c54b5ef7b40af6a4541401be034f813017b900d8990af45fad5b5214b573bd303ef7a75ef4b8c5c5b9842:1be034f813017b900d8990af45fad5b5214b573bd303ef7a75ef4b8c5c5b9842:16152c2e037b1c0d3219ced8e0674aee6b57834b55106c5344625322da638ecea2fc9a424a05ee9512d48fcf75dd8bd4691b3c10c28ec98ee1afa5b863d1c36795ed18105db3a9aabd9d2b4c1747adbaf1a56ffcc0c533c1c0faef331cdb79d961fa39f880a1b8b1164741822efb15a7259a465bef212855751fab66a897bfa211abe0ea2f2e1cd8a11d80e142cde1263eec267a3138ae1fcf4099db0ab53d64f336f4bcd7a363f6db112c0a2453051a0006f813aaf4ae948a2090619374fa58052409c28ef76225687df3cb2d1b0bfb43b09f47f1232f790e6d8dea759e57942099f4c4bd3390f28afc2098244961465c643fc8b29766af2bcbc5440b86e83608cfc937be98bb4827fd5e6b689adc2e26513db531076a6564396255a09975b7034dac06461b255642e3a7ed75fa9fc265011f5f6250382a84ac268d63ba64:279cace6fdaf3945e3837df474b28646143747632bede93e7a66f5ca291d2c24978512ca0cb8827c8c322685bd605503a5ec94dbae61bbdcae1e49650602bc0716152c2e037b1c0d3219ced8e0674aee6b57834b55106c5344625322da638ecea2fc9a424a05ee9512d48fcf75dd8bd4691b3c10c28ec98ee1afa5b863d1c36795ed18105db3a9aabd9d2b4c1747adbaf1a56ffcc0c533c1c0faef331cdb79d961fa39f880a1b8b1164741822efb15a7259a465bef212855751fab66a897bfa211abe0ea2f2e1cd8a11d80e142cde1263eec267a3138ae1fcf4099db0ab53d64f336f4bcd7a363f6db112c0a2453051a0006f813aaf4ae948a2090619374fa58052409c28ef76225687df3cb2d1b0bfb43b09f47f1232f790e6d8dea759e57942099f4c4bd3390f28afc2098244961465c643fc8b29766af2bcbc5440b86e83608cfc937be98bb4827fd5e6b689adc2e26513db531076a6564396255a09975b7034dac06461b255642e3a7ed75fa9fc265011f5f6250382a84ac268d63ba64: +65de297b70cbe80980500af0561a24db50001000125f4490366d8300d3128592ba8e2ad929bdcea538741042b57f2067d3153707a453770db9f3c4ca75504d24:ba8e2ad929bdcea538741042b57f2067d3153707a453770db9f3c4ca75504d24:131d8f4c2c94b153565b86592e770c987a443461b39aa2408b29e213ab057affc598b583739d6603a83fef0afc514721db0e76f9bd1b72b98c565cc8881af5747c0ba6f58c53dd2377da6c0d3aa805620cc4e75d52aabcba1f9b2849e08bd1b6b92e6f06615b814519606a02dc65a8609f5b29e9c2af5a894f7116ef28cfd1e7b76b64061732f7a5a3f8aa4c2e569e627a3f9749aa597be49d6b94436c352dd5fa7b83c92d2610faa32095ca302152d91a3c9776750e758ee8e9e402c6f5385eaa5df23850e54beb1be437a416c7115ed6aa6de13b55482532787e0bee34b83f3084406765635497c931b62a0518f1fbc2b891dc7262c7c6b67eda594fa530d74c9329bad5be94c287fbcde53aa80272b83322613d9368e5904076fdbcc88b2c0e59c10b02c448e00d1b3e7a9c9640feffb9523a8a60e1d83f04a4b8df69153b:7a9b736b01cc92a3349f1a3c32dbd91959825394ff443c567405e899c8185ce8fad9500e1fce89d95a6253c00477435acf04bff993de1b00495def0834ee1f07131d8f4c2c94b153565b86592e770c987a443461b39aa2408b29e213ab057affc598b583739d6603a83fef0afc514721db0e76f9bd1b72b98c565cc8881af5747c0ba6f58c53dd2377da6c0d3aa805620cc4e75d52aabcba1f9b2849e08bd1b6b92e6f06615b814519606a02dc65a8609f5b29e9c2af5a894f7116ef28cfd1e7b76b64061732f7a5a3f8aa4c2e569e627a3f9749aa597be49d6b94436c352dd5fa7b83c92d2610faa32095ca302152d91a3c9776750e758ee8e9e402c6f5385eaa5df23850e54beb1be437a416c7115ed6aa6de13b55482532787e0bee34b83f3084406765635497c931b62a0518f1fbc2b891dc7262c7c6b67eda594fa530d74c9329bad5be94c287fbcde53aa80272b83322613d9368e5904076fdbcc88b2c0e59c10b02c448e00d1b3e7a9c9640feffb9523a8a60e1d83f04a4b8df69153b: +0826e7333324e7ec8c764292f6015d4670e9b8d7c4a89e8d909e8ef435d18d15ffb2348ca8a018058be71d1512f376f91e8b0d552581254e107602217395e662:ffb2348ca8a018058be71d1512f376f91e8b0d552581254e107602217395e662:7f9e3e2f03c9df3d21b990f5a4af8295734afe783accc34fb1e9b8e95a0fd837af7e05c13cda0de8fadac9205265a0792b52563bdc2fee766348befcc56b88bbb95f154414fb186ec436aa62ea6fcabb11c017a9d2d15f67e595980e04c9313bc94fbc8c1134c2f40332bc7e311ac1ce11b505f8572ada7fbe196fba822d9a914492fa7185e9f3bea4687200a524c673a1cdf87eb3a140dcdb6a8875613488a2b00adf7175341c1c257635fa1a53a3e21d60c228399eea0991f112c60f653d7148e2c5ceb98f940831f070db1084d79156cc82c46bc9b8e884f3fa81be2da4cdda46bcaa24cc461f76ee647bb0f0f8c15ac5daa795b945e6f85bb310362e48d8095c782c61c52b481b4b002ad06ea74b8d306eff71abf21db710a8913cbe48332be0a0b3f31e0c7a6eba85ce33f357c7aeccd30bfb1a6574408b66fe404d31c3c5:4bac7fabec8724d81ab09ae130874d70b5213492104372f601ae5abb10532799373c4dad215876441f474e2c006be37c3c8f5f6f017d0870414fd276a8f428087f9e3e2f03c9df3d21b990f5a4af8295734afe783accc34fb1e9b8e95a0fd837af7e05c13cda0de8fadac9205265a0792b52563bdc2fee766348befcc56b88bbb95f154414fb186ec436aa62ea6fcabb11c017a9d2d15f67e595980e04c9313bc94fbc8c1134c2f40332bc7e311ac1ce11b505f8572ada7fbe196fba822d9a914492fa7185e9f3bea4687200a524c673a1cdf87eb3a140dcdb6a8875613488a2b00adf7175341c1c257635fa1a53a3e21d60c228399eea0991f112c60f653d7148e2c5ceb98f940831f070db1084d79156cc82c46bc9b8e884f3fa81be2da4cdda46bcaa24cc461f76ee647bb0f0f8c15ac5daa795b945e6f85bb310362e48d8095c782c61c52b481b4b002ad06ea74b8d306eff71abf21db710a8913cbe48332be0a0b3f31e0c7a6eba85ce33f357c7aeccd30bfb1a6574408b66fe404d31c3c5: +00ad6227977b5f38ccda994d928bba9086d2daeb013f8690db986648b90c1d4591a4ea005752b92cbebf99a8a5cbecd240ae3f016c44ad141b2e57ddc773dc8e:91a4ea005752b92cbebf99a8a5cbecd240ae3f016c44ad141b2e57ddc773dc8e:cb5bc5b98b2efce43543e91df041e0dbb53ed8f67bf0f197c52b2211e7a45e2e1ec818c1a80e10abf6a43535f5b79d974d8ae28a2295c0a6521763b607d5103c6aef3b2786bd5afd7563695660684337bc3090739fb1cd53a9d644139b6d4caec75bda7f2521fbfe676ab45b98cb317aa7ca79fc54a3d7c578466a6aa64e434e923465a7f211aa0c61681bb8486e90206a25250d3fdae6fb03299721e99e2a914910d91760089b5d281e131e6c836bc2de08f7e02c48d323c647e9536c00ec1039201c0362618c7d47aa8e7b9715ffc439987ae1d31154a6198c5aa11c128f4082f556c99baf103ecadc3b2f3b2ec5b469623bc03a53caf3814b16300aedbda538d676d1f607102639db2a62c446707ce6469bd873a0468225be88b0aef5d4020459b94b32fe2b0133e92e7ba54dd2a5397ed85f966ab39ed0730cca8e7dacb8a336:dc501db79fd782bc88cae792557d5d273f9ba560c7d90037fe84ac879d684f612a77452c4443e95c07b8be192c35769b17bbdfca42280de796d92119d833670dcb5bc5b98b2efce43543e91df041e0dbb53ed8f67bf0f197c52b2211e7a45e2e1ec818c1a80e10abf6a43535f5b79d974d8ae28a2295c0a6521763b607d5103c6aef3b2786bd5afd7563695660684337bc3090739fb1cd53a9d644139b6d4caec75bda7f2521fbfe676ab45b98cb317aa7ca79fc54a3d7c578466a6aa64e434e923465a7f211aa0c61681bb8486e90206a25250d3fdae6fb03299721e99e2a914910d91760089b5d281e131e6c836bc2de08f7e02c48d323c647e9536c00ec1039201c0362618c7d47aa8e7b9715ffc439987ae1d31154a6198c5aa11c128f4082f556c99baf103ecadc3b2f3b2ec5b469623bc03a53caf3814b16300aedbda538d676d1f607102639db2a62c446707ce6469bd873a0468225be88b0aef5d4020459b94b32fe2b0133e92e7ba54dd2a5397ed85f966ab39ed0730cca8e7dacb8a336: +1521c6dbd6f724de73eaf7b56264f01035c04e01c1f3eb3cbe83efd26c439ada2f61a26ffb68ba4f6e141529dc2617e8531c7151404808093b4fa7fedaea255d:2f61a26ffb68ba4f6e141529dc2617e8531c7151404808093b4fa7fedaea255d:3e3c7c490788e4b1d42f5cbcae3a9930bf617ebdff447f7be2ac2ba7cd5bcfc015760963e6fe5b956fb7cdb35bd5a17f5429ca664f437f08753a741c2bc8692b71a9115c582a25b2f74d329854d60b7817c079b3523aaff8793c2f72fff8cd10592c54e738df1d6452fb72da131c6731ea5c953c62ea177ac1f4735e5154477387109afae15f3ed6eeb08606e28c81d4386f03b9376924b6ef8d221ee29547f82a7ede48e1dc17723e3d42171eeaf96ac84bedc2a01dd86f4d085734fd69f91b5263e439083ff0318536adff4147308e3aafd1b58bb74f6fb0214a46fdcd3524f18df5a719ce57319e791b4ea606b499bfa57a60e707f94e18f1fed22f91bc79e6364a843f9cbf93825c465e9cae9072bc9d3ec4471f21ab2f7e99a633f587aac3db78ae9666a89a18008dd61d60218554411a65740ffd1ae3adc06595e3b7876407b6:a817ed23ec398a128601c1832dc6af7643bf3a5f517bcc579450fdb4759028f4966164125f6ebd0d6bf86ff298a39c766d0c21fdb0cbfdf81cd0eb1f03cd8a083e3c7c490788e4b1d42f5cbcae3a9930bf617ebdff447f7be2ac2ba7cd5bcfc015760963e6fe5b956fb7cdb35bd5a17f5429ca664f437f08753a741c2bc8692b71a9115c582a25b2f74d329854d60b7817c079b3523aaff8793c2f72fff8cd10592c54e738df1d6452fb72da131c6731ea5c953c62ea177ac1f4735e5154477387109afae15f3ed6eeb08606e28c81d4386f03b9376924b6ef8d221ee29547f82a7ede48e1dc17723e3d42171eeaf96ac84bedc2a01dd86f4d085734fd69f91b5263e439083ff0318536adff4147308e3aafd1b58bb74f6fb0214a46fdcd3524f18df5a719ce57319e791b4ea606b499bfa57a60e707f94e18f1fed22f91bc79e6364a843f9cbf93825c465e9cae9072bc9d3ec4471f21ab2f7e99a633f587aac3db78ae9666a89a18008dd61d60218554411a65740ffd1ae3adc06595e3b7876407b6: +17e5f0a8f34751babc5c723ecf339306992f39ea065ac140fcbc397d2dd32c4b4f1e23cc0f2f69c88ef9162ab5f8c59fb3b8ab2096b77e782c63c07c8c4f2b60:4f1e23cc0f2f69c88ef9162ab5f8c59fb3b8ab2096b77e782c63c07c8c4f2b60:c0fad790024019bd6fc08a7a92f5f2ac35cf6432e2eaa53d482f6e1204935336cb3ae65a63c24d0ec6539a10ee18760f2f520537774cdec6e96b55536011daa8f8bcb9cdaf6df5b34648448ac7d7cb7c6bd80d67fbf330f8765297766046a925ab52411d1604c3ed6a85173040125658a32cf4c854ef2813df2be6f3830e5eee5a6163a83ca8849f612991a31e9f88028e50bf8535e11755fad029d94cf25959f6695d09c1ba4315d40f7cf51b3f8166d02faba7511ecd8b1dded5f10cd6843455cff707ed225396c61d0820d20ada70d0c3619ff679422061c9f7c76e97d5a37af61fd62212d2dafc647ebbb979e61d9070ec03609a07f5fc57d119ae64b7a6ef92a5afae660a30ed48d702cc3128c633b4f19060a0578101729ee979f790f45bdbb5fe1a8a62f01a61a31d61af07030450fa0417323e9407bc76e73130e7c69d62e6a7:efe2cb63fe7b4fc98946dc82fb6998e741ed9ce6b9c1a93bb45bc0a7d8396d7405282b43fe363ba5b23589f8e1fae130e157ce888cd72d053d0cc19d257a4300c0fad790024019bd6fc08a7a92f5f2ac35cf6432e2eaa53d482f6e1204935336cb3ae65a63c24d0ec6539a10ee18760f2f520537774cdec6e96b55536011daa8f8bcb9cdaf6df5b34648448ac7d7cb7c6bd80d67fbf330f8765297766046a925ab52411d1604c3ed6a85173040125658a32cf4c854ef2813df2be6f3830e5eee5a6163a83ca8849f612991a31e9f88028e50bf8535e11755fad029d94cf25959f6695d09c1ba4315d40f7cf51b3f8166d02faba7511ecd8b1dded5f10cd6843455cff707ed225396c61d0820d20ada70d0c3619ff679422061c9f7c76e97d5a37af61fd62212d2dafc647ebbb979e61d9070ec03609a07f5fc57d119ae64b7a6ef92a5afae660a30ed48d702cc3128c633b4f19060a0578101729ee979f790f45bdbb5fe1a8a62f01a61a31d61af07030450fa0417323e9407bc76e73130e7c69d62e6a7: +0cd7aa7d605e44d5ffb97966b2cb93c189e4c5a85db87fad7ab8d62463c59b594889855fe4116b4913927f47f2273bf559c3b394a983631a25ae597033185e46:4889855fe4116b4913927f47f2273bf559c3b394a983631a25ae597033185e46:28a55dda6cd0844b6577c9d6da073a4dc35cbc98ac158ab54cf88fd20cc87e83c4bba2d74d82ce0f4854ec4db513de400465aaa5eee790bc84f16337072d3a91cde40d6e0df1ba0cc0645f5d5cbbb642381d7b9e211d25267a8acf77d1edb69c3a630f5b133d24f046a81bf22ff03b31d8447e12c3f7b77114a70cbd20bbd08b0b3827a6bbcf90409e344447a7fbc59bdd97d729071f8d71dcc33e6ef2cbab1d411edf13734db1dd9703276f5eb2d6aa2cb8952dd6712bfae809ce08c3aa502b8135713fac0a9c25b1d45b6a5831e02421bba65b81a596efa24b0576bd1dc7fdfb49be762875e81bd540722bc06140b9aa2ef7b84a801e41ded68d4546ac4873d9e7ced649b64fadaf0b5c4b6eb8d036315233f4326ca01e03393050cd027c24f67303fb846bd2c6b3dba06bed0d59a36289d24bd648f7db0b3a81346612593e3ddd18c557:bf9115fd3d02706e398d4bf3b02a82674ff3041508fd39d29f867e501634b9261f516a794f98738d7c7013a3f2f858ffdd08047fb6bf3dddfb4b4f4cbeef300328a55dda6cd0844b6577c9d6da073a4dc35cbc98ac158ab54cf88fd20cc87e83c4bba2d74d82ce0f4854ec4db513de400465aaa5eee790bc84f16337072d3a91cde40d6e0df1ba0cc0645f5d5cbbb642381d7b9e211d25267a8acf77d1edb69c3a630f5b133d24f046a81bf22ff03b31d8447e12c3f7b77114a70cbd20bbd08b0b3827a6bbcf90409e344447a7fbc59bdd97d729071f8d71dcc33e6ef2cbab1d411edf13734db1dd9703276f5eb2d6aa2cb8952dd6712bfae809ce08c3aa502b8135713fac0a9c25b1d45b6a5831e02421bba65b81a596efa24b0576bd1dc7fdfb49be762875e81bd540722bc06140b9aa2ef7b84a801e41ded68d4546ac4873d9e7ced649b64fadaf0b5c4b6eb8d036315233f4326ca01e03393050cd027c24f67303fb846bd2c6b3dba06bed0d59a36289d24bd648f7db0b3a81346612593e3ddd18c557: +33371d9e892f9875052ac8e325ba505e7477c1ace24ba7822643d43d0acef3de35929bded27c249c87d8b8d82f59260a575327b546c3a167c69f5992d5b8e006:35929bded27c249c87d8b8d82f59260a575327b546c3a167c69f5992d5b8e006:27a32efba28204be59b7ff5fe488ca158a91d5986091ecc4458b49e090dd37cbfede7c0f46186fabcbdff78d2844155808efffd873ed9c9261526e04e4f7050b8d7bd267a0fe3d5a449378d54a4febbd2f26824338e2aaaf35a32ff0f62504bda5c2e44abc63159f336cf25e6bb40ddb7d8825dff18fd51fc01951eaedcd33707007e1203ca58b4f7d242f8166a907e099932c001bfb1ec9a61e0ef2da4e8446af208201315d69681710d425d2400c387d7b9df321a4aec602b9c656c3e2310bff8756d18b802134b15604f4edc111149a9879e31241dd34f702f4c349617b13529769a772f5e52a89c098e0dca5920667893a250061b17991626eb9319298685be46b6a8b68422444fa5a36bcf3a687e2eccb9322c87dc80165da898930850b98fc863cada1aa99c6d61c451b9ccf4874c7f0e75b0a0c602f044812c71765adaf02025395b0:985ca446ddc007827cc8f2852cbd8115ef8c5975e9d7ce96d74dfed859aa14a4c15254006bea5e08359efe2625d715e0897ee5a16f151203be5010418637de0527a32efba28204be59b7ff5fe488ca158a91d5986091ecc4458b49e090dd37cbfede7c0f46186fabcbdff78d2844155808efffd873ed9c9261526e04e4f7050b8d7bd267a0fe3d5a449378d54a4febbd2f26824338e2aaaf35a32ff0f62504bda5c2e44abc63159f336cf25e6bb40ddb7d8825dff18fd51fc01951eaedcd33707007e1203ca58b4f7d242f8166a907e099932c001bfb1ec9a61e0ef2da4e8446af208201315d69681710d425d2400c387d7b9df321a4aec602b9c656c3e2310bff8756d18b802134b15604f4edc111149a9879e31241dd34f702f4c349617b13529769a772f5e52a89c098e0dca5920667893a250061b17991626eb9319298685be46b6a8b68422444fa5a36bcf3a687e2eccb9322c87dc80165da898930850b98fc863cada1aa99c6d61c451b9ccf4874c7f0e75b0a0c602f044812c71765adaf02025395b0: +beedb8073df58f8c1bffbdbd77ec7decb2c82a9babecefc0331507bdc2c2a7e7b27e908b805e296fc30d2e474b060cd50c0f6f520b3671712183bd89d4e733e9:b27e908b805e296fc30d2e474b060cd50c0f6f520b3671712183bd89d4e733e9:35ca57f0f915e5209d54ea4b871ffb585354df1b4a4a1796fbe4d6227d3e1aba5171ed0391a79e83e24d82fdafd15c17b28bf6c94d618c74d65264e58faaacd2902872fdd0efa22e8d2d7ce8e3b8197f0c3615b0a385235fa9fd8e4564ee6e6b1650b4cfb94d872c805c32d4f3a18f966461d3adbb605fa525884f8eb197627396ba4d995d78ac02948a0eaabb58519b9a8e2e7985cd1de2c71d8918d96a0168660ce17cddf364e3ec0d4bd90f2104751a1927ee1d23f3e7a69840ed040b00e5f6e4866ec58813149cc382aebf6162608c79574d553f47230e924a0ef1ebf55d8e1a52abb62a2d7ac86027c7c03cc83fa1949da29e2f3037ab986fd2fffe650e3149babae5a50b1ee9696f3babec72e29697c82422814d272085500fd837fe3c7a973ef4c169af12dd7f02700620bb045bdbf84623f326350570b3cadbc9aea4200b28287e17ab:8c890cccadc7760e1e82e43c44b3dc0b685a48b479ae13cc0a6b0557d0fb1cbabba63d2a96843412ea8d36c50acbf52b92cfb2dce49dc48af6ddcf8ee47a860835ca57f0f915e5209d54ea4b871ffb585354df1b4a4a1796fbe4d6227d3e1aba5171ed0391a79e83e24d82fdafd15c17b28bf6c94d618c74d65264e58faaacd2902872fdd0efa22e8d2d7ce8e3b8197f0c3615b0a385235fa9fd8e4564ee6e6b1650b4cfb94d872c805c32d4f3a18f966461d3adbb605fa525884f8eb197627396ba4d995d78ac02948a0eaabb58519b9a8e2e7985cd1de2c71d8918d96a0168660ce17cddf364e3ec0d4bd90f2104751a1927ee1d23f3e7a69840ed040b00e5f6e4866ec58813149cc382aebf6162608c79574d553f47230e924a0ef1ebf55d8e1a52abb62a2d7ac86027c7c03cc83fa1949da29e2f3037ab986fd2fffe650e3149babae5a50b1ee9696f3babec72e29697c82422814d272085500fd837fe3c7a973ef4c169af12dd7f02700620bb045bdbf84623f326350570b3cadbc9aea4200b28287e17ab: +9184ef618816832592bc8eb35f4ffd4ff98dfbf7776c90f2aad212ce7e03351e687b7726010d9bde2c90e573cd2a2a702ff28c4a2af70afc7315c94d575601e5:687b7726010d9bde2c90e573cd2a2a702ff28c4a2af70afc7315c94d575601e5:729eb7e54a9d00c58617af18c345b8dc6e5b4e0f57de2f3c02e54a2ec8f1425ec2e240775b5ab0c10f84ac8bafda4584f7e21c655faecd8030a98906bd68398f26b5d58d92b6cf045e9bd9743c74c9a342ec61ce57f37b981eac4d8bf034608866e985bb68686a68b4a2af88b992a2a6d2dc8ce88bfb0a36cf28bbab7024abfa2bea53313b66c906f4f7cf66970f540095bd0104aa4924dd82e15413c22679f847e48cd0c7ec1f677e005fec0177fbd5c559fc39add613991fbaeae4d24d39d309ef74647f8192cc4c62d0642028c76a1b951f6bc9639deb91ecc08be6043f2109705a42c7eae712649d91d96ccbbfb63d8d0dd6dd112160f61361ecdc6793929ca9aef9ab56944a6fa4a7df1e279eaf58ce8323a9cf62c94279fff7440fbc936baa61489c999330badcb9fc0e184bc5093f330cbb242f71fb378738fea10511dd438364d7f76bcc:b3c24e75132c563475422d5ea412b5c1e8e6e5ea1c08ead1393c412da134c9a1638284ea7e2ca032fe3d3e32a9066a8c8839903f6ef46e966bb5e492d8c2aa00729eb7e54a9d00c58617af18c345b8dc6e5b4e0f57de2f3c02e54a2ec8f1425ec2e240775b5ab0c10f84ac8bafda4584f7e21c655faecd8030a98906bd68398f26b5d58d92b6cf045e9bd9743c74c9a342ec61ce57f37b981eac4d8bf034608866e985bb68686a68b4a2af88b992a2a6d2dc8ce88bfb0a36cf28bbab7024abfa2bea53313b66c906f4f7cf66970f540095bd0104aa4924dd82e15413c22679f847e48cd0c7ec1f677e005fec0177fbd5c559fc39add613991fbaeae4d24d39d309ef74647f8192cc4c62d0642028c76a1b951f6bc9639deb91ecc08be6043f2109705a42c7eae712649d91d96ccbbfb63d8d0dd6dd112160f61361ecdc6793929ca9aef9ab56944a6fa4a7df1e279eaf58ce8323a9cf62c94279fff7440fbc936baa61489c999330badcb9fc0e184bc5093f330cbb242f71fb378738fea10511dd438364d7f76bcc: +354e13152ee1fe748a1252204c6527bdc1b1eb2eb53678150e6359924708d812d45ff6c5fb83e7bb9669aa8960deb7dbc665c988439b6c9ef672c6811dc8bcf6:d45ff6c5fb83e7bb9669aa8960deb7dbc665c988439b6c9ef672c6811dc8bcf6:8e5fccf66b1ba6169cb685733d9d0e0190361c90bcab95c163285a97fe356d2bdcde3c9380268805a384d063da09ccd9969cc3ff7431e60a8e9f869cd62faa0e356151b280bc526e577c2c538c9a724dc48bf88b70321d7e1eeedb3c4af706748c942e67bdabdb41bec2977b1523069e31e29b76300288f88a51b384b80cc2526f1679340ddec3881f5cd28b0378d9cd0a812b68dd3f68f7a23e1b54bee7466ac765cf38df04d67441dfa498c4bffc52045fa6d2dbcdbfa33dfaa77644ffccef0decdb6790c70a0d734ec287cc338cb5a909c0055189301169c4f7702c05c0911a27b16ef9ed934fa6a0ca7b13e413523422535647968030edc40cd73e7d6b345b7581f438316d68e3cd292b846d3f4f7c4862bc7e6b3fb89a27f6f60cd7db2e34ec9aae1013fe37acff8ad888cb9a593ef5e621eae5186c58b31dcfde22870e336d33f440f6b8d49a:de2b46e65f3decef34332e500f2e11306fbdcf1be85a1c1ee68ba3045dcec2c7be608d22927da1f44c0e2083ae622cf3c29d893887994efcfa2ca594f5051f038e5fccf66b1ba6169cb685733d9d0e0190361c90bcab95c163285a97fe356d2bdcde3c9380268805a384d063da09ccd9969cc3ff7431e60a8e9f869cd62faa0e356151b280bc526e577c2c538c9a724dc48bf88b70321d7e1eeedb3c4af706748c942e67bdabdb41bec2977b1523069e31e29b76300288f88a51b384b80cc2526f1679340ddec3881f5cd28b0378d9cd0a812b68dd3f68f7a23e1b54bee7466ac765cf38df04d67441dfa498c4bffc52045fa6d2dbcdbfa33dfaa77644ffccef0decdb6790c70a0d734ec287cc338cb5a909c0055189301169c4f7702c05c0911a27b16ef9ed934fa6a0ca7b13e413523422535647968030edc40cd73e7d6b345b7581f438316d68e3cd292b846d3f4f7c4862bc7e6b3fb89a27f6f60cd7db2e34ec9aae1013fe37acff8ad888cb9a593ef5e621eae5186c58b31dcfde22870e336d33f440f6b8d49a: +7ff62d4b3c4d99d342d4bb401d726b21e99f4ef592149fc311b68761f5567ff67fdfdb9eca29d3f01d9486d7e112ce03aa37b91326a4283b9c03999c5eda099a:7fdfdb9eca29d3f01d9486d7e112ce03aa37b91326a4283b9c03999c5eda099a:99c44c796572a4823fc6c3807730839173774c05dbfc1492ed0d00509a95a1de37274b3135ed0456a1718e576597dc13f2a2ab37a45c06cbb4a2d22afad4d5f3d90ab3d8da4dcdaa06d44f2219088401c5dceee26055c4782f78d7d63a380608e1bef89eeef338c2f0897da106fafce2fb2ebc5db669c7c172c9cfe77d3109d239fe5d005c8ee751511b5a88317c729b0d8b70b52f6bd3cda2fe865c77f36e4f1b635f336e036bd718bec90ee78a802811510c4058c1ba364017253aa842922e1dd7d7a0f0fc9c69e43fc4eaeffaaf1ae5fa5d2d73b43079617baba030923fe5b13d2c1c4fe6fac3f2db74e2020a734b6121a0302fce820ba0580ce6135348fdf0632e0008df03ee112168f5cfa0037a26a1f69b1f1317edf2a3ab367455a77e00691215d7aa3133c2159d3da2b134cf04f0defbf07a6064011e64dd14d4f8f064356655428804c2771a:058f79927fbf6178724815c7b11c63baaa90bcc15d7272be082f8a9141861c816433055f6cf6491424853f9ec78bb91ace913a93411b4e5ed58bc4ba5715c60a99c44c796572a4823fc6c3807730839173774c05dbfc1492ed0d00509a95a1de37274b3135ed0456a1718e576597dc13f2a2ab37a45c06cbb4a2d22afad4d5f3d90ab3d8da4dcdaa06d44f2219088401c5dceee26055c4782f78d7d63a380608e1bef89eeef338c2f0897da106fafce2fb2ebc5db669c7c172c9cfe77d3109d239fe5d005c8ee751511b5a88317c729b0d8b70b52f6bd3cda2fe865c77f36e4f1b635f336e036bd718bec90ee78a802811510c4058c1ba364017253aa842922e1dd7d7a0f0fc9c69e43fc4eaeffaaf1ae5fa5d2d73b43079617baba030923fe5b13d2c1c4fe6fac3f2db74e2020a734b6121a0302fce820ba0580ce6135348fdf0632e0008df03ee112168f5cfa0037a26a1f69b1f1317edf2a3ab367455a77e00691215d7aa3133c2159d3da2b134cf04f0defbf07a6064011e64dd14d4f8f064356655428804c2771a: +6cabadd03f8a2e6ebab96a74f80e18164e4d1b6baa678f5a82e25604af989aaf2a4a3179564194e00100c18bc35351d8b135bbae5b32b28fce1d7b6766ca4b32:2a4a3179564194e00100c18bc35351d8b135bbae5b32b28fce1d7b6766ca4b32:279f78cf3b9ccfc6e1b01e1a82f50ed172e9a8e1e702bb15661dd7dc3a456ff7a7a7fdfb081db3867079630c7f70fd753292ec60ecbf50632e9aa45b996505c66e6dc3c6ae892e21b6a8705e4bbae8f16a3378554b31fdb0139dcd15c96a8a7e4b88756a86d18db5dc74fd7691197dd88e2c7d5df52b049344cdc477c9cd7e89eda99ccfb1d00814d0152b9654df3279372ca5f18b1c946f2894a76b079ddb1c3cd61fbb969aeec9193a6b88fb7d136c07f9821e5c1074b4e93bcaf6fa14d0d1d7e1707589d77ec1337206e53a1f06cc26672ff95c13d5ff444766931ba30a0afdcdadd2098e9c41fd87a3f23cd16dbb0efbf8092ce33e327f42610990e1cee6cb8e54951aa081e69765ae4009aeed758e768de50c23d9a22b4a06dc4d19fc8cbd0cdef4c983461755d0a3b5d6a9c12253e09568339ff7e5f78c5fdf7ec89f9186a621a8c0eed11b67022e:4e65c6c1d493045e8a9250e397c1d1d30ffed24db66a8961aa458f8f0fcb760c39fe8657d7ab8f84000b96d519717cff71f926522c1efec7f8b2624eae55f60c279f78cf3b9ccfc6e1b01e1a82f50ed172e9a8e1e702bb15661dd7dc3a456ff7a7a7fdfb081db3867079630c7f70fd753292ec60ecbf50632e9aa45b996505c66e6dc3c6ae892e21b6a8705e4bbae8f16a3378554b31fdb0139dcd15c96a8a7e4b88756a86d18db5dc74fd7691197dd88e2c7d5df52b049344cdc477c9cd7e89eda99ccfb1d00814d0152b9654df3279372ca5f18b1c946f2894a76b079ddb1c3cd61fbb969aeec9193a6b88fb7d136c07f9821e5c1074b4e93bcaf6fa14d0d1d7e1707589d77ec1337206e53a1f06cc26672ff95c13d5ff444766931ba30a0afdcdadd2098e9c41fd87a3f23cd16dbb0efbf8092ce33e327f42610990e1cee6cb8e54951aa081e69765ae4009aeed758e768de50c23d9a22b4a06dc4d19fc8cbd0cdef4c983461755d0a3b5d6a9c12253e09568339ff7e5f78c5fdf7ec89f9186a621a8c0eed11b67022e: +0fa0c32c3ae34be51b92f91945405981a8e202488558a8e220c288c7d6a5532dd6aee62bd91fc9453635ffcc02b2f38dcab13285140380580ccdff0865df0492:d6aee62bd91fc9453635ffcc02b2f38dcab13285140380580ccdff0865df0492:53f44be0e5997ff07264cb64ba1359e2801def8755e64a2362bddaf597e672d021d34fface6d97e0f2b1f6ae625fd33d3c4f6e9ff7d0c73f1da8defb23f324975e921bb2473258177a16612567edf7d5760f3f3e3a6d26aaabc5fde4e2043f73fa70f128020933b1ba3b6bd69498e9503ea670f1ed880d3651f2e4c59e79cabc86e9b703394294112d5d8e213c317423b525a6df70106a9d658a262028b5f45100cb77d1150d8fe461eed434f241015f3276ad7b09a291b4a7f35e3c30051cbf13b1d4a7fa0c81a50f939e7c49673afdc87883c9e3e61f5a1df03755470fda74bf23ea88676b258a97a280d5f90b52b714b596035bae08c8d0fe6d94f8949559b1f27d7116cf59dd3cfbf18202a09c13f5c4fbc8d97225492887d32870c2297e34debd9876d6d01ac27a16b088b079079f2b20feb02537cda314c43cb2dca371b9df37ed11ec97e1a7a6993a:7e9ab85ee94fe4b35dcb545329a0ef25923de5c9dc23e7df1a7e77ab0dcfb89e03f4e785ca6429cb2b0df50da6230f733f00f33a45c4e576cd40bdb84f1ae00153f44be0e5997ff07264cb64ba1359e2801def8755e64a2362bddaf597e672d021d34fface6d97e0f2b1f6ae625fd33d3c4f6e9ff7d0c73f1da8defb23f324975e921bb2473258177a16612567edf7d5760f3f3e3a6d26aaabc5fde4e2043f73fa70f128020933b1ba3b6bd69498e9503ea670f1ed880d3651f2e4c59e79cabc86e9b703394294112d5d8e213c317423b525a6df70106a9d658a262028b5f45100cb77d1150d8fe461eed434f241015f3276ad7b09a291b4a7f35e3c30051cbf13b1d4a7fa0c81a50f939e7c49673afdc87883c9e3e61f5a1df03755470fda74bf23ea88676b258a97a280d5f90b52b714b596035bae08c8d0fe6d94f8949559b1f27d7116cf59dd3cfbf18202a09c13f5c4fbc8d97225492887d32870c2297e34debd9876d6d01ac27a16b088b079079f2b20feb02537cda314c43cb2dca371b9df37ed11ec97e1a7a6993a: +7b06f88026fa86f39fce2426f67cc5996bedd0cfc4b5ebb1b5e3edbb47e080aa3f1469ee6a2e7867e2e9012d402cf5a4861497c01df879a1deb1c539830b58de:3f1469ee6a2e7867e2e9012d402cf5a4861497c01df879a1deb1c539830b58de:71175d4e21721297d9176d817f4e785d9600d923f987fe0b26fd79d33a5ea5d1e818b71f0f92b8c73afddabdcc27f6d16e26aafa874cfd77a00e06c36b041487582bb933760f88b419127345776ea418f83522254fed33819bc5c95f8f8404cc144ebf1486c88515409d3433aaf519d9920f5256e629419e9a95580a35b069b8d25533dfcbc98ad36404a951808e01378c03266326d120046975fde07daef3266caacd821c1403499d7fdf17c033c8d8c3f28f162b5f09dfdaca06285f00c6cb986dfdf5151aa6639608b5b13e78d65a4368585b16138754fbd113835a686cd066c2b89bb0953c24d50e77bf0fc457c1e0fcf5d44da8db9a88f062be3b688d5cdcff1d1c00e81ec9d413882295b341fee8fa427dc109adeb5f284eec202f1bef115bf96b1782d3ccdeb682b69bf92d170c007d5df80e1ed962f677dc24a145a1e4e829e8dec0104e5f78365944:42f133e34e3eb7032a133ed781537ec62e44a5ce8381e5e0bf9e13a914a4b2c757811d6d3b1e86672424ea4230d10f7c610abb7069e61e319b4066a2bd7bc90071175d4e21721297d9176d817f4e785d9600d923f987fe0b26fd79d33a5ea5d1e818b71f0f92b8c73afddabdcc27f6d16e26aafa874cfd77a00e06c36b041487582bb933760f88b419127345776ea418f83522254fed33819bc5c95f8f8404cc144ebf1486c88515409d3433aaf519d9920f5256e629419e9a95580a35b069b8d25533dfcbc98ad36404a951808e01378c03266326d120046975fde07daef3266caacd821c1403499d7fdf17c033c8d8c3f28f162b5f09dfdaca06285f00c6cb986dfdf5151aa6639608b5b13e78d65a4368585b16138754fbd113835a686cd066c2b89bb0953c24d50e77bf0fc457c1e0fcf5d44da8db9a88f062be3b688d5cdcff1d1c00e81ec9d413882295b341fee8fa427dc109adeb5f284eec202f1bef115bf96b1782d3ccdeb682b69bf92d170c007d5df80e1ed962f677dc24a145a1e4e829e8dec0104e5f78365944: +c3f5e149968a24f4de9119531975f443015ccca305d7119ed4749e8bf6d94fc739aaccdb948a4038538a4588322f806bb129b5876c4bec51271afe4f49690045:39aaccdb948a4038538a4588322f806bb129b5876c4bec51271afe4f49690045:c46370e37f2e0cadcf93402f1f0cb048f52881ba750b7a43f56ab11ce348732fb57e7f9aaf8dfcbe455e14e983c248d026a27e7f148d5db5a53f94635702b895127771047a876d14107386c5e0ff8933345bbd7a936d990d33efa28c2ec4e4864ffd2ff576f7c88f954cfc1c459e883bb712dae3cdf6632066f1f4d13a509615b3360cadc5a307f23e52a51b40a6feebe0b18d0e9ee4e348f33cd81a8def222f6a59b12861d335bd9af85cc004be46f1d3a424f4870ae9dc587e5a4ade136b9370649348c33ac3bf1febeebffea37085ed59cac9d9e696470b234609e9a10a9d431ff91e69cb5135fd117ff58a36539744ebe70cea6973c00c7a4d57b62f4a7136d731b8e46ff18ec0ed69070031905075d8541d568cfce6eeb76242b7819a7b6a93552111bb88f165527cfa6966d39fcbe0a7dea008e39c7a3e577ab307cd1d0ea326833d52654e172955f3fcd4:5fa2b531677b00b85b0a313cbd479f55f4ab3ec5cfce5e454d2b74176ccc3399c899f9d6b51ed4c1e76185ac9fe730c4b4014044f7041185bc3c85722eb2ea02c46370e37f2e0cadcf93402f1f0cb048f52881ba750b7a43f56ab11ce348732fb57e7f9aaf8dfcbe455e14e983c248d026a27e7f148d5db5a53f94635702b895127771047a876d14107386c5e0ff8933345bbd7a936d990d33efa28c2ec4e4864ffd2ff576f7c88f954cfc1c459e883bb712dae3cdf6632066f1f4d13a509615b3360cadc5a307f23e52a51b40a6feebe0b18d0e9ee4e348f33cd81a8def222f6a59b12861d335bd9af85cc004be46f1d3a424f4870ae9dc587e5a4ade136b9370649348c33ac3bf1febeebffea37085ed59cac9d9e696470b234609e9a10a9d431ff91e69cb5135fd117ff58a36539744ebe70cea6973c00c7a4d57b62f4a7136d731b8e46ff18ec0ed69070031905075d8541d568cfce6eeb76242b7819a7b6a93552111bb88f165527cfa6966d39fcbe0a7dea008e39c7a3e577ab307cd1d0ea326833d52654e172955f3fcd4: +42305c9302f45ea6f87e26e2208fd94b3c4ad037b1b6c83cf6677aa1096a013c3b97b1f11ce45ba46ffbb25b76bfc5ad7b77f90cc69ed76115dea4029469d587:3b97b1f11ce45ba46ffbb25b76bfc5ad7b77f90cc69ed76115dea4029469d587:d110828d449198d675e74e8e39439fd15e75bf2cc1f430abfb245836885bafc420f754b89d2fbbf6dd3490792e7a4f766073cfe3b302d089831ace869e2730fde45c2121ec3ef217aa9c43fa7cc7e9ed0a01ad9f1d2fc3613638ca9fc193c98b37455bf5dbf8f38b64708dfdca6c21f0975f1017c5da5f6434bda9f033cec2a631ab50318e017b170b240bf01eb8b36c7e1cb59e7736ac34444208132a8f59e4f313d65d849c6a4fdf13e20ecaee3823e589a171b39b2489497b06e6ff58c2c9f1dc5d3aa3bd10e6443e22d42d07b783f79fd43a46e1cde314b663a95f7246dea131fcd46d1dc333c5454f86b2c4e2e424dea405cc2230d4dcd39a2eab2f92845cf6a7994192063f1202749ef52dcb96f2b79ed6a98118ca0b99ba2285490860eb4c61ab78b9ddc6acc7ad883fa5e96f9d029171223abf7573e36230e0a81f6c1311151473ee264f4b842e923dcb3b:18d05e5d01668e83f40fa3bbee28b388acf318d1b0b5ad668c672f345c8eda14c2f884cd2a9039459ce0810bc5b580fe70d3964a43edb49e73a6ff914bbf040cd110828d449198d675e74e8e39439fd15e75bf2cc1f430abfb245836885bafc420f754b89d2fbbf6dd3490792e7a4f766073cfe3b302d089831ace869e2730fde45c2121ec3ef217aa9c43fa7cc7e9ed0a01ad9f1d2fc3613638ca9fc193c98b37455bf5dbf8f38b64708dfdca6c21f0975f1017c5da5f6434bda9f033cec2a631ab50318e017b170b240bf01eb8b36c7e1cb59e7736ac34444208132a8f59e4f313d65d849c6a4fdf13e20ecaee3823e589a171b39b2489497b06e6ff58c2c9f1dc5d3aa3bd10e6443e22d42d07b783f79fd43a46e1cde314b663a95f7246dea131fcd46d1dc333c5454f86b2c4e2e424dea405cc2230d4dcd39a2eab2f92845cf6a7994192063f1202749ef52dcb96f2b79ed6a98118ca0b99ba2285490860eb4c61ab78b9ddc6acc7ad883fa5e96f9d029171223abf7573e36230e0a81f6c1311151473ee264f4b842e923dcb3b: +c57a43dcd7bab8516009546918d71ad459b7345efdca8d4f19929875c839d7222083b444236b9ab31d4e00c89d55c6260fee71ac1a47c4b5ba227404d382b82d:2083b444236b9ab31d4e00c89d55c6260fee71ac1a47c4b5ba227404d382b82d:a4f6d9c281cf81a28a0b9e77499aa24bde96cc1264374491c008294ee0af6f6e4bbb686396f59068d358e30fe9992db0c6f16680a1c71e27a4a907ac607d39bdc3258c7956482fb37996f4beb3e5051b8148019a1c256e2ee999ebc8ce64c54e07fedb4fbd8953ebd93b7d69ce5a0082edd6209d12d3619b4fd2eae916461f72a4ce727157251a19209bbff9fbdbd289436f3fcacc6b4e1318521a47839cba4b14f7d7a21e7b5d6b6a753d5804afcd2b1eb7779b92abab8afa8aa4fa51caec0b85dcd0fc2a0676036d3f56630a831ffeb502861dd89161c708a9c006c73c930ce5b94756426ff18aa112fb4eb9a68500b48d4eedbd4167b6ffd0a11d49443a173ce9d949436748fc0634f06bb08b8f3423f4463dba7b4d199b64df578117f0a2645f0b2a1e2ada27d286f76733f25b82ed1d48a5c3898d4ad621e50ed9060daad40a39532e4d1bf162ce36804d5d4e2d:1edef9bc036971f1fa88edf45393c802e6c1a1631c8a06871a09a320821dce40beca97e53a0361a955a4c6d60b8ca8e400c81340911ccb4f56284041cdbb1804a4f6d9c281cf81a28a0b9e77499aa24bde96cc1264374491c008294ee0af6f6e4bbb686396f59068d358e30fe9992db0c6f16680a1c71e27a4a907ac607d39bdc3258c7956482fb37996f4beb3e5051b8148019a1c256e2ee999ebc8ce64c54e07fedb4fbd8953ebd93b7d69ce5a0082edd6209d12d3619b4fd2eae916461f72a4ce727157251a19209bbff9fbdbd289436f3fcacc6b4e1318521a47839cba4b14f7d7a21e7b5d6b6a753d5804afcd2b1eb7779b92abab8afa8aa4fa51caec0b85dcd0fc2a0676036d3f56630a831ffeb502861dd89161c708a9c006c73c930ce5b94756426ff18aa112fb4eb9a68500b48d4eedbd4167b6ffd0a11d49443a173ce9d949436748fc0634f06bb08b8f3423f4463dba7b4d199b64df578117f0a2645f0b2a1e2ada27d286f76733f25b82ed1d48a5c3898d4ad621e50ed9060daad40a39532e4d1bf162ce36804d5d4e2d: +2dddb6b8fd04fa90ece1a709f8418f2e5d0c9c43afe7cfce19e6ad15a73476f78059de6a7c4776489ecc2e7d707ffce30285bf30a23f78d72db49cfd6ed0d492:8059de6a7c4776489ecc2e7d707ffce30285bf30a23f78d72db49cfd6ed0d492:474baa590a4cd72d5424e51d8257b3d44325bc4c5063a0033c86ebbe99ed7212184c19944d082a115379dd4cece973faa0bca6485bd25f3744a719e70aa0291e1b5a96e637c140616a98263357c76b6eb0083fe51414e386870d0fdc7dd9abe4ff6fb5bbf1e7b15dac3e08e2615f655c3104ceb32a4cc2c9e9c43cf282d346ac253ccc46b635ae040973b49735720ffb890469a567c5824e0c00d7ccd5509a718092a906461c4d6163eaf422418f5fc6e009fc3f529ac61a2f89bb8e0ed45d940c4c2331ff8d8e1d6d58d417d8fc2656a02e8701aee75aed918724eebe4a2cf4744c5c401e217023df68a6f6a0228bd05a679a697d8de7036b9ed269090d3c65486afb91e27954eb15b964665ede7ad008f12fb3a9d0e69c13b4254f43819e0818a4195f68b8a38ae81f3fcb1879c95ab4cd0ffc38e381089260cca967ace5a085b457ab5eb363852101377570f9ac9e38:c634ea7bf72e895a2e796e2834201415b8b45e05e045559284eb9052c0e84f62a5a9f0c9764f7576788c7228b19ef517c195497325a48a9344b147c12fd75509474baa590a4cd72d5424e51d8257b3d44325bc4c5063a0033c86ebbe99ed7212184c19944d082a115379dd4cece973faa0bca6485bd25f3744a719e70aa0291e1b5a96e637c140616a98263357c76b6eb0083fe51414e386870d0fdc7dd9abe4ff6fb5bbf1e7b15dac3e08e2615f655c3104ceb32a4cc2c9e9c43cf282d346ac253ccc46b635ae040973b49735720ffb890469a567c5824e0c00d7ccd5509a718092a906461c4d6163eaf422418f5fc6e009fc3f529ac61a2f89bb8e0ed45d940c4c2331ff8d8e1d6d58d417d8fc2656a02e8701aee75aed918724eebe4a2cf4744c5c401e217023df68a6f6a0228bd05a679a697d8de7036b9ed269090d3c65486afb91e27954eb15b964665ede7ad008f12fb3a9d0e69c13b4254f43819e0818a4195f68b8a38ae81f3fcb1879c95ab4cd0ffc38e381089260cca967ace5a085b457ab5eb363852101377570f9ac9e38: +5547f1004baedfce5cfc0850b05302374aad24f6163994ecd751df3af3c106207ce620787385ee1951ac49a77352ee0d6f8c5cd47df74e9e3216a6324fc7cf7f:7ce620787385ee1951ac49a77352ee0d6f8c5cd47df74e9e3216a6324fc7cf7f:a6c17eeb5b8066c2cd9a89667317a945a0c7c96996e77ae854c509c6cd0631e922ad04503af87a3c4628adafed7600d071c078a22e7f64bda08a362b38b26ca15006d38acf532d0dedea4177a2d33f06956d80e963848ec791b2762fa99449b4f1a1ed9b3f2580be3ac7d7f52fb14421d6222ba76f807750c6cbb0b16f0895fc73d9dfc587e1a9e5d1e58375fbab705b8f0c1fd7df8b3ad446f2f08459e7ed1af59556fbc966dc249c1cf604f3e677c8a09d4363608774bf3811bef0642748c55c516c7a580fa3499050acb30eed870d0d91174cb623e98c3ad121cf81f04e57d49b008424a98a31eeaaf5f38e000f903d48d215ed52f862d636a5a73607de85760167267efe30f8a26ebc5aa0c09f5b258d3361ca69d1d7ee07b59648179ab2170ec50c07f6616f216872529421a6334a4a1ed3d2671ef47bc9a92afb58314e832db8a9003408a0487503fe4f67770dd4b6:29df3ad589009c667baa5e72dabb4e53cb7876de4e7efe5cc21ead7fa878db57f97c1103ddb39a861eb88653c1d4ec3b4306e4584b47b8bc90423119e7e4af00a6c17eeb5b8066c2cd9a89667317a945a0c7c96996e77ae854c509c6cd0631e922ad04503af87a3c4628adafed7600d071c078a22e7f64bda08a362b38b26ca15006d38acf532d0dedea4177a2d33f06956d80e963848ec791b2762fa99449b4f1a1ed9b3f2580be3ac7d7f52fb14421d6222ba76f807750c6cbb0b16f0895fc73d9dfc587e1a9e5d1e58375fbab705b8f0c1fd7df8b3ad446f2f08459e7ed1af59556fbc966dc249c1cf604f3e677c8a09d4363608774bf3811bef0642748c55c516c7a580fa3499050acb30eed870d0d91174cb623e98c3ad121cf81f04e57d49b008424a98a31eeaaf5f38e000f903d48d215ed52f862d636a5a73607de85760167267efe30f8a26ebc5aa0c09f5b258d3361ca69d1d7ee07b59648179ab2170ec50c07f6616f216872529421a6334a4a1ed3d2671ef47bc9a92afb58314e832db8a9003408a0487503fe4f67770dd4b6: +3dd7203c237aefe9e38a201ff341490179905f9f100828da18fcbe58768b5760f067d7b2ff3a957e8373a7d42ef0832bcda84ebf287249a184a212a94c99ea5b:f067d7b2ff3a957e8373a7d42ef0832bcda84ebf287249a184a212a94c99ea5b:db28ed31ac04b0c2decee7a6b24fc9a082cc262ca7ccf2a247d6372ec3e9120ecedb4542ea593fea30335c5ab9dd318a3b4fd5834299cf3f53d9ef46137b273c390ec3c26a0b4470d0d94b77d82cae4b24587837b167bb7f8166710baeb3ee70af797316cb7d05fa57e468ae3f0bd449404d8528808b41fcca62f5e0a2aa5d8f3acab008cc5f6e5ab02777bdcde87f0a10ef06a4bb37fe02c94815cf76bfb8f5cdd865cc26dcb5cf492edfd547b535e2e6a6d8540956dcba62cfea19a9474406e934337e454270e01036ac45793b6b8aceda187a08d56a2ce4e98f42ea375b101a6b9fcb4231d171aa463eeb43586a4b82a387bcddaf71a80fd5c1f7292efc2bd8e70c11eaa817106061b6c461c4883d613cc06c7e2a03f73d90fc55cdc07265eefd36be72270383d6c676cae37c93691f1ae3d927b3a1cd963e4229757ae5231eea73a9f71515628305410ac2593b325cc631:4c036935a96abc0d050d907bedbe9946fb97439f039c742e051ccf09add7df44d17da98c2ca01bdc2424da1e4debf347f8fff48ac8030d2cc07f9575c044be04db28ed31ac04b0c2decee7a6b24fc9a082cc262ca7ccf2a247d6372ec3e9120ecedb4542ea593fea30335c5ab9dd318a3b4fd5834299cf3f53d9ef46137b273c390ec3c26a0b4470d0d94b77d82cae4b24587837b167bb7f8166710baeb3ee70af797316cb7d05fa57e468ae3f0bd449404d8528808b41fcca62f5e0a2aa5d8f3acab008cc5f6e5ab02777bdcde87f0a10ef06a4bb37fe02c94815cf76bfb8f5cdd865cc26dcb5cf492edfd547b535e2e6a6d8540956dcba62cfea19a9474406e934337e454270e01036ac45793b6b8aceda187a08d56a2ce4e98f42ea375b101a6b9fcb4231d171aa463eeb43586a4b82a387bcddaf71a80fd5c1f7292efc2bd8e70c11eaa817106061b6c461c4883d613cc06c7e2a03f73d90fc55cdc07265eefd36be72270383d6c676cae37c93691f1ae3d927b3a1cd963e4229757ae5231eea73a9f71515628305410ac2593b325cc631: +282775df9ebbd7c5a65f3a2b096e36ee64a8f8ea719da77758739e4e7476111da2b49646033a13937cad6b0e914e3cec54989c252ca5643d076555d8c55e56e0:a2b49646033a13937cad6b0e914e3cec54989c252ca5643d076555d8c55e56e0:14cc50c2973ea9d0187a73f71cb9f1ce07e739e049ec2b27e6613c10c26b73a2a966e01ac3be8b505aeaad1485c1c2a3c6c2b00f81b9e5f927b73bfd498601a7622e8544837aad02e72bf72196dc246902e58af253ad7e025e3666d3bfc46b5b02f0eb4a37c9554992abc8651de12fd813177379bb0ce172cd8aaf937f979642bc2ed7c7a430cb14c3cd3101b9f6b91ee3f542acdf017f8c2116297f4564768f4db95dad8a9bcdc8da4d8fb13ef6e2da0b1316d3c8c2f3ed836b35fe2fd33effb409e3bc1b0f85225d2a1de3bfc2d20563946475c4d7ca9fddbaf59ad8f8961d287ae7dd803e7af1fa612329b1bdc04e225600ae731bc01ae0925aed62ac50d46086f3646cf47b072f0d3b044b36f85cec729a8bb2b92883ca4dfb34a8ee8a0273b31af50982bb6131bfa11d55504b1f6f1a0a00438ca26d8ab4f48bcddc9d5a38851abede4151d5b70d720732a00abea2c8b979:15763973859402907d8dcb86adc24a2a168ba3abf2246173d6348afed51ef60b0c0edeff4e10bcef4c6e5778c8bc1f5e9ee0237373445b455155d23de127a20214cc50c2973ea9d0187a73f71cb9f1ce07e739e049ec2b27e6613c10c26b73a2a966e01ac3be8b505aeaad1485c1c2a3c6c2b00f81b9e5f927b73bfd498601a7622e8544837aad02e72bf72196dc246902e58af253ad7e025e3666d3bfc46b5b02f0eb4a37c9554992abc8651de12fd813177379bb0ce172cd8aaf937f979642bc2ed7c7a430cb14c3cd3101b9f6b91ee3f542acdf017f8c2116297f4564768f4db95dad8a9bcdc8da4d8fb13ef6e2da0b1316d3c8c2f3ed836b35fe2fd33effb409e3bc1b0f85225d2a1de3bfc2d20563946475c4d7ca9fddbaf59ad8f8961d287ae7dd803e7af1fa612329b1bdc04e225600ae731bc01ae0925aed62ac50d46086f3646cf47b072f0d3b044b36f85cec729a8bb2b92883ca4dfb34a8ee8a0273b31af50982bb6131bfa11d55504b1f6f1a0a00438ca26d8ab4f48bcddc9d5a38851abede4151d5b70d720732a00abea2c8b979: +4730a5cf9772d7d6665ba787bea4c95252e6ecd63ec62390547bf100c0a46375f9f094f7cc1d40f1926b5b22dce465784468b20ab349bc6d4fdf78d0042bbc5b:f9f094f7cc1d40f1926b5b22dce465784468b20ab349bc6d4fdf78d0042bbc5b:e7476d2e668420e1b0fadfbaa54286fa7fa890a87b8280e26078152295e1e6e55d1241435cc430a8693bb10cde4643f59cbfcc256f45f5090c909a14c7fc49d37bfc25af11e8f4c83f4c32d4aabf43b20fa382bb6622a1848f8ffc4dff3408bb4ec7c67a35b4cdaee5e279c0fc0a66093a9f36a60fdd65e6334a804e845c8530b6fda363b5640337d027243ccfb3c177f43e717896e46ead7f72ca06aa0ff1e77247121baf48be9a445f729ca1390fc46151cbd33fcbd7373f27a6ba55c92cbf6945b09b44b9a4e5800d403070ae66048997b2197f02181a097e563f9b9acc841139258a258bc610d3bd891637356b2edc8c184c35c65af91aaf7b1c16d74a5f5f862548139254ecf550631d5f8849afdb5b64cf366ff2633a93f3a18c39b5150245fb5f33c9e4e2d94af6963a70b88f9e7e519f8fa2a0f2e3749de883d0e6f052a949d0fc7153a8693f6d801d7352eb2f7a465c0e:552c7347bdfe131646ce0932d82a36d2c1b76d7c30ee890e0592e19f9d18b9a56f48d7a9b68c017da6b550c943af4a907baf317e419fbbc96f6cf4bfad42de00e7476d2e668420e1b0fadfbaa54286fa7fa890a87b8280e26078152295e1e6e55d1241435cc430a8693bb10cde4643f59cbfcc256f45f5090c909a14c7fc49d37bfc25af11e8f4c83f4c32d4aabf43b20fa382bb6622a1848f8ffc4dff3408bb4ec7c67a35b4cdaee5e279c0fc0a66093a9f36a60fdd65e6334a804e845c8530b6fda363b5640337d027243ccfb3c177f43e717896e46ead7f72ca06aa0ff1e77247121baf48be9a445f729ca1390fc46151cbd33fcbd7373f27a6ba55c92cbf6945b09b44b9a4e5800d403070ae66048997b2197f02181a097e563f9b9acc841139258a258bc610d3bd891637356b2edc8c184c35c65af91aaf7b1c16d74a5f5f862548139254ecf550631d5f8849afdb5b64cf366ff2633a93f3a18c39b5150245fb5f33c9e4e2d94af6963a70b88f9e7e519f8fa2a0f2e3749de883d0e6f052a949d0fc7153a8693f6d801d7352eb2f7a465c0e: +2770aadd1d123e9547832dfb2a837eba089179ef4f23abc4a53f2a714e423ee23c5fbb07530dd3a20ff35a500e3708926310fed8a899690232b42c15bd86e5dc:3c5fbb07530dd3a20ff35a500e3708926310fed8a899690232b42c15bd86e5dc:a5cc2055eba3cf6f0c6332c1f2ab5854870913b03ff7093bc94f335add44332231d9869f027d82efd5f1227144ab56e3222dc3ddccf062d9c1b0c1024d9b416dfa3ee8a7027923003465e0ffaefb75b9f29dc6bcf213adc5e318fd8ba93a7aa5bfb495de9d7c5e1a196cd3a2d7721f8ba785aa9052a1811c7fcc8f93932765059cab9c9b718945895ef26f3ac048d4cabf91a9e6aa83ac14d43156827837914eb763a23cba53f60f150f4b70203ec1833ff105849457a8da7327661fb23a554164e05fcf0146b10674964be6f6aa0acc94c41ad57180e5180d199bd9102f55d740e81789b15671bbd0670e6de5d97e1ae626d8a0ebc32c8fd9d24737274e47d2dd5941a272e72a598928ad109cde937bf248d57f5d2942983c51e2a89f8f054d5c48dfad8fcf1ffa97f7de6a3a43ca15fc6720efaec69f0836d84223f9776d111ec2bbc69b2dfd58be8ca12c072164b718cd7c246d64:f267715e9a84c7314f2d5869ef4ab8d2149a13f7e8e1c728c423906293b49ce6283454dd1c7b04741df2eabedc4d6ab1397dc95a679df04d2c17d66c79bb7601a5cc2055eba3cf6f0c6332c1f2ab5854870913b03ff7093bc94f335add44332231d9869f027d82efd5f1227144ab56e3222dc3ddccf062d9c1b0c1024d9b416dfa3ee8a7027923003465e0ffaefb75b9f29dc6bcf213adc5e318fd8ba93a7aa5bfb495de9d7c5e1a196cd3a2d7721f8ba785aa9052a1811c7fcc8f93932765059cab9c9b718945895ef26f3ac048d4cabf91a9e6aa83ac14d43156827837914eb763a23cba53f60f150f4b70203ec1833ff105849457a8da7327661fb23a554164e05fcf0146b10674964be6f6aa0acc94c41ad57180e5180d199bd9102f55d740e81789b15671bbd0670e6de5d97e1ae626d8a0ebc32c8fd9d24737274e47d2dd5941a272e72a598928ad109cde937bf248d57f5d2942983c51e2a89f8f054d5c48dfad8fcf1ffa97f7de6a3a43ca15fc6720efaec69f0836d84223f9776d111ec2bbc69b2dfd58be8ca12c072164b718cd7c246d64: +4fdab7c1600e70114b11f533242376af7614b4d5da046ac4bedea21d8a361598a25c9a94d6e4ecd95a4bd6805f762eb1c457a8d45d243238b1839cbba8f441cc:a25c9a94d6e4ecd95a4bd6805f762eb1c457a8d45d243238b1839cbba8f441cc:da405890d11a872c119dab5efcbff61e931f38eccca457edc626d3ea29ed4fe3154fafec1444da74343c06ad90ac9d17b511bcb73bb49d90bafb7c7ea800bd58411df1275c3cae71b700a5dab491a4261678587956aa4a219e1ac6dd3fb2cb8c46197218e726dc7ed234526a6b01c0d72cb93ab3f4f38a08e5940b3f61a72ad2789a0532000fac1d2d2e3ad632ac8b62bb3ff5b99d53597bf4d44b19674924df9b3db3d0253f74627ccab30031c85e291c58b5fa9167522a46746fc307036745d4f9817786e5d300e6c5d503125fea01dec3e3fedbf3861ca2627a0518fb2b24e5a7a014178719e9b345f7b249ce3a413280c8deb674f59a25be92a8ab6400c7c52b0728ae34e22b2ec200c1cbaba2ccd8af29249d17af60c36007a722fc80258a7bebab1cdaad7462a8b7588c2f7e27c6d07afcf60117fed11bd6859e75e3b4fcee3981881e95dd116827dd4b369af069d3c8f2676f8a:5075c090cfbeb6b01802af7f4da5aa4f434d5ee2f3530eebb75c85e08621f83edc08aa96693894a4277633ba81e19e9e55af5c495daa5e1a6f8cbb79c01c7207da405890d11a872c119dab5efcbff61e931f38eccca457edc626d3ea29ed4fe3154fafec1444da74343c06ad90ac9d17b511bcb73bb49d90bafb7c7ea800bd58411df1275c3cae71b700a5dab491a4261678587956aa4a219e1ac6dd3fb2cb8c46197218e726dc7ed234526a6b01c0d72cb93ab3f4f38a08e5940b3f61a72ad2789a0532000fac1d2d2e3ad632ac8b62bb3ff5b99d53597bf4d44b19674924df9b3db3d0253f74627ccab30031c85e291c58b5fa9167522a46746fc307036745d4f9817786e5d300e6c5d503125fea01dec3e3fedbf3861ca2627a0518fb2b24e5a7a014178719e9b345f7b249ce3a413280c8deb674f59a25be92a8ab6400c7c52b0728ae34e22b2ec200c1cbaba2ccd8af29249d17af60c36007a722fc80258a7bebab1cdaad7462a8b7588c2f7e27c6d07afcf60117fed11bd6859e75e3b4fcee3981881e95dd116827dd4b369af069d3c8f2676f8a: +264504604e70d72dc4474dbb34913e9c0f806dfe18c7879a41762a9e4390ec61eb2b518ce7dc71c91f3665581651fd03af84c46bf1fed2433222353bc7ec511d:eb2b518ce7dc71c91f3665581651fd03af84c46bf1fed2433222353bc7ec511d:901d70e67ed242f2ec1dda813d4c052cfb31fd00cfe5446bf3b93fdb950f952d94ef9c99d1c264a6b13c3554a264beb97ed20e6b5d66ad84db5d8f1de35c496f947a23270954051f8e4dbe0d3ef9ab3003dd47b859356cecb81c50affa68c15dadb5f864d5e1bb4d3bada6f3aba1c83c438d79a94bfb50b43879e9cef08a2bfb22fad943dbf7683779746e31c486f01fd644905048b112ee258042153f46d1c7772a0624bcd6941e9062cfda75dc8712533f4057335c298038cbca29ebdb560a295a88339692808eb3481fd9735ea414f620c143b2133f57bb64e44778a8ca70918202d157426102e1dfc0a8f7b1ae487b74f02792633154dfe74caa1b7088fda22fa8b9bc354c585f1567706e2955493870f54169e0d7691159df43897961d24a852ea970c514948f3b48f71ee586e72ec78db820f253e08db84f6f312c4333bd0b732fe75883507783e9a1fd4fbab8e5870f9bf7ad58aa:eea439a00f7e459b402b835150a779eed171ab971bd1b58dcc7f9386dadd583de8dc69e267121dde41f0f9493d450b16219cdf3c22f09482ce402fe17ca49e08901d70e67ed242f2ec1dda813d4c052cfb31fd00cfe5446bf3b93fdb950f952d94ef9c99d1c264a6b13c3554a264beb97ed20e6b5d66ad84db5d8f1de35c496f947a23270954051f8e4dbe0d3ef9ab3003dd47b859356cecb81c50affa68c15dadb5f864d5e1bb4d3bada6f3aba1c83c438d79a94bfb50b43879e9cef08a2bfb22fad943dbf7683779746e31c486f01fd644905048b112ee258042153f46d1c7772a0624bcd6941e9062cfda75dc8712533f4057335c298038cbca29ebdb560a295a88339692808eb3481fd9735ea414f620c143b2133f57bb64e44778a8ca70918202d157426102e1dfc0a8f7b1ae487b74f02792633154dfe74caa1b7088fda22fa8b9bc354c585f1567706e2955493870f54169e0d7691159df43897961d24a852ea970c514948f3b48f71ee586e72ec78db820f253e08db84f6f312c4333bd0b732fe75883507783e9a1fd4fbab8e5870f9bf7ad58aa: +2ca7447a3668b748b1fd3d52d2080d30e34d397bb2846caf8f659ac168788ca5ab331cd40a31d0173c0c8c1c17002532807bf89e3edb6d34c2dd8294632b9fbc:ab331cd40a31d0173c0c8c1c17002532807bf89e3edb6d34c2dd8294632b9fbc:a82bcd9424bffda0f2f5e9eae17835dbe468f61b785aab82934737a91c5f602cb7c617cdffe87cad726a4972e15a7b8ee147f062d2a5a4d89706b571fa8aa2b95981c78abeaaae86203fa2c0e07297406ea8c27111a86dbe1d5a7c3b7ae930904d9890f6d4abebd1412a73ad5feea64acf065d3e63b5cbe20cf20bbd2d8b94f9053ed5f66633482530124446605918de66455e8cf4b101a127233c4e27d5d55bf95bd3195d0340d43531fc75faf8dded5275bf89750de838fd10c31745be4ca41fa871cb0f9b016706a1a7e3c44bb90ac7a8ad51e272389292fd6c98ad7a069e76e3f5f3e0cc770b9e9b35a765d0d93712d7cdabd17e5d01dd8183af4ad9365db0a0fa41381fce60a081df1c5ab0f8c18f95a7a8b582dfff7f149ea579df0623b33b7508f0c663f01e3a2dcd9dfbee51cc615220fdaffdab51bdae42cb9f7fa9e3b7c69cc8ada5ccd642529ba514fdc54fcf2720b8f5d08b95:f93ada15ae9cd2b54f26f86f0c28392aed5eb6b6b44d01a4e33a54e7da37c38e8d53366f73fd85be642e4ec81236d163f0d025e76c8bbdd65d43df49f09c1f01a82bcd9424bffda0f2f5e9eae17835dbe468f61b785aab82934737a91c5f602cb7c617cdffe87cad726a4972e15a7b8ee147f062d2a5a4d89706b571fa8aa2b95981c78abeaaae86203fa2c0e07297406ea8c27111a86dbe1d5a7c3b7ae930904d9890f6d4abebd1412a73ad5feea64acf065d3e63b5cbe20cf20bbd2d8b94f9053ed5f66633482530124446605918de66455e8cf4b101a127233c4e27d5d55bf95bd3195d0340d43531fc75faf8dded5275bf89750de838fd10c31745be4ca41fa871cb0f9b016706a1a7e3c44bb90ac7a8ad51e272389292fd6c98ad7a069e76e3f5f3e0cc770b9e9b35a765d0d93712d7cdabd17e5d01dd8183af4ad9365db0a0fa41381fce60a081df1c5ab0f8c18f95a7a8b582dfff7f149ea579df0623b33b7508f0c663f01e3a2dcd9dfbee51cc615220fdaffdab51bdae42cb9f7fa9e3b7c69cc8ada5ccd642529ba514fdc54fcf2720b8f5d08b95: +494ea9bcce26885b7d17d1fc114448f239f0ce46e5f247b4c999fa86296924726901e5efae57536ba5fdd96b59657359065f25d391a1aa8cdc0d38bb5d53c139:6901e5efae57536ba5fdd96b59657359065f25d391a1aa8cdc0d38bb5d53c139:3badbfa5f5a8aa2cce0a60e686cdce654d24452f98fd54872e7395b39464380a0e185557ea134d095730864f4254d3dd946970c10c804fcc0899dfa024205be0f80b1c75449523324fe6a0751e47b4ff4822b8c33e9eaf1d1d96e0de3d4acd89696b7fcc03d49f92f82b9725700b350db1a87615369545561b8599f5ea920a310a8bafc0e8d7468cbf6f3820e943594afdd5166e4e3309dddd7694ef67e694f34fc62724ff96ac3364176f34e8a02b4cf569db5b8f77d58512aedabf0bcd1c2df12db3a9473f948c5c3243309aae46c49efd088b60f31a8a72ad7e5a35acc5d89fa66807eb5d3ba9cdf08d4753cb85089ee36f5c96b432b6928352afad58012225d6157f9e3611426df921b6d1d8374628a63031e9ffb90e42ffbba021f174f68503155430152c9155dc98ffa26c4fab065e1f8e4622c2f28a8cb043110b617441140f8e20adc16f799d1d5096b1f50532be5042d21b81ea46c7:548a093a680361b7dc56f14503b55eeec3b3f4fd4ca99d6aedce0830f7f4ae2f7328539b34c48fc9760922333dae9c7c017e7db73b8faa6c06be05e347992b063badbfa5f5a8aa2cce0a60e686cdce654d24452f98fd54872e7395b39464380a0e185557ea134d095730864f4254d3dd946970c10c804fcc0899dfa024205be0f80b1c75449523324fe6a0751e47b4ff4822b8c33e9eaf1d1d96e0de3d4acd89696b7fcc03d49f92f82b9725700b350db1a87615369545561b8599f5ea920a310a8bafc0e8d7468cbf6f3820e943594afdd5166e4e3309dddd7694ef67e694f34fc62724ff96ac3364176f34e8a02b4cf569db5b8f77d58512aedabf0bcd1c2df12db3a9473f948c5c3243309aae46c49efd088b60f31a8a72ad7e5a35acc5d89fa66807eb5d3ba9cdf08d4753cb85089ee36f5c96b432b6928352afad58012225d6157f9e3611426df921b6d1d8374628a63031e9ffb90e42ffbba021f174f68503155430152c9155dc98ffa26c4fab065e1f8e4622c2f28a8cb043110b617441140f8e20adc16f799d1d5096b1f50532be5042d21b81ea46c7: +00d735ebaee75dd579a40dfd82508274d01a1572df99b811d5b01190d82192e4ba02517c0fdd3e2614b3f7bf99ed9b492b80edf0495d230f881730ea45bc17c4:ba02517c0fdd3e2614b3f7bf99ed9b492b80edf0495d230f881730ea45bc17c4:59c0b69af95d074c88fdc8f063bfdc31b5f4a9bc9cecdffa8128e01e7c1937dde5eb0570b51b7b5d0a67a3555b4cdce2bca7a31a4fe8e1d03ab32b4035e6dadbf1532059ee01d3d9a7633a0e706a1154cab22a07cd74c06a3cb601244cf3cf35a35c3100ba47f31372a2da65dcff0d7a80a1055d8aa99212e899aad7f02e949e6fee4d3c9cefa85069eaff1f6ad06fc300c871ab82b2bedb934d20875c2a263242cdb7f9be192a8710b24c7ea98d43daec8baa5553c678a38f0e0adf7d3ff2dcc799a1dbad6eab1c3d9458a9db922f02e75cfab9d65c7336dae71895d5bb15cac203f2b38b9996c410f8655ad22d3c091c20b7f926d45e780128f19747462abc5c58932fbb9e0bc62d53868802f1b083f183b8a1f9434986d5cf97c04e2f3e145730cba98779c7fed0cab1c05d5e4653c6c3f6736260bc78ee4372862ffe9e90371d762c7432781f35ced884a4baca05653ef25f25a6f3d5628308:dcdc54611937d2bd06cacd9818b3be15ce7425427a75f50d197a337a3b8ba6714ef48866f243bd5ac7415e914517a2c1c5a953f432b99db0e620d64f74eb850559c0b69af95d074c88fdc8f063bfdc31b5f4a9bc9cecdffa8128e01e7c1937dde5eb0570b51b7b5d0a67a3555b4cdce2bca7a31a4fe8e1d03ab32b4035e6dadbf1532059ee01d3d9a7633a0e706a1154cab22a07cd74c06a3cb601244cf3cf35a35c3100ba47f31372a2da65dcff0d7a80a1055d8aa99212e899aad7f02e949e6fee4d3c9cefa85069eaff1f6ad06fc300c871ab82b2bedb934d20875c2a263242cdb7f9be192a8710b24c7ea98d43daec8baa5553c678a38f0e0adf7d3ff2dcc799a1dbad6eab1c3d9458a9db922f02e75cfab9d65c7336dae71895d5bb15cac203f2b38b9996c410f8655ad22d3c091c20b7f926d45e780128f19747462abc5c58932fbb9e0bc62d53868802f1b083f183b8a1f9434986d5cf97c04e2f3e145730cba98779c7fed0cab1c05d5e4653c6c3f6736260bc78ee4372862ffe9e90371d762c7432781f35ced884a4baca05653ef25f25a6f3d5628308: +8c34b905440b61911d1d8137c53d46a1a76d4609af973e18eb4c5709295627bbb69a8b2fdf5c20e734c2ffb294bc8ae1011d664f11afe7fbc471925cf72fa99d:b69a8b2fdf5c20e734c2ffb294bc8ae1011d664f11afe7fbc471925cf72fa99d:30b57a389b48a0beb1a48432bff6b314bded79c4a1763a5acb57cea1bfb4c6d016cf090f5bd05bbd114e33ae7c17782dfa264f46c45f8c599c603016fe9ff05b6b5a99e92fe713a4cd5c41b292ed2bb2e9cf33a440542e821ec82cbf665c3f02e3dc337d7fdb58e31b27cb2954541468814698510df18c85c81fad12db11ec6b966f4930da5646b991db97445097da30dab61cda53a41083cb96add19de6c5eec323bca9d3530e38c00b35af7360077601be6ac97f3030f930a27b90fe8b6911bae389065adc15e1882300e2a003274d23182d5efd5ba4b9130c07bd5c65fecb8b5cb7eb38836b318befdfd77de4d6ca0181f77ae5740891683225f549dd8426145c97c5818c319f7ab2d868e1a41ceab64c085116069897bf2ca3667652406155ed0646431b6de1ccc03b4279ae4d326679265dce82048e7298e1f87fcec0768ac0f5d8ff84f7210be54d411af8edea7217f4e59413121e148c60da:3e0b72073dc9375eedcca6c4fc1cd315938a050c92716bd2284f4629a962beec0b7d7cf16ab923d58f5b90d3901a8e5c75c8f17dab9998e007d8c49511973d0e30b57a389b48a0beb1a48432bff6b314bded79c4a1763a5acb57cea1bfb4c6d016cf090f5bd05bbd114e33ae7c17782dfa264f46c45f8c599c603016fe9ff05b6b5a99e92fe713a4cd5c41b292ed2bb2e9cf33a440542e821ec82cbf665c3f02e3dc337d7fdb58e31b27cb2954541468814698510df18c85c81fad12db11ec6b966f4930da5646b991db97445097da30dab61cda53a41083cb96add19de6c5eec323bca9d3530e38c00b35af7360077601be6ac97f3030f930a27b90fe8b6911bae389065adc15e1882300e2a003274d23182d5efd5ba4b9130c07bd5c65fecb8b5cb7eb38836b318befdfd77de4d6ca0181f77ae5740891683225f549dd8426145c97c5818c319f7ab2d868e1a41ceab64c085116069897bf2ca3667652406155ed0646431b6de1ccc03b4279ae4d326679265dce82048e7298e1f87fcec0768ac0f5d8ff84f7210be54d411af8edea7217f4e59413121e148c60da: +77a83e18c9f000eeff7deeac959ecba2206c0aa39d2f0e2aed5729482a7a022962b1b316135596bfbca6037ed847c61fb7f09fa36ce90abb7789b86f768b59dd:62b1b316135596bfbca6037ed847c61fb7f09fa36ce90abb7789b86f768b59dd:f3d5fa2acaefd858f1df26e03059cdcbc2468ad74afc993d0db9c4cde4113f8d55c7da71d38ba06520531c61fddb5f33d5f0353be2376e580711be45c0a30b1fa01b55e228c6fa35e3f95b67909fc7df3fd464d93d661a926f9d11f7550c17fbcc3496526e8f10e0c8916677b2be5b319b688f21e81aaa9482e5c93e64ce8c437b9c1e14fefed70a3fee568811dc31cadab3d5b220254465336dc4d97a3bd096b5e065e0cfbe82849e2c1905aca486533f0da7a61f1e9a55b8e2a83262deeb59f2b13d3a8aef5700845b83b25ae2183c0ddac0ce42f8d25674cb0d0d220a6de7c1858bb07d59a3372344d944602aa451d2b937db0fe6feca0beba81721fc361ea7509e2b6d397e1c191b56f54ab436d0d27ab4c061bd661ad1a4452387e8735754d07fa7ef4d4548b172582425b299046e6301b5ba6b914418f149cf722e10bde2e0d41700f12c8429fc897b7819da92292240cd45565458c9a7b29c12:1eaad8420ac12c99ac1ff4476678e3cbbe94da6a797f174664d5ee0f641433fb1e7cb2f5613e10805df8654cd8e0d45d96230932bc7f20b04eae836435134309f3d5fa2acaefd858f1df26e03059cdcbc2468ad74afc993d0db9c4cde4113f8d55c7da71d38ba06520531c61fddb5f33d5f0353be2376e580711be45c0a30b1fa01b55e228c6fa35e3f95b67909fc7df3fd464d93d661a926f9d11f7550c17fbcc3496526e8f10e0c8916677b2be5b319b688f21e81aaa9482e5c93e64ce8c437b9c1e14fefed70a3fee568811dc31cadab3d5b220254465336dc4d97a3bd096b5e065e0cfbe82849e2c1905aca486533f0da7a61f1e9a55b8e2a83262deeb59f2b13d3a8aef5700845b83b25ae2183c0ddac0ce42f8d25674cb0d0d220a6de7c1858bb07d59a3372344d944602aa451d2b937db0fe6feca0beba81721fc361ea7509e2b6d397e1c191b56f54ab436d0d27ab4c061bd661ad1a4452387e8735754d07fa7ef4d4548b172582425b299046e6301b5ba6b914418f149cf722e10bde2e0d41700f12c8429fc897b7819da92292240cd45565458c9a7b29c12: +73b03373ef1fd849005ecd6270dd9906f19f4439e40376cdbc520902bc976812663719e08ba3ba1666f6069a3f54991866b18cc6be41991b02eb3026ff9e155f:663719e08ba3ba1666f6069a3f54991866b18cc6be41991b02eb3026ff9e155f:d5c2deaba795c30aba321bc7de6996f0d90e4d05c747fb4dae8f3451895def6e16e72f38eace756f36635f8fb0b72a3a0c1f54663817a94d4fd346f835ab0e657f001a6f2cecb86d0825bd02639254f7f7f38ca99dbb86c64a633f73baf933aae3563281f4005e2d0e7cec9fbde8e588a957e211068be65b3d3d35bf4e8d5bb3478333df9ced9b2abaf48697994a145e9321499fc5ee560f4fbb6849e1ae8eb3d1de0083a21a03f6a6b28176f0130d3895e50e75e3d7d0947a7bc2c5b9ff69895d27791442ba8d0f2180712b567f712ea912f3b0d92c19342e0106ff1d87b46ad33af300b90855ba9769d366e79425d98e4de19905a04577707cbe625b84691781cd26bf62260b4a8bd605f77af6f970e1b3a112e8918344bd0d8d2e41dfd2ce9895b0246e50887aa3a577ff73be4b6ae60feb0ca36f6a5f8171ed209e5c566529c0940d9b4bd744ccee56e54a9a0c6e4da520dd315c2872b02db563703e:a40abe98fc69da8a1ff9ff5c2cca93632e975980ee8b82c3c376022d6524ab736d01b072f2b681b5f1cd3ea067012ed6d074e949c42327a366caa9e4750a3c08d5c2deaba795c30aba321bc7de6996f0d90e4d05c747fb4dae8f3451895def6e16e72f38eace756f36635f8fb0b72a3a0c1f54663817a94d4fd346f835ab0e657f001a6f2cecb86d0825bd02639254f7f7f38ca99dbb86c64a633f73baf933aae3563281f4005e2d0e7cec9fbde8e588a957e211068be65b3d3d35bf4e8d5bb3478333df9ced9b2abaf48697994a145e9321499fc5ee560f4fbb6849e1ae8eb3d1de0083a21a03f6a6b28176f0130d3895e50e75e3d7d0947a7bc2c5b9ff69895d27791442ba8d0f2180712b567f712ea912f3b0d92c19342e0106ff1d87b46ad33af300b90855ba9769d366e79425d98e4de19905a04577707cbe625b84691781cd26bf62260b4a8bd605f77af6f970e1b3a112e8918344bd0d8d2e41dfd2ce9895b0246e50887aa3a577ff73be4b6ae60feb0ca36f6a5f8171ed209e5c566529c0940d9b4bd744ccee56e54a9a0c6e4da520dd315c2872b02db563703e: +eab179e41ed5c889ffe6aabdc054faf1307c395e46e313e17a14fe01023ffa3086f34746d3f7a01ddbe322f1aca56d22856d38733a3a6900bb08e776450ec803:86f34746d3f7a01ddbe322f1aca56d22856d38733a3a6900bb08e776450ec803:971095cebe5031530224387c5c31966e389b8566390054cf45264b44e18964b7be52c33c4ffb259af16283438fa15dd66bc7791b7533ef10cb0beab524a6437626f4cc74512851adcc2fb129055a482c61107383fb7c5241831d5551634eef0dc0b8f9053a00971aa8fa1ae0898e4b481b6707e97c0f942040b339d92fc17bbade74675af243d8b2dafb15b1db55d12415b85f3037291930ab61600ba3431f8eb425be4491614728af101e81c091f348bc5ffd1bde6ae6cad5c15b3aa7358078cc4effb54a86e7f0e0c55e4cfe0a54605ed443fdf2aaba016585da617e77341d52889d75dd540d39fe8b7993ed705cfddea0cb0d5a731d6bfcdb816afaff47e963eedebdf241af5593353d6d401a34f029a8cdeb1904cc2caa4f9635cc2ba6b7b1a29da625ffc383be2f5a8f1fa4f39b2d4b4f4c2d8838ce258a04d4a120493fdf07f68c0ffd1c16b768a35c55fea2cac696b5c20efc10865cde8a64627dcd:143cb28027c2f82e375e5f340e7fe6e60ce7bd51000b49c74168af85e26ed2ed630ed2672090164cc54b052da694ebdd21a21b3053f4dcfd7895ea5f6c8aa80d971095cebe5031530224387c5c31966e389b8566390054cf45264b44e18964b7be52c33c4ffb259af16283438fa15dd66bc7791b7533ef10cb0beab524a6437626f4cc74512851adcc2fb129055a482c61107383fb7c5241831d5551634eef0dc0b8f9053a00971aa8fa1ae0898e4b481b6707e97c0f942040b339d92fc17bbade74675af243d8b2dafb15b1db55d12415b85f3037291930ab61600ba3431f8eb425be4491614728af101e81c091f348bc5ffd1bde6ae6cad5c15b3aa7358078cc4effb54a86e7f0e0c55e4cfe0a54605ed443fdf2aaba016585da617e77341d52889d75dd540d39fe8b7993ed705cfddea0cb0d5a731d6bfcdb816afaff47e963eedebdf241af5593353d6d401a34f029a8cdeb1904cc2caa4f9635cc2ba6b7b1a29da625ffc383be2f5a8f1fa4f39b2d4b4f4c2d8838ce258a04d4a120493fdf07f68c0ffd1c16b768a35c55fea2cac696b5c20efc10865cde8a64627dcd: +fbf146ebd51075570ec51ac410ae9f391db75b610ada6362b4dbd949656cfb66be7c2f5b21d746c8ea3245ce6f268e9da74e00fa85c9c475260c68fa1af6361f:be7c2f5b21d746c8ea3245ce6f268e9da74e00fa85c9c475260c68fa1af6361f:cd7ad4f17fcff73acc402dc102d09079b29aaf2a0f4b27cf6beeb1e2b23d19ab47deb3ae1becd68861ea279c46691738f4fff47c43047c4f8b56b6bbcc3fde0723d44120dcd307a6310dc4f366b8f3cd52db19b8266a487f7872391c45fe0d3248a7abf2c20022d3769547f683067dcc363cd22fd7cda3cadc15804056f0e2aa2b795008c598be7a961805e6df291ba3041c47ff5640275f46e6ae82092d21abcbcfba11e730216008822de3ce462400596da79f7ae5d1df8389112ad98868fa94fb0546bfe6a67aa8d28c4d32072d2eadd6256255f18c2382e662dfa922a680e06a43622c4871d27d1807f7b2703070c83db8dd929c06038b2183cb8e2b9ec4c778d7ecf9e9ffac77fa7737b055feac2e7982aeeec0b72f1bbca2424e1a844bbac79cb2e7400f81dc449d0560b521a7c16bb4167e6696586058a9b8ed2e5116690b77f2a17e5c0b16a83dcbd2e24552293e258b32ba7f844944379342698627:6768006fe0f201b217dd10eb05d4b82adcfeb2ecfc8373c3308f4150394811eb60491881a2e53d1289d96478e18a64c34b2a19832cdccfd96a2e4a0c469fdc0bcd7ad4f17fcff73acc402dc102d09079b29aaf2a0f4b27cf6beeb1e2b23d19ab47deb3ae1becd68861ea279c46691738f4fff47c43047c4f8b56b6bbcc3fde0723d44120dcd307a6310dc4f366b8f3cd52db19b8266a487f7872391c45fe0d3248a7abf2c20022d3769547f683067dcc363cd22fd7cda3cadc15804056f0e2aa2b795008c598be7a961805e6df291ba3041c47ff5640275f46e6ae82092d21abcbcfba11e730216008822de3ce462400596da79f7ae5d1df8389112ad98868fa94fb0546bfe6a67aa8d28c4d32072d2eadd6256255f18c2382e662dfa922a680e06a43622c4871d27d1807f7b2703070c83db8dd929c06038b2183cb8e2b9ec4c778d7ecf9e9ffac77fa7737b055feac2e7982aeeec0b72f1bbca2424e1a844bbac79cb2e7400f81dc449d0560b521a7c16bb4167e6696586058a9b8ed2e5116690b77f2a17e5c0b16a83dcbd2e24552293e258b32ba7f844944379342698627: +dff0eb6b426dea2fd33c1d3fc24df9b31b486facb7edb8502954a3e8da99d9fdc245085ece69fb9aa560d0c27fdb634f7a840d41d8463660fbe82483b0f3cc3a:c245085ece69fb9aa560d0c27fdb634f7a840d41d8463660fbe82483b0f3cc3a:e7c9e313d86160f4c74aa0ae07369ee22b27f81b3f69097affae28dae48483fb52a5c062306b59610f5cdbff6332b1960cd6f2b8f7b41578c20f0bc9637a0fdfc739d61f699a573f1c1a0b49294506cf4487965e5bb07bbf81803cb3d5cb3829c66c4bee7fc800ede216150934d277dea50edb097b992f11bb669fdf140bf6ae9fec46c3ea32f888fde9d154ea84f01c51265a7d3fef6eefc1ccdbffd1e2c897f05546a3b1ca11d9517cd667c660ec3960f7a8e5e80202a78d3a388b92f5c1dee14ae6acf8e17c841c9557c35a2eeced6e6af6372148e483ccd06c8fe344924e1019fb91cbf7941b9a176a073415867210670410c5dbd0ac4a50e6c0a509ddfdc555f60d696d41c77db8e6c84d5181f872755e64a721b061fcd68c463db4d32c9e01ea501267de22879d7fc12c8ca0379edb45abaa6e64dda2af6d40ccf24fbebad7b5a8d3e52007945ecd3ddc1e3efeb522581ac80e98c863ba0c590a3ed95cd1:6b48b10f545ddb7a89cd5829f4e5b20146cf6bc96e550d06f65de8bdae7ccdded26cd630f86c9266bccf88e924033e04f83a54f8290d7f734cf8673cca8f9703e7c9e313d86160f4c74aa0ae07369ee22b27f81b3f69097affae28dae48483fb52a5c062306b59610f5cdbff6332b1960cd6f2b8f7b41578c20f0bc9637a0fdfc739d61f699a573f1c1a0b49294506cf4487965e5bb07bbf81803cb3d5cb3829c66c4bee7fc800ede216150934d277dea50edb097b992f11bb669fdf140bf6ae9fec46c3ea32f888fde9d154ea84f01c51265a7d3fef6eefc1ccdbffd1e2c897f05546a3b1ca11d9517cd667c660ec3960f7a8e5e80202a78d3a388b92f5c1dee14ae6acf8e17c841c9557c35a2eeced6e6af6372148e483ccd06c8fe344924e1019fb91cbf7941b9a176a073415867210670410c5dbd0ac4a50e6c0a509ddfdc555f60d696d41c77db8e6c84d5181f872755e64a721b061fcd68c463db4d32c9e01ea501267de22879d7fc12c8ca0379edb45abaa6e64dda2af6d40ccf24fbebad7b5a8d3e52007945ecd3ddc1e3efeb522581ac80e98c863ba0c590a3ed95cd1: +9f32958c7679b90fd5036056a75ec2eb2f56ec1effc7c012461dc89a3a1674201d7269dcb6d1f584e662d4ce251de0aba290ef78b97d448afb1e5333f1976d26:1d7269dcb6d1f584e662d4ce251de0aba290ef78b97d448afb1e5333f1976d26:a56ba86c71360504087e745c41627092ad6b49a71e9daa5640e1044bf04d4f071ad728779e95d1e2460584e6f0773545da82d4814c9189a120f12f3e3819813e5b240d0f26436f70ee353b4d20cea54a1460b5b8f1008d6f95f3aa2d8f1e908fced50d624e3a096938b9353854b96da463a2798a5a312ec790842c10c446e3350c764bf5c972593b9987bf23256daa8894d47f22e85b97607e66fc08a12c789c4746080368d321bb9015a1155b65523ad8e99bb989b44eac756b0734acd7c6357c70b59743246d1652d91b0f9896965141345b9945cf34980452f3502974edb76b9c785fb0f4395266b055f3b5db8aab68e9d7102a1cd9ee3d142504f0e88b282e603a738e051d98de05d1fcc65b5f7e99c4111cc0aec489abd0ecad311bfc13e7d1653b9c31e81c998037f959d5cd980835aa0e0b09bcbed634391151da02bc01a36c9a5800afb984163a7bb815edbc0226eda0595c724ca9b3f8a71178f0d20a5a:9881a5763bdb259a3fefbba3d957162d6c70b804fa94ab613406a6ec42505b8789465ca1a9a33e1895988842270c55e5bdd5483f6b17b31781b593507a6c1808a56ba86c71360504087e745c41627092ad6b49a71e9daa5640e1044bf04d4f071ad728779e95d1e2460584e6f0773545da82d4814c9189a120f12f3e3819813e5b240d0f26436f70ee353b4d20cea54a1460b5b8f1008d6f95f3aa2d8f1e908fced50d624e3a096938b9353854b96da463a2798a5a312ec790842c10c446e3350c764bf5c972593b9987bf23256daa8894d47f22e85b97607e66fc08a12c789c4746080368d321bb9015a1155b65523ad8e99bb989b44eac756b0734acd7c6357c70b59743246d1652d91b0f9896965141345b9945cf34980452f3502974edb76b9c785fb0f4395266b055f3b5db8aab68e9d7102a1cd9ee3d142504f0e88b282e603a738e051d98de05d1fcc65b5f7e99c4111cc0aec489abd0ecad311bfc13e7d1653b9c31e81c998037f959d5cd980835aa0e0b09bcbed634391151da02bc01a36c9a5800afb984163a7bb815edbc0226eda0595c724ca9b3f8a71178f0d20a5a: +f86d6f766f88b00717b7d6327eb26cf3ceeba5385184426f9cfd8295e2421ff2cb1d250504754183704dbe21c323d66f9f9011758f6d8dab6f597b199662145b:cb1d250504754183704dbe21c323d66f9f9011758f6d8dab6f597b199662145b:da8423a6b7a18f20aa1f90ed2331b17b24067c40175bc25d8109e21d87ac00528eb3b2f66a2b52dc7ef2f8cecb75c76099cfa23db8da897043ba1cce31e2dfea46075f5e073203eaeb3d62c84c107b6dab33a14eaf149aa61850c15f5a58d88a15aba9196f9e495e8dbecbcf7e8444f5dd72a08a099d7f6209990b562974ea829ef11d29a920e3a799d0d92cb50d50f817631ab09de97c31e9a05f4d78d649fcd93a83752078ab3bb0e16c564d4fb07ca923c0374ba5bf1eea7e73668e135031feafcbb47cbc2ae30ec16a39b9c337e0a62eecdd80c0b7a04924ac3972da4fa9299c14b5a53d37b08bf02268b3bac9ea9355090eeb04ad87bee0593ba4e4443dda38a97afbf2db9952df63f178f3b4c52bcc132be8d9e26881213abdeb7e1c44c4061548909f0520f0dd7520fc408ea28c2cebc0f53063a2d30570e05350e52b390dd9b67662984847be9ad9b4cd50b069ffd29dd9c62ef14701f8d012a4a70c8431cc:ec61c0b292203a8f1d87235ede92b74723c8d23408423773ae50b1e9bc4464e03e446da9dce4c39f6dd159bea26c009ed00120bc36d4a247dc0d24bcefcc110cda8423a6b7a18f20aa1f90ed2331b17b24067c40175bc25d8109e21d87ac00528eb3b2f66a2b52dc7ef2f8cecb75c76099cfa23db8da897043ba1cce31e2dfea46075f5e073203eaeb3d62c84c107b6dab33a14eaf149aa61850c15f5a58d88a15aba9196f9e495e8dbecbcf7e8444f5dd72a08a099d7f6209990b562974ea829ef11d29a920e3a799d0d92cb50d50f817631ab09de97c31e9a05f4d78d649fcd93a83752078ab3bb0e16c564d4fb07ca923c0374ba5bf1eea7e73668e135031feafcbb47cbc2ae30ec16a39b9c337e0a62eecdd80c0b7a04924ac3972da4fa9299c14b5a53d37b08bf02268b3bac9ea9355090eeb04ad87bee0593ba4e4443dda38a97afbf2db9952df63f178f3b4c52bcc132be8d9e26881213abdeb7e1c44c4061548909f0520f0dd7520fc408ea28c2cebc0f53063a2d30570e05350e52b390dd9b67662984847be9ad9b4cd50b069ffd29dd9c62ef14701f8d012a4a70c8431cc: +a5b34cefab9479df8389d7e6f6c146aa8affb0bec837f78af64624a145cc344e7b0f4f24d9972bc6fe83826c52716ad1e0d7d19f123858cb3e99fa636ac9631a:7b0f4f24d9972bc6fe83826c52716ad1e0d7d19f123858cb3e99fa636ac9631a:e21e98af6c2bac70557eb0e864da2c2b4d6c0a39a059d3477251f6178a39676f4749e7fbea623f148a43a8b0fe0610506fa658abd2f5fa39198f2636b724db22d1aebc2ab07b2b6dbffdee8cece81e1af1493ec1964e16bf86ab258ca0feb77e3c8717e44038abe152c14be15660bf93b2d48d92c4ed7074d2494210621bcf204fba88c654d5ffe01e1a53d08f70bb237089dc807216ff6a85dbec3102237d42590778acf6c1dc566d5a2bb9a63bc21c329c272e5965baeeb0fe891de3cc8cbfa8e541a8881df68942e7ff8dc656bd08575f6aaf924a176d663b1a1f43574d11768c701b269561e55438dbebfd443d2115cb933d1cde4a915b54c325c27f499ef02bd012ff1f9a36390922887600fe712bcdc23eb5974a305372ad52951f83f0e58cc49e289841621917f1fcb0235147240dae4cf3b99b6ac6d8de94efe7c4436714508bcd0114c56068ff1b7c16d51bd906437874d6549ab5d8087896872ec8a09d7412:2fbd899d72b6d39e4f45b8b62cbbd5f3c0acb1ad8540913fa585877e91ccfef7bee50a4b0f9fedf5cc1e0d1953ad399c8389a93391e1b7c929af6d6f3b796c08e21e98af6c2bac70557eb0e864da2c2b4d6c0a39a059d3477251f6178a39676f4749e7fbea623f148a43a8b0fe0610506fa658abd2f5fa39198f2636b724db22d1aebc2ab07b2b6dbffdee8cece81e1af1493ec1964e16bf86ab258ca0feb77e3c8717e44038abe152c14be15660bf93b2d48d92c4ed7074d2494210621bcf204fba88c654d5ffe01e1a53d08f70bb237089dc807216ff6a85dbec3102237d42590778acf6c1dc566d5a2bb9a63bc21c329c272e5965baeeb0fe891de3cc8cbfa8e541a8881df68942e7ff8dc656bd08575f6aaf924a176d663b1a1f43574d11768c701b269561e55438dbebfd443d2115cb933d1cde4a915b54c325c27f499ef02bd012ff1f9a36390922887600fe712bcdc23eb5974a305372ad52951f83f0e58cc49e289841621917f1fcb0235147240dae4cf3b99b6ac6d8de94efe7c4436714508bcd0114c56068ff1b7c16d51bd906437874d6549ab5d8087896872ec8a09d7412: +ad75c9ce299c4d59393367d77a4c9f8df8dcec765c6dbd25b527fb7669913604b9910548fe6312a119c9993eebcfb9dc90030ffb0e4de2b7ccd23cbeb4fef71b:b9910548fe6312a119c9993eebcfb9dc90030ffb0e4de2b7ccd23cbeb4fef71b:62fc5ab67deb1fee9ab6cca3b88a1df1e589f0fd4a88f4aa7738948761fe84372c5b18e4655220c1d84d52acad32e229a5c756c20fc62fe4b4b4e5fd7077ae4ed5397aa796f2307ceedb6505b39297856f4aeb5e70938e36ee24a0ac7d9868306f6b53910623b7dc89a6672ad738576ed5d88831dd338321c8902bc2061f65e94d452fdfa0dc665cefb92308e52301bd4627006b363d06b775a395914d8c863e95a00d6893f3376134c429f56478145e4456f7a12d65bb2b8965d728cb2ddbb708f7125c237095a92195d92fa727a372f3545ae701f3808fee802c8967a76e8a940e55fb2d810bfb47ada156f0eda1829b159cf05c7f36cf3847d7b21de84c3dc0fe658347f79396a01139a508b60022db1c0e5aeef47e445e66f783e62c96597bdb16f209c08a9132c7573136170ee3ebf24261265a89fb4f10333375e20b33ab7403464f5249461c6853c5fddb9f58af816892910393a7077b799fdc3489720998feea86:6b7ef27bcfbf2b714985033764fccff555e3f5bc44610d6c8c62117cb3831a07f4a8bddb0eaed1d46b0289b15de1aa4dcc17d71be96a09e66ba4dc4627c7870562fc5ab67deb1fee9ab6cca3b88a1df1e589f0fd4a88f4aa7738948761fe84372c5b18e4655220c1d84d52acad32e229a5c756c20fc62fe4b4b4e5fd7077ae4ed5397aa796f2307ceedb6505b39297856f4aeb5e70938e36ee24a0ac7d9868306f6b53910623b7dc89a6672ad738576ed5d88831dd338321c8902bc2061f65e94d452fdfa0dc665cefb92308e52301bd4627006b363d06b775a395914d8c863e95a00d6893f3376134c429f56478145e4456f7a12d65bb2b8965d728cb2ddbb708f7125c237095a92195d92fa727a372f3545ae701f3808fee802c8967a76e8a940e55fb2d810bfb47ada156f0eda1829b159cf05c7f36cf3847d7b21de84c3dc0fe658347f79396a01139a508b60022db1c0e5aeef47e445e66f783e62c96597bdb16f209c08a9132c7573136170ee3ebf24261265a89fb4f10333375e20b33ab7403464f5249461c6853c5fddb9f58af816892910393a7077b799fdc3489720998feea86: +1ced574529b9b416977e92eb39448a8717cac2934a243a5c44fb44b73ccc16da85e167d5f062fee82014f3c8b1beaed8eefb2c22d8649c424b86b21b11eb8bda:85e167d5f062fee82014f3c8b1beaed8eefb2c22d8649c424b86b21b11eb8bda:1b3b953cce6d15303c61ca707609f70e7250f6c0deba56a8ce522b5986689651cdb848b842b2229661b8eeabfb8570749ed6c2b10a8fbf515053b5ea7d7a9228349e4646f9505e198029fec9ce0f38e4e0ca73625842d64caf8ced070a6e29c743586aa3db6d82993ac71fd38b783162d8fe04ffd0fa5cbc381d0e219c91937df6c973912fc02fda5377312468274c4bee6dca7f79c8b544861ed5babcf5c50e1473491be01708ac7c9ff58f1e40f855497ce9d7cc47b9410f2edd00f6496740243b8d03b2f5fa742b9c630867f77ac42f2b62c14e5ebddc7b647a05fff43670745f2851eff4909f5d27d57ae87f61e965ee60fdf97724c59267f2610b7ad5de919856d64d7c212659ce8656149b6a6d29d8f92b312be50b6e2a431d36ae022b00a6fe360e3af65432899c43be0427e36d21cfec81f21aa53b33db5ed2c37da8f96ac3e7dc67a1de37546cf7de1008c7e1adbe0f34fa7eb2434d94e6a13f4cf86a98d497622f:e0303aefe08a77738dcc657afbb9b835ed279613a53c73fdc5ddbfb350e5cff4d6c9bb43dc07c95bf4e23b64c40f8804c7169952e3c8d59a7197241bfed0740f1b3b953cce6d15303c61ca707609f70e7250f6c0deba56a8ce522b5986689651cdb848b842b2229661b8eeabfb8570749ed6c2b10a8fbf515053b5ea7d7a9228349e4646f9505e198029fec9ce0f38e4e0ca73625842d64caf8ced070a6e29c743586aa3db6d82993ac71fd38b783162d8fe04ffd0fa5cbc381d0e219c91937df6c973912fc02fda5377312468274c4bee6dca7f79c8b544861ed5babcf5c50e1473491be01708ac7c9ff58f1e40f855497ce9d7cc47b9410f2edd00f6496740243b8d03b2f5fa742b9c630867f77ac42f2b62c14e5ebddc7b647a05fff43670745f2851eff4909f5d27d57ae87f61e965ee60fdf97724c59267f2610b7ad5de919856d64d7c212659ce8656149b6a6d29d8f92b312be50b6e2a431d36ae022b00a6fe360e3af65432899c43be0427e36d21cfec81f21aa53b33db5ed2c37da8f96ac3e7dc67a1de37546cf7de1008c7e1adbe0f34fa7eb2434d94e6a13f4cf86a98d497622f: +f0790d93e2d3b84f61ef4c807147aba410e415e72b71b0d61d01026fed99da3defdf649fb033cf328e0b287796f8a25e9c6e2e871b33c2c21a4028a8a25a4b28:efdf649fb033cf328e0b287796f8a25e9c6e2e871b33c2c21a4028a8a25a4b28:7973e9f32d74805992eb65da0d637335e50eff0ce68ea2d1f3a02de704492b9cfbe7e7ba96fdb42bb821a513d73fc60402e92c855deaed73ffeaf70952029062c833e14ec1b14f144e2207f6a0e727e5a7e3cbab27d5972970f69518a15b093e740cc0ce11bf5248f0826b8a98bde8bf2c7082c97aff158d08371118c89021cc3974ae8f76d86673c3f824b62c79c4b41f40eaa8943738f03300f68cbe175468eb235a9ff0e6537f8714e97e8f08ca444e41191063b5fabd156e85dcf66606b81dad4a95065584b3e0658c20a706eaf4a0777da4d2e0cd2a0fca60109c2b4403db3f03cd4781c1fbb0272202bcb11687808c50cb98f64b7f3fd3d43333bb5a061b9e377090abb1e0a885cb26b73c163e63ff6451ff2f4ec8249c7e152bd03973a1e964e2b5b235281a938399a112a24529e383a560dc50bb1b622ad74ef35658dcb10ffe022568ac3ffae5b465a8ed7643e8561b352ee9944a35d882c712b187788a0abae5a22f:08773a6a78762cbb1e25fcbb29139941bdf16f4e09a1fa08fc701f32f933edd74c0ae983c12a0a5b020b6bcf44bb719dde8ed0781a8298265640e1608c98b3017973e9f32d74805992eb65da0d637335e50eff0ce68ea2d1f3a02de704492b9cfbe7e7ba96fdb42bb821a513d73fc60402e92c855deaed73ffeaf70952029062c833e14ec1b14f144e2207f6a0e727e5a7e3cbab27d5972970f69518a15b093e740cc0ce11bf5248f0826b8a98bde8bf2c7082c97aff158d08371118c89021cc3974ae8f76d86673c3f824b62c79c4b41f40eaa8943738f03300f68cbe175468eb235a9ff0e6537f8714e97e8f08ca444e41191063b5fabd156e85dcf66606b81dad4a95065584b3e0658c20a706eaf4a0777da4d2e0cd2a0fca60109c2b4403db3f03cd4781c1fbb0272202bcb11687808c50cb98f64b7f3fd3d43333bb5a061b9e377090abb1e0a885cb26b73c163e63ff6451ff2f4ec8249c7e152bd03973a1e964e2b5b235281a938399a112a24529e383a560dc50bb1b622ad74ef35658dcb10ffe022568ac3ffae5b465a8ed7643e8561b352ee9944a35d882c712b187788a0abae5a22f: +4cb9df7ce6fae9d62ba09e8eb70e4c969bdeafcb5ec7d7024326e6603b0621bf018069dd0eb44055a35cd8c77c37ca9fb1ad2417271385e134b2f4e81f52033c:018069dd0eb44055a35cd8c77c37ca9fb1ad2417271385e134b2f4e81f52033c:14627d6ea0e7895460759476dc74c42800ceef994327518151490d9df23067914e44788a12768ccb25471b9c3ba9d14fb436dcba38429b3a0456877763c49175d0e082683e07a9058f3685c6279307b2303d1221b9c29793d8a4877f6df51587384dadf751c5f7bfbd207d519622c37b51ceeee2c20d8269f8cb88d3fe43d6d434d5bbd0e203c1532d97ba552147227496c87f67b50bb76193add0144df1c176657585408362ca2ed04ad62acf1c25e341dfd1498d85b4b1349a8b0b9b02c43523c55853419bfed37d5a2cdf17dfbf1a3bd7759d6ae180f9d27dcd9a8933e29a7c0a30771eea7c2e0fa242925d2336dce585629057d844323964f6d3d11ff0b3f829a3be8c9f0468a6823d8e70ab5a2da21e15fa8b041a29812222e9c30b2bd9a12d1fdee6f87876e8ce81009637a8bb2236129a47ca74289ee4aad429ffe29f47430241ca8cc3848b7200fd6e1470651a9a0a6f72c9033e831df051408a6260f65cbaf6e012b18e:e33c07836c537d6bfbd0f4592d6e35b163499ba78dc7ffcec565d04f9a7db781943e29e6ce76763e9baddf57437fd9c6b03239a6e6850e4502a356c2e12c370514627d6ea0e7895460759476dc74c42800ceef994327518151490d9df23067914e44788a12768ccb25471b9c3ba9d14fb436dcba38429b3a0456877763c49175d0e082683e07a9058f3685c6279307b2303d1221b9c29793d8a4877f6df51587384dadf751c5f7bfbd207d519622c37b51ceeee2c20d8269f8cb88d3fe43d6d434d5bbd0e203c1532d97ba552147227496c87f67b50bb76193add0144df1c176657585408362ca2ed04ad62acf1c25e341dfd1498d85b4b1349a8b0b9b02c43523c55853419bfed37d5a2cdf17dfbf1a3bd7759d6ae180f9d27dcd9a8933e29a7c0a30771eea7c2e0fa242925d2336dce585629057d844323964f6d3d11ff0b3f829a3be8c9f0468a6823d8e70ab5a2da21e15fa8b041a29812222e9c30b2bd9a12d1fdee6f87876e8ce81009637a8bb2236129a47ca74289ee4aad429ffe29f47430241ca8cc3848b7200fd6e1470651a9a0a6f72c9033e831df051408a6260f65cbaf6e012b18e: +a136e009d53e5ef59d0946bc175663a86bc0fcd29eadd95cfc9d266037b1e4fb9c1806ec0454f58314eb8397d64287dee386640d8491aba364607688841715a0:9c1806ec0454f58314eb8397d64287dee386640d8491aba364607688841715a0:a49d1c3d49e13c2eda56868a8824aa9f8d2bf72f21955ebafd07b3bdc8e924de20936cee513d8a64a47173a3bd659eff1accff8244b26aae1a0c27fa891bf4d85e8fb1b76a6cab1e7f74c89ee07bb40d714326f09b3fd40632fad208ea816f9072028c14b5b54ecc1c5b7fc809e7e0786e2f11495e76017eb62aa4563f3d00ee84348d9838cd17649f6929a6d206f60e6fc82e0c3464b27e0e6abd22f4469bdfd4cb54f77e329b80f71bf42129ec13c9dfe192adfaa42ee3ddeeda385816fbad5f411938c63b560f4ecd94534be7d98725cd94c99ce492f0f069ba0ec08f877a7812ef27ae19d7a77be63f66bcf8d6cf3a1a61fc9cfef104c7462a21ca7f03afb5bb1ac8c75124b554e8d044b810d95ff8c9dd09a34484d8c4b6c95f95c3c22823f52ce844293724d5259191f1ba0929e2acdbb8b9a7a8adf0c52e78acdfdf057b0985881afbed4dbebdebbdae0a2b63bd4e90f96afdcbbd78f506309f9bdb650013cb73faed73904e:bc094ba91c115dee15d753361a75f3f03d6af45c92157e95dbe8d32194b6c5ce72b9dc66f73df12dca0b639f3e791d478616a1f8d7359a42c8eae0dda16b1606a49d1c3d49e13c2eda56868a8824aa9f8d2bf72f21955ebafd07b3bdc8e924de20936cee513d8a64a47173a3bd659eff1accff8244b26aae1a0c27fa891bf4d85e8fb1b76a6cab1e7f74c89ee07bb40d714326f09b3fd40632fad208ea816f9072028c14b5b54ecc1c5b7fc809e7e0786e2f11495e76017eb62aa4563f3d00ee84348d9838cd17649f6929a6d206f60e6fc82e0c3464b27e0e6abd22f4469bdfd4cb54f77e329b80f71bf42129ec13c9dfe192adfaa42ee3ddeeda385816fbad5f411938c63b560f4ecd94534be7d98725cd94c99ce492f0f069ba0ec08f877a7812ef27ae19d7a77be63f66bcf8d6cf3a1a61fc9cfef104c7462a21ca7f03afb5bb1ac8c75124b554e8d044b810d95ff8c9dd09a34484d8c4b6c95f95c3c22823f52ce844293724d5259191f1ba0929e2acdbb8b9a7a8adf0c52e78acdfdf057b0985881afbed4dbebdebbdae0a2b63bd4e90f96afdcbbd78f506309f9bdb650013cb73faed73904e: +ff0f1c57dd884fbeea6e2917282b79ba67f8a6851267b9f4636dafda33bd2b5bfef6378ad12a7c252fa6eb742b05064b41530ff019dc680ab544c027ea2836e7:fef6378ad12a7c252fa6eb742b05064b41530ff019dc680ab544c027ea2836e7:522a5e5eff5b5e98fad6878a9d72df6eb318622610a1e1a48183f5590ecef5a6df671b28be91c88cdf7ae2881147fe6c37c28b43f64cf981c455c59e765ce94e1b6491631deaeef6d1da9ebca88643c77f83eae2cfdd2d97f604fe45081d1be5c4ae2d875996b8b6fecd707d3fa219a93ba0488e55247b405e330cfb97d31a1361c9b2084bdb13fb0c058925db8c3c649c9a3e937b533cc6310fa3b16126fb3cc9bb2b35c5c8300015488a30fadca3c8871fa70dfdc7055bf8e631f20c9b2528311e324a7c4edd5462079f3441c9ecf55fa999e731372344fdc0d413e417aaa001a1b2d3d9bc000fec1b02bd7a88a812d9d8a66f9464764c070c93041eefb17ce74eff6d4aff75f0cbf6a789a9ecde74abe33130fca0da853aa7c3313ada3f0ae2f595c6796a93685e729dd18a669d6381825ab3f36a391e7525b2a807a52fa5ec2a030a8cf3b77337ac41fceb580e845eed655a48b547238c2e8137c92f8c27e585caad3106eee3814a:d5008486726cce330a29dd7e4d7474d735798201afd1206feb869a112e5b43523c06976761be3cf9b2716378273c94f93572a7d2b8982634e0755c632b449008522a5e5eff5b5e98fad6878a9d72df6eb318622610a1e1a48183f5590ecef5a6df671b28be91c88cdf7ae2881147fe6c37c28b43f64cf981c455c59e765ce94e1b6491631deaeef6d1da9ebca88643c77f83eae2cfdd2d97f604fe45081d1be5c4ae2d875996b8b6fecd707d3fa219a93ba0488e55247b405e330cfb97d31a1361c9b2084bdb13fb0c058925db8c3c649c9a3e937b533cc6310fa3b16126fb3cc9bb2b35c5c8300015488a30fadca3c8871fa70dfdc7055bf8e631f20c9b2528311e324a7c4edd5462079f3441c9ecf55fa999e731372344fdc0d413e417aaa001a1b2d3d9bc000fec1b02bd7a88a812d9d8a66f9464764c070c93041eefb17ce74eff6d4aff75f0cbf6a789a9ecde74abe33130fca0da853aa7c3313ada3f0ae2f595c6796a93685e729dd18a669d6381825ab3f36a391e7525b2a807a52fa5ec2a030a8cf3b77337ac41fceb580e845eed655a48b547238c2e8137c92f8c27e585caad3106eee3814a: +0bc6af64de5709d3dbc28f7ef6d3fe28b6de529f08f5857ccb910695de454f56fb491fc900237bdc7e9a119f27150cd911935cd3628749ff40ef41f3955bc8ac:fb491fc900237bdc7e9a119f27150cd911935cd3628749ff40ef41f3955bc8ac:ac7886e4f4172a22c95e8eea37437b375d72accedcee6cc6e816763301a2d8ef4d6f31a2c1d635818b7026a395ce0dafd71c5180893af76b7ea056c972d680eca01dcbdbae6b26f1c5f33fc988b824fbbe00cacc316469a3bae07aa7c8885af7f65f42e75cef94dbb9aab4825143c85070e7716b7612f64ef0b0166011d23eb5654aa098b02d8d71e57c8fa17bff2fe97dc8193177eadc09fb192d80aa92afa98720d4614817ff3c39d3acce18906fa3de09618931d0d7a60c4429cbfa20cf165c947929ac293ae6c06e7e8f25f1264291e3e1c98f5d93e6ecc2389bc60dbbf4a621b132c552a99c95d26d8d1af61138b570a0de4b497ebe8051c7273a98e6e7876d0b327503af3cb2cc4091ce1925cb2f2957f4ec56ee90f8a09dd57d6e83067a356a4cfe65b1b7a4465da2ab133b0efb5e7d4dbb811bcbbde712afbf0f7dd3f326222284b8c74eac7ad6257fa8c632b7da2559a6266e91e0ef90dbb0aa968f75376b693fcaa5da342221:dbc7134d1cd6b0813b53352714b6df939498e91cf37c324337d9c088a1b998347d26185b430900412929e4f63e910379fc42e355a4e98f6fee27dafad1957206ac7886e4f4172a22c95e8eea37437b375d72accedcee6cc6e816763301a2d8ef4d6f31a2c1d635818b7026a395ce0dafd71c5180893af76b7ea056c972d680eca01dcbdbae6b26f1c5f33fc988b824fbbe00cacc316469a3bae07aa7c8885af7f65f42e75cef94dbb9aab4825143c85070e7716b7612f64ef0b0166011d23eb5654aa098b02d8d71e57c8fa17bff2fe97dc8193177eadc09fb192d80aa92afa98720d4614817ff3c39d3acce18906fa3de09618931d0d7a60c4429cbfa20cf165c947929ac293ae6c06e7e8f25f1264291e3e1c98f5d93e6ecc2389bc60dbbf4a621b132c552a99c95d26d8d1af61138b570a0de4b497ebe8051c7273a98e6e7876d0b327503af3cb2cc4091ce1925cb2f2957f4ec56ee90f8a09dd57d6e83067a356a4cfe65b1b7a4465da2ab133b0efb5e7d4dbb811bcbbde712afbf0f7dd3f326222284b8c74eac7ad6257fa8c632b7da2559a6266e91e0ef90dbb0aa968f75376b693fcaa5da342221: +2f5e83bd5b412e71ae3e9084cd369efcc79bf6037c4b174dfd6a11fb0f5da218a22a6da29a5ef6240c49d8896e3a0f1a4281a266c77d383ee6f9d25ffacbb872:a22a6da29a5ef6240c49d8896e3a0f1a4281a266c77d383ee6f9d25ffacbb872:b766273f060ef3b2ae3340454a391b426bc2e97264f8674553eb00dd6ecfdd59b611d8d662929fec710d0e462020e12cdbf9c1ec8858e85671acf8b7b14424ce92079d7d801e2ad9acac036bc8d2dfaa72aa839bff30c0aa7e414a882c00b645ff9d31bcf5a54382def4d0142efa4f06e823257ff132ee968cdc6738c53f53b84c8df76e9f78dd5056cf3d4d5a80a8f84e3edec48520f2cb4583e708539355ef7aa86fb5a0e87a94dcf14f30a2cca568f139d9ce59eaf459a5c5916cc8f20b26aaf6c7c029379aedb05a07fe585ccac60307c1f58ca9f859157d06d06baa394aace79d51b8cb38cfa2598141e245624e5ab9b9d68731173348905315bf1a5ad61d1e8adaeb810e4e8a86d7c13537b0be860ab2ed35b73399b8808aa91d750f77943f8a8b7e89fdb50728aa3dbbd8a41a6e00756f438c9b9e9d55872df5a9068add8a972b7e43edad9ced2237ca1367be4b7cdb66a54ea12eef129471158610eaf28f99f7f686557dcdf644ea:9f80922bc8db32d0cc43f9936affebe7b2bc35a5d82277cd187b5d50dc7fc4c4832fffa34e9543806b485c04548e7c75429425e14d55d91fc1052efd8667430bb766273f060ef3b2ae3340454a391b426bc2e97264f8674553eb00dd6ecfdd59b611d8d662929fec710d0e462020e12cdbf9c1ec8858e85671acf8b7b14424ce92079d7d801e2ad9acac036bc8d2dfaa72aa839bff30c0aa7e414a882c00b645ff9d31bcf5a54382def4d0142efa4f06e823257ff132ee968cdc6738c53f53b84c8df76e9f78dd5056cf3d4d5a80a8f84e3edec48520f2cb4583e708539355ef7aa86fb5a0e87a94dcf14f30a2cca568f139d9ce59eaf459a5c5916cc8f20b26aaf6c7c029379aedb05a07fe585ccac60307c1f58ca9f859157d06d06baa394aace79d51b8cb38cfa2598141e245624e5ab9b9d68731173348905315bf1a5ad61d1e8adaeb810e4e8a86d7c13537b0be860ab2ed35b73399b8808aa91d750f77943f8a8b7e89fdb50728aa3dbbd8a41a6e00756f438c9b9e9d55872df5a9068add8a972b7e43edad9ced2237ca1367be4b7cdb66a54ea12eef129471158610eaf28f99f7f686557dcdf644ea: +722a2da50e42c11a61c9afac7be1a2fed2267d650f8f7d8e5bc706b807c1b91dfd0b964562f823721e649c3fedb432a76f91e0aead7c61d35f95ed7726d78589:fd0b964562f823721e649c3fedb432a76f91e0aead7c61d35f95ed7726d78589:173e8bb885e1f9081404acac999041d2ecfcb73f945e0db36e631d7cd1ab999eb717f34bf07874bf3d34e2530eb6085f4a9f88ae1b0f7d80f221456a8e9a8890b91a50192deaaacc0a1a615a87841e2c5a9e057957af6e48e78cc86198e32e7aa24dcf6cffa329bc72606d65b11682c8ba736cce22a05785df1146331e41609cf9ca711cf464958297138b58a9073f3bbf06ad8a85d135de66652104d88b49d27ad41e59bcc44c7fab68f53f0502e293ffcabaaf755927dfdffbfde3b35c080b5de4c8b785f4da64ef357bc0d1466a6a96560c3c4f3e3c0b563a003f5f95f237171bce1a001771a04ede7cdd9b8ca770fd36ef90e9fe0000a8d7685fd153cc7282de95920a8f8f0898d00bf0c6c933fe5bb9653ff146c4e2acd1a2e0c23c1244844dacf8652716302c2032f9c114679ed26b3ee3ab4a7b18bc4e3071f0977db57cd0ac68c0727a09b4f125fb64af2850b26c8a484263334e2da902d744737044e79ab1cf5b2f93a022b63d40cd:c2695a57172aaa31bd0890f231ca8eeec0287a87172669a899ad0891cea4c47579b50420e791cdec8c182c8a0e8dde21b2480b0cfd8111e28e5603347a352d04173e8bb885e1f9081404acac999041d2ecfcb73f945e0db36e631d7cd1ab999eb717f34bf07874bf3d34e2530eb6085f4a9f88ae1b0f7d80f221456a8e9a8890b91a50192deaaacc0a1a615a87841e2c5a9e057957af6e48e78cc86198e32e7aa24dcf6cffa329bc72606d65b11682c8ba736cce22a05785df1146331e41609cf9ca711cf464958297138b58a9073f3bbf06ad8a85d135de66652104d88b49d27ad41e59bcc44c7fab68f53f0502e293ffcabaaf755927dfdffbfde3b35c080b5de4c8b785f4da64ef357bc0d1466a6a96560c3c4f3e3c0b563a003f5f95f237171bce1a001771a04ede7cdd9b8ca770fd36ef90e9fe0000a8d7685fd153cc7282de95920a8f8f0898d00bf0c6c933fe5bb9653ff146c4e2acd1a2e0c23c1244844dacf8652716302c2032f9c114679ed26b3ee3ab4a7b18bc4e3071f0977db57cd0ac68c0727a09b4f125fb64af2850b26c8a484263334e2da902d744737044e79ab1cf5b2f93a022b63d40cd: +5fe9c3960ed5bd374cc94d42357e6a24dc7e3060788f726365defacf13cd12da0ce7b155c8b20ebdaacdc2aa23627e34b1f9ace980650a2530c7607d04814eb4:0ce7b155c8b20ebdaacdc2aa23627e34b1f9ace980650a2530c7607d04814eb4:c9490d83d9c3a9370f06c91af001685a02fe49b5ca667733fff189eee853ec1667a6c1b6c787e9244812d2d532866ab74dfc870d6f14033b6bcd39852a3900f8f08cd95a74cb8cbe02b8b8b51e993a06adfebd7fc9854ae5d29f4df9642871d0c5e470d903cfbcbd5adb3275628f28a80bf8c0f0376687dae673bf7a8547e80d4a9855ae2572fc2b205dc8a198016ddc9b50995f5b39f368f540504a551803d6dd5f874828e5541ded052894d9e2dc5e6aa351087e790c0dd5d9c4decb217e4db81c98a184b264e6daeac0f11e074cae2bfc899f54b419c65dcc22664a915fbfffac35cee0f286eb7b144933db933e16c4bcb650d537722489de236373fd8d65fc86118b6def37ca4608bc6ce927b65436ffda7f02bfbf88b045ae7d2c2b45a0b30c8f2a04df953221088c555fe9a5df260982a3d64df194ee952fa9a98c31b96493db6180d13d67c36716f95f8c0bd7a039ad990667ca34a83ac1a18c37dd7c7736aa6b9b6fc2b1ac0ce119ef77:379f9c54c413af0d192e9bc736b29da9d521e7ba7841d309f9bcc1e742ec4308fe9f7ba51e0b22aed487cb4aa3913b9bebfb3aacd38f4039f9bbbebe1ad80002c9490d83d9c3a9370f06c91af001685a02fe49b5ca667733fff189eee853ec1667a6c1b6c787e9244812d2d532866ab74dfc870d6f14033b6bcd39852a3900f8f08cd95a74cb8cbe02b8b8b51e993a06adfebd7fc9854ae5d29f4df9642871d0c5e470d903cfbcbd5adb3275628f28a80bf8c0f0376687dae673bf7a8547e80d4a9855ae2572fc2b205dc8a198016ddc9b50995f5b39f368f540504a551803d6dd5f874828e5541ded052894d9e2dc5e6aa351087e790c0dd5d9c4decb217e4db81c98a184b264e6daeac0f11e074cae2bfc899f54b419c65dcc22664a915fbfffac35cee0f286eb7b144933db933e16c4bcb650d537722489de236373fd8d65fc86118b6def37ca4608bc6ce927b65436ffda7f02bfbf88b045ae7d2c2b45a0b30c8f2a04df953221088c555fe9a5df260982a3d64df194ee952fa9a98c31b96493db6180d13d67c36716f95f8c0bd7a039ad990667ca34a83ac1a18c37dd7c7736aa6b9b6fc2b1ac0ce119ef77: +ec2fa541ac14b414149c3825eaa7001b795aa1957d4040dda92573904afa7ee471b363b2408404d7beecdef1e1f511bb6084658b532f7ea63d4e3f5f01c61d31:71b363b2408404d7beecdef1e1f511bb6084658b532f7ea63d4e3f5f01c61d31:2749fc7c4a729e0e0ad71b5b74eb9f9c534ebd02ffc9df4374d813bdd1ae4eb87f1350d5fdc563934515771763e6c33b50e64e0cd114573031d2186b6eca4fc802cddc7cc51d92a61345a17f6ac38cc74d84707a5156be9202dee3444652e79bae7f0d31bd17567961f65dd01a8e4bee38331938ce4b2b550691b99a4bc3c072d186df4b3344a5c8fbfbb9fd2f355f6107e410c3d0c798b68d3fb9c6f7ab5fe27e70871e86767698fe35b77ead4e435a9402cc9ed6a2657b059be0a21003c048bbf5e0ebd93cbb2e71e923cf5c728d1758cd817ad74b454a887126d653b95a7f25e5293b768c9fc5a9c35a2372e3741bc90fd66301427b10824bb4b1e9110bfba84c21a40eb8fed4497e91dc3ffd0438c514c0a8cb4cac6ad0256bf11d5aa7a9c7c00b669b015b0bf81425a21413e2ffb6edc0bd78e385c44fd74558e511c2c25fee1fec18d3990b8690300fa711e93d9854668f0187065e76e7113ae763c30ddd86720b5546a6c3c6f1c43bc67b14:84d18d56f964e3776759bba92c510c2b6d574555c3cddade212da90374554991e7d77e278d63e34693e1958078cc3685f8c41c1f5342e351899638ef612114012749fc7c4a729e0e0ad71b5b74eb9f9c534ebd02ffc9df4374d813bdd1ae4eb87f1350d5fdc563934515771763e6c33b50e64e0cd114573031d2186b6eca4fc802cddc7cc51d92a61345a17f6ac38cc74d84707a5156be9202dee3444652e79bae7f0d31bd17567961f65dd01a8e4bee38331938ce4b2b550691b99a4bc3c072d186df4b3344a5c8fbfbb9fd2f355f6107e410c3d0c798b68d3fb9c6f7ab5fe27e70871e86767698fe35b77ead4e435a9402cc9ed6a2657b059be0a21003c048bbf5e0ebd93cbb2e71e923cf5c728d1758cd817ad74b454a887126d653b95a7f25e5293b768c9fc5a9c35a2372e3741bc90fd66301427b10824bb4b1e9110bfba84c21a40eb8fed4497e91dc3ffd0438c514c0a8cb4cac6ad0256bf11d5aa7a9c7c00b669b015b0bf81425a21413e2ffb6edc0bd78e385c44fd74558e511c2c25fee1fec18d3990b8690300fa711e93d9854668f0187065e76e7113ae763c30ddd86720b5546a6c3c6f1c43bc67b14: +6132692a5ef27bf476b1e991e6c431a8c764f1aebd470282db3321bb7cb09c207a2d166184f9e5f73bea454486b041ceb5fc2314a7bd59cb718e79f0ec989d84:7a2d166184f9e5f73bea454486b041ceb5fc2314a7bd59cb718e79f0ec989d84:a9c0861665d8c2de06f9301da70afb27b3024b744c6b38b24259294c97b1d1cb4f0dcf7575a8ed454e2f0980f50313a77363415183fe9677a9eb1e06cb6d34a467cb7b0758d6f55c564b5ba15603e202b18856d89e72a23ab07d8853ff77da7aff1caebd7959f2c710ef31f5078a9f2cdae92641a1cc5f74d0c143ec42afbaa5f378a9e10d5bf74587fa5f49c156233247dafd3929acde888dc684337e40cdc5932e7eb73ffcc90b85c0ad460416691aefbd7efd07b657c350946a0e366b37a6c8089aba5c5fe3bbca064afbe9d47fbc83914af1cb43c2b2efa98e0a43be32ba823202001def36817251b65f9b0506cef6683642a46ed612f8ca81ee97bb04d317b517343ade2b77126d1f02a87b7604c8653b6748cf5488fa6d43df809faa19e69292d38c5d397dd8e20c7af7c5334ec977f5010a0f7cb5b89479ca06db4d12627f067d6c42186a6b1f8742f36ae709ba720e3cd898116666d81b190b9b9d2a72202cb690a03f3310429a71dc048cde:eb677f3347e1a1ea929efdf62bf9105a6c8f4993033b4f6d03cb0dbf9c742b270704e383ab7c0676bdb1ad0ce9b16673083c9602ec10ae1dd98e8748b336440ba9c0861665d8c2de06f9301da70afb27b3024b744c6b38b24259294c97b1d1cb4f0dcf7575a8ed454e2f0980f50313a77363415183fe9677a9eb1e06cb6d34a467cb7b0758d6f55c564b5ba15603e202b18856d89e72a23ab07d8853ff77da7aff1caebd7959f2c710ef31f5078a9f2cdae92641a1cc5f74d0c143ec42afbaa5f378a9e10d5bf74587fa5f49c156233247dafd3929acde888dc684337e40cdc5932e7eb73ffcc90b85c0ad460416691aefbd7efd07b657c350946a0e366b37a6c8089aba5c5fe3bbca064afbe9d47fbc83914af1cb43c2b2efa98e0a43be32ba823202001def36817251b65f9b0506cef6683642a46ed612f8ca81ee97bb04d317b517343ade2b77126d1f02a87b7604c8653b6748cf5488fa6d43df809faa19e69292d38c5d397dd8e20c7af7c5334ec977f5010a0f7cb5b89479ca06db4d12627f067d6c42186a6b1f8742f36ae709ba720e3cd898116666d81b190b9b9d2a72202cb690a03f3310429a71dc048cde: +f219b2101164aa9723bde3a7346f68a35061c01f9782072580ba32df903ba891f66b920d5aa1a6085495a1480539beba01ffe60e6a6388d1b2e8eda23355810e:f66b920d5aa1a6085495a1480539beba01ffe60e6a6388d1b2e8eda23355810e:015577d3e4a0ec1ab25930106343ff35ab4f1e0a8a2d844aadbb70e5fc5348ccb679c2295c51d702aaae7f6273ce70297b26cb7a253a3db94332e86a15b4a64491232791f7a8b082ee2834af30400e804647a532e9c454d2a0a7320130ab6d4d860073a34667ac25b7e5e2747ba9f5c94594fb68377ae260369c40713b4e32f23195bf91d3d7f1a2719bf408aad8d8a347b112e84b118817cb06513344021763035272a7db728a0ccdaa949c61715d0764140b3e8c01d20ff1593c7f2d55c4e82a1c0cb1ea58442bf80a741bca91f58ab0581b498ee9fe3c92ca654148ef75313543d1aff382befe1a93b02190ce0102175158e2071d02bacad8dbe9fb940fcb610c105ad52c80feb1ec4e524f4c0ec7983e9ce696fa4fcf4bf0514b8f0432b17d5448fc426fea2b01ac7b26c2aed769927534da22576fc1bba726e9d65be01b59f60a648ace2fc3e5e275789fa637cbbd84be3d6ac24457a6292cd656c7b569a52ffea7916b8d04b4f4a75be7ac95142f:17f0127ca3bafa5f4ee959cd60f772be87a0034961517e39a0a1d0f4b9e26db1336e60c82b352c4cbacdbbd11771c3774f8cc5a1a795d6e4f4ebd51def36770b015577d3e4a0ec1ab25930106343ff35ab4f1e0a8a2d844aadbb70e5fc5348ccb679c2295c51d702aaae7f6273ce70297b26cb7a253a3db94332e86a15b4a64491232791f7a8b082ee2834af30400e804647a532e9c454d2a0a7320130ab6d4d860073a34667ac25b7e5e2747ba9f5c94594fb68377ae260369c40713b4e32f23195bf91d3d7f1a2719bf408aad8d8a347b112e84b118817cb06513344021763035272a7db728a0ccdaa949c61715d0764140b3e8c01d20ff1593c7f2d55c4e82a1c0cb1ea58442bf80a741bca91f58ab0581b498ee9fe3c92ca654148ef75313543d1aff382befe1a93b02190ce0102175158e2071d02bacad8dbe9fb940fcb610c105ad52c80feb1ec4e524f4c0ec7983e9ce696fa4fcf4bf0514b8f0432b17d5448fc426fea2b01ac7b26c2aed769927534da22576fc1bba726e9d65be01b59f60a648ace2fc3e5e275789fa637cbbd84be3d6ac24457a6292cd656c7b569a52ffea7916b8d04b4f4a75be7ac95142f: +fc180035aec0f5ede7bda93bf77ade7a81ed06de07ee2e3aa8576be81608610a4f215e948cae243ee3143b80282ad792c780d2a6b75060ca1d290ca1a8e3151f:4f215e948cae243ee3143b80282ad792c780d2a6b75060ca1d290ca1a8e3151f:b5e8b01625664b222339e0f05f93a990ba48b56ae65439a17520932df011721e284dbe36f98631c066510098a68d7b692a3863e99d58db76ca5667c8043cb10bd7abbaf506529fbb23a5166be038affdb9a234c4f4fcf43bddd6b8d2ce772dd653ed115c095e232b269dd4888d2368cb1c66be29dd383fca67f66765b296564e37555f0c0e484504c591f006ea8533a12583ad2e48318ff6f324ecaf804b1bae04aa896743e67ef61ca383d58e42acfc6410de30776e3ba262373b9e1441943955101a4e768231ad9c6529eff6118dde5df02f94b8d6df2d99f27863b517243a579e7aaff311ea3a0282e47ca876fabc2280fce7adc984dd0b30885b1650f1471dfcb0522d49fec7d042f32a93bc368f076006ea01ec1c7412bf66f62dc88de2c0b74701a5614e855e9fa728fb1f1171385f96afbde70dea02e9aa94dc21848c26302b50ae91f9693a1864e4e095ae03cdc22ad28a0eb7db596779246712fab5f5da327efec3e79612de0a6ccaa536759b8e:a43a71c3a19c35660dae6f31a254b8c0ea3593fc8fca74d13640012b9e9473d4afe070db01e7fb399bf4ca6070e062180011285a67dd6858b761e46c6bd32004b5e8b01625664b222339e0f05f93a990ba48b56ae65439a17520932df011721e284dbe36f98631c066510098a68d7b692a3863e99d58db76ca5667c8043cb10bd7abbaf506529fbb23a5166be038affdb9a234c4f4fcf43bddd6b8d2ce772dd653ed115c095e232b269dd4888d2368cb1c66be29dd383fca67f66765b296564e37555f0c0e484504c591f006ea8533a12583ad2e48318ff6f324ecaf804b1bae04aa896743e67ef61ca383d58e42acfc6410de30776e3ba262373b9e1441943955101a4e768231ad9c6529eff6118dde5df02f94b8d6df2d99f27863b517243a579e7aaff311ea3a0282e47ca876fabc2280fce7adc984dd0b30885b1650f1471dfcb0522d49fec7d042f32a93bc368f076006ea01ec1c7412bf66f62dc88de2c0b74701a5614e855e9fa728fb1f1171385f96afbde70dea02e9aa94dc21848c26302b50ae91f9693a1864e4e095ae03cdc22ad28a0eb7db596779246712fab5f5da327efec3e79612de0a6ccaa536759b8e: +a2836a65427912122d25dcdfc99d7046fe9b53d5c1bb23617f11890e94ca93ed8c12bda214c8abb2286acffbf8112425040aab9f4d8bb7870b98da0159e882f1:8c12bda214c8abb2286acffbf8112425040aab9f4d8bb7870b98da0159e882f1:813d6061c56eae0ff53041c0244aa5e29e13ec0f3fb428d4beb8a99e04bca8c41bddb0db945f487efe38f2fc14a628fafa2462f860e4e34250eb4e93f139ab1b74a2614519e41ee2403be427930ab8bc82ec89ceafb60905bd4ddbbd13bdb19654314fc92373140b962e2258e038d71b9ec66b84ef8319e03551cb707e747f6c40ad476fbefdce71f3a7b67a1af1869bc6440686e7e0855e4f369d1d88b8099fba54714678627bba1aff41e7707bc97eddf890b0c08dce3e9800d24c6f61092ce28d481b5dea5c096c55d72f8946009131fb968e2bc8a054d825adab76740dcf0d758c8bf54ff38659e71b32bfe2e615aaabb0f5293085649cf60b9847bc62011ce3878af628984a5840a4ad5dae3702db367da0f8a165fed0517eb5c442b0145330241b97eeca733ba6688b9c129a61cd1236aff0e27bcf98c28b0fbeea55a3d7c7193d644b2749f986bd46af8938e8faaeafbd9cec3612ab005bd7c3eeafe9a31279ca6102560666ba16136ff1452f850adb:e6a9a6b436559a4320c45c0c2c4a2aedecb90d416d52c82680ac7330d062aebef3e9ac9f2c5ffa455c9be113013a2b282e5600fd306435ada83b1e48ba2a3605813d6061c56eae0ff53041c0244aa5e29e13ec0f3fb428d4beb8a99e04bca8c41bddb0db945f487efe38f2fc14a628fafa2462f860e4e34250eb4e93f139ab1b74a2614519e41ee2403be427930ab8bc82ec89ceafb60905bd4ddbbd13bdb19654314fc92373140b962e2258e038d71b9ec66b84ef8319e03551cb707e747f6c40ad476fbefdce71f3a7b67a1af1869bc6440686e7e0855e4f369d1d88b8099fba54714678627bba1aff41e7707bc97eddf890b0c08dce3e9800d24c6f61092ce28d481b5dea5c096c55d72f8946009131fb968e2bc8a054d825adab76740dcf0d758c8bf54ff38659e71b32bfe2e615aaabb0f5293085649cf60b9847bc62011ce3878af628984a5840a4ad5dae3702db367da0f8a165fed0517eb5c442b0145330241b97eeca733ba6688b9c129a61cd1236aff0e27bcf98c28b0fbeea55a3d7c7193d644b2749f986bd46af8938e8faaeafbd9cec3612ab005bd7c3eeafe9a31279ca6102560666ba16136ff1452f850adb: +f051af426d0c3282fafc8bf912ade1c24211a95ad200e1eef549320e1cb1a252fa87955e0ea13dde49d83dc22e63a2bdf1076725c2cc7f93c76511f28e7944f2:fa87955e0ea13dde49d83dc22e63a2bdf1076725c2cc7f93c76511f28e7944f2:b48d9f84762b3bcc66e96d76a616fa8fe8e01695251f47cfc1b7b17d60dc9f90d576ef64ee7d388504e2c9079638165a889696471c989a876f8f13b63b58d531fea4dd1229fc631668a047bfae2da281feae1b6de3ebe280abe0a82ee00fbfdc22ce2d10e06a0492ff1404dfc094c40b203bf55721dd787ed4e91d5517aaf58d3bdd35d44a65ae6ba75619b339b650518cefcc17493de27a3b5d41788f87edbde72610f181bf06e208e0eb7cdfe881d91a2d6cc77aa19c0fcf330fedb44675d800eb8cff9505d8887544a503cbe373c4847b19e8f3995726efd6649858595c57ccaf0cbc9eb25de83ba046bc9f1838ac7b8953dd81b81ac0f68d0e9338cb55402552afb6bc16949351b926d151a82efc695e8d7da0dd55099366789718ccbf36030bd2c3c109399be26cdb8b9e2a155f3b2cb1bfa71ab69a23625a4ac118fe91cb2c19788cf52a71d730d576b421d96982a51a2991daec440cda7e6cc3282b8312714278b819bfe2387eb96aa91d40173034f428:b8f713578a64466719aceb432fce302a87cf066bf3e102a350616921a840964bfc7e685d8fd17455ac3eb4861edcb8979d35e3a4bd82a078cd707721d733400eb48d9f84762b3bcc66e96d76a616fa8fe8e01695251f47cfc1b7b17d60dc9f90d576ef64ee7d388504e2c9079638165a889696471c989a876f8f13b63b58d531fea4dd1229fc631668a047bfae2da281feae1b6de3ebe280abe0a82ee00fbfdc22ce2d10e06a0492ff1404dfc094c40b203bf55721dd787ed4e91d5517aaf58d3bdd35d44a65ae6ba75619b339b650518cefcc17493de27a3b5d41788f87edbde72610f181bf06e208e0eb7cdfe881d91a2d6cc77aa19c0fcf330fedb44675d800eb8cff9505d8887544a503cbe373c4847b19e8f3995726efd6649858595c57ccaf0cbc9eb25de83ba046bc9f1838ac7b8953dd81b81ac0f68d0e9338cb55402552afb6bc16949351b926d151a82efc695e8d7da0dd55099366789718ccbf36030bd2c3c109399be26cdb8b9e2a155f3b2cb1bfa71ab69a23625a4ac118fe91cb2c19788cf52a71d730d576b421d96982a51a2991daec440cda7e6cc3282b8312714278b819bfe2387eb96aa91d40173034f428: +a103e92672c65f81ea5da1fff1a4038788479e941d503a756f4a755201a57c1dee63a5b69641217acbaf3339da829ec071b9931e5987153514d30140837a7af4:ee63a5b69641217acbaf3339da829ec071b9931e5987153514d30140837a7af4:b1984e9eec085d524c1eb3b95c89c84ae085be5dc65c326e19025e1210a1d50edbbba5d1370cf15d68d687eb113233e0fba50f9433c7d358773950c67931db8296bbcbecec888e87e71a2f7579fad2fa162b85fb97473c456b9a5ce2956676969c7bf4c45679085b62f2c224fc7f458794273f6d12c5f3e0d06951824d1cca3e2f904559ed28e2868b366d79d94dc98667b9b5924268f3e39b1291e5abe4a758f77019dacbb22bd8196e0a83a5677658836e96ca5635055a1e63d65d036a68d87ac2fd283fdda390319909c5cc7680368848873d597f298e0c6172308030ffd452bb1363617b316ed7cd949a165dc8abb53f991aef3f3e9502c5dfe4756b7c6bfdfe89f5e00febdd6afb0402818f11cf8d1d5864fe9da1b86e39aa935831506cf2400ea7ed75bd9533b23e202fe875d7d9638c89d11cb2d6e6021ae6bd27c7754810d35cd3a61494f27b16fc794e2cd2f0d3453ada933865db78c579571f8fc5c5c6be8eaffce6a852e5b3b1c524c49313d427abcb:2aa2035c2ce5b5e6ae161e168f3ad0d6592bcf2c4a049d3ed342fceb56be9c7cb372027573ae0178e8878ebefca7b030327b8aad41857de58cb78e1a00cbac05b1984e9eec085d524c1eb3b95c89c84ae085be5dc65c326e19025e1210a1d50edbbba5d1370cf15d68d687eb113233e0fba50f9433c7d358773950c67931db8296bbcbecec888e87e71a2f7579fad2fa162b85fb97473c456b9a5ce2956676969c7bf4c45679085b62f2c224fc7f458794273f6d12c5f3e0d06951824d1cca3e2f904559ed28e2868b366d79d94dc98667b9b5924268f3e39b1291e5abe4a758f77019dacbb22bd8196e0a83a5677658836e96ca5635055a1e63d65d036a68d87ac2fd283fdda390319909c5cc7680368848873d597f298e0c6172308030ffd452bb1363617b316ed7cd949a165dc8abb53f991aef3f3e9502c5dfe4756b7c6bfdfe89f5e00febdd6afb0402818f11cf8d1d5864fe9da1b86e39aa935831506cf2400ea7ed75bd9533b23e202fe875d7d9638c89d11cb2d6e6021ae6bd27c7754810d35cd3a61494f27b16fc794e2cd2f0d3453ada933865db78c579571f8fc5c5c6be8eaffce6a852e5b3b1c524c49313d427abcb: +d47c1b4b9e50cbb71fd07d096d91d87213d44b024373044761c4822f9d9df880f4e1cb86c8ca2cfee43e58594a8778436d3ea519704e00c1bbe48bbb1c9454f8:f4e1cb86c8ca2cfee43e58594a8778436d3ea519704e00c1bbe48bbb1c9454f8:88d7009d51de3d337eef0f215ea66ab830ec5a9e6823761c3b92ad93ea341db92ece67f4ef4ceb84194ae6926c3d014b2d59781f02e0b32f9a611222cb9a5850c6957cb8079ae64e0832a1f05e5d1a3c572f9d08f1437f76bb3b83b52967c3d48c3576848891c9658d4959eb80656d26cdba0810037c8a18318ff122f8aa8985c773cb317efa2f557f1c3896bcb162df5d87681bb787e7813aa2dea3b0c564d646a92861f444ca1407efbac3d12432cbb70a1d0eaffb11741d3718fedee2b83036189a6fc45a52f74fa487c18fd264a7945f6c9e44b011f5d86613f1939b19f4f4fdf53234057be3f005ad64eebf3c8ffb58cb40956c4336df01d4424b706a0e561d601708d12485e21bcb6d799d8d1d044b400064ec0944501406e70253947006cabbdb2dd6bd8cee4497653d9113a44d4de9b68d4c526fca0b9b0c18fe50fb917fdd9a914fb816108a73a6b3fff9e654e69c9cfe02b05c6c1b9d15c4e65cf31018b8100d784633ee1888eee3572aafa6f189ea22d0:627e7ca7e34ed6331d62b9541c1ea9a9292be7b0a65d805e266b5122272a82db7d765acc7e2a290d685804922f91ed04a3c382c03ff21a1768f584413c4e5f0088d7009d51de3d337eef0f215ea66ab830ec5a9e6823761c3b92ad93ea341db92ece67f4ef4ceb84194ae6926c3d014b2d59781f02e0b32f9a611222cb9a5850c6957cb8079ae64e0832a1f05e5d1a3c572f9d08f1437f76bb3b83b52967c3d48c3576848891c9658d4959eb80656d26cdba0810037c8a18318ff122f8aa8985c773cb317efa2f557f1c3896bcb162df5d87681bb787e7813aa2dea3b0c564d646a92861f444ca1407efbac3d12432cbb70a1d0eaffb11741d3718fedee2b83036189a6fc45a52f74fa487c18fd264a7945f6c9e44b011f5d86613f1939b19f4f4fdf53234057be3f005ad64eebf3c8ffb58cb40956c4336df01d4424b706a0e561d601708d12485e21bcb6d799d8d1d044b400064ec0944501406e70253947006cabbdb2dd6bd8cee4497653d9113a44d4de9b68d4c526fca0b9b0c18fe50fb917fdd9a914fb816108a73a6b3fff9e654e69c9cfe02b05c6c1b9d15c4e65cf31018b8100d784633ee1888eee3572aafa6f189ea22d0: +fc0c32c5eb6c71ea08dc2b300cbcef18fdde3ea20f68f21733237b4ddaab900e47c37d8a080857eb8777a6c0a9a5c927303faf5c320953b5de48e462e12d0062:47c37d8a080857eb8777a6c0a9a5c927303faf5c320953b5de48e462e12d0062:a7b1e2db6bdd96b3d51475603537a76b42b04d7ebd24fe515a887658e4a352e22109335639a59e2534811f4753b70209d0e4698e9d926088826c14689681ea00fa3a2fcaa0047ced3ef287e6172502b215e56497614d86b4cb26bcd77a2e172509360ee58893d01c0d0fb4d4abfe4dbd8d2a2f54190fa2f731c1ceac6829c3ddc9bfb2ffd70c57ba0c2b22d2326fbfe7390db8809f73547ff47b86c36f2bf7454e678c4f1c0fa870bd0e30bbf3278ec8d0c5e9b64aff0af64babc19b70f4cf9a41cb8f95d3cde24f456ba3571c8f021d38e591dec05cb5d1ca7b48f9da4bd734b069a9fd106500c1f408ab7fe8e4a6e6f3ed64da0ed24b01e33df8475f95fa9ed71d04dd30b3cd823755a3401bf5afae10ee7e18ec6fe637c3793fd434b48d7145130447e00299101052558b506554ec9c399f62941c3f414cbc352caa345b930adecfaddac91ee53d1451a65e06201026325de07c931f69bba868a7c87ee23c604ec6794332917dfe2c5b69669b659706917f71eddf96:6887c6e2b98a82af5ee3dfa7ca2cb25d9c10745620a82956acba85cb57c8ec24279fa42f092359a1b6bbeafba050f14b6288209e6ef7bc1e0a2b872c1138f305a7b1e2db6bdd96b3d51475603537a76b42b04d7ebd24fe515a887658e4a352e22109335639a59e2534811f4753b70209d0e4698e9d926088826c14689681ea00fa3a2fcaa0047ced3ef287e6172502b215e56497614d86b4cb26bcd77a2e172509360ee58893d01c0d0fb4d4abfe4dbd8d2a2f54190fa2f731c1ceac6829c3ddc9bfb2ffd70c57ba0c2b22d2326fbfe7390db8809f73547ff47b86c36f2bf7454e678c4f1c0fa870bd0e30bbf3278ec8d0c5e9b64aff0af64babc19b70f4cf9a41cb8f95d3cde24f456ba3571c8f021d38e591dec05cb5d1ca7b48f9da4bd734b069a9fd106500c1f408ab7fe8e4a6e6f3ed64da0ed24b01e33df8475f95fa9ed71d04dd30b3cd823755a3401bf5afae10ee7e18ec6fe637c3793fd434b48d7145130447e00299101052558b506554ec9c399f62941c3f414cbc352caa345b930adecfaddac91ee53d1451a65e06201026325de07c931f69bba868a7c87ee23c604ec6794332917dfe2c5b69669b659706917f71eddf96: +a8d73d639a23cc6a967ef31bcabb5d063e53e1eab8fcc7cab9bc3a17fde9c2f88daa9f4c8b1a44691bf44521f2f7ca45dc7fc61f6a4ce6f98faa41c2a74977d1:8daa9f4c8b1a44691bf44521f2f7ca45dc7fc61f6a4ce6f98faa41c2a74977d1:fd1fac3d53313b11acd29f5a83ac11896dab2530fa47865b2295c0d99dd67c36ed8e5fa549150c794c5549efb5c1d69114d5d607b23285b7212afaab57846a54ae67b9e880e07b6586607cecf6d4eed516a3a75511fe367d88eb871e6d71b7d6aa1367a01421b1088fc2d75e44954b73625c52da8a3a183c60be9da6050f59a453caa53520593671728d431877bfaac913a765fb6a56b75290b2a8aaac34afb9217ba1b0d5850ba0fdabf80969def0feee794ceb60614e3368e63ef20e4c32d341ec9b0328ea9fe139207ed7a626ff08943b415233db7cfcc845c9b63121d4ed52ec3748ab6a1f36b2103c7dc7e9303acea4ba8af7a3e07184fb491e891ede84f0dc41cadc3973028e879acd2031afc29a16092868e2c7f539fc1b792edab195a25ab9830661346b39ef53915de4af52c421eaf172e9da76a08c283a52df907f705d7e8599c5baae0c2af380c1bb46f93484a03f28374324b278992b50b7afa02552cafa503f034f8d866e9b720271dd68ccb685a85fffd1:c4dcef1a2453939b364b340250c3129431431d5ba3f47670ab07ce680c69bf28b678627c76a6360fc40dc109aa7dea371b825e46134f624572182acf3957e70ffd1fac3d53313b11acd29f5a83ac11896dab2530fa47865b2295c0d99dd67c36ed8e5fa549150c794c5549efb5c1d69114d5d607b23285b7212afaab57846a54ae67b9e880e07b6586607cecf6d4eed516a3a75511fe367d88eb871e6d71b7d6aa1367a01421b1088fc2d75e44954b73625c52da8a3a183c60be9da6050f59a453caa53520593671728d431877bfaac913a765fb6a56b75290b2a8aaac34afb9217ba1b0d5850ba0fdabf80969def0feee794ceb60614e3368e63ef20e4c32d341ec9b0328ea9fe139207ed7a626ff08943b415233db7cfcc845c9b63121d4ed52ec3748ab6a1f36b2103c7dc7e9303acea4ba8af7a3e07184fb491e891ede84f0dc41cadc3973028e879acd2031afc29a16092868e2c7f539fc1b792edab195a25ab9830661346b39ef53915de4af52c421eaf172e9da76a08c283a52df907f705d7e8599c5baae0c2af380c1bb46f93484a03f28374324b278992b50b7afa02552cafa503f034f8d866e9b720271dd68ccb685a85fffd1: +79c7dcb7d59a8df6b2b2ba0413059d89680995c20e916da01b8f067dc60cdeb4298743c73918bd556b28f8d4824a09b814752a7aeae7ee04875c53f4d6b108d9:298743c73918bd556b28f8d4824a09b814752a7aeae7ee04875c53f4d6b108d9:5fe202f5b33b7788810d2508a13b3114d69b8596e6eacda05a04a2eb597fa3279c208b5a5b65daacb699f144e1d660e78e139b578331abec5c3c35334454f03e832c8d6e2984df5d450ecb5d33582a78808a9c78f26ebcd1244ef52e3fa6dca115c1f0cb56e38eae0e5b39f5fd863dffd0b2fb5b958f2d739db312fc667a17b031c4c9f8c5a2ad577984cc4146c437580efd2152173fe0d5782cc2ae9831a8d9a04177256018ff7631e0b0d8a99cb28f008b320421e27a74c31359188663456d85e098c1ebd281701097b6ae5a871e5ccc02058a501416cb91c12cef5be6f1914370e563f1a1b2aa41f4b8ee84cd32a1d509e529787d14a445438d807ecd620e2fa26de0da6426864784d4a28f54103e609283b99ee9b2b699c980bbb7882c3ea68ddc90802ac232f2c8e84291987bf3c5240921b59cfa214969317673d0be7f34b1ca0e15ea73c7175401ce550be106b49e62f8db68695e740e0f3a3556a19f3c8e6b91ac1cc23e863fcd0f0d9eb7047aa631e0d2eb9bcc6b:7b7cbe44c771e4371bae13b0722babcc1064155732962f407cba2acd35381d42210bece822f4681121fd4dab745a1f3077922fba1a78045b712902baccac660e5fe202f5b33b7788810d2508a13b3114d69b8596e6eacda05a04a2eb597fa3279c208b5a5b65daacb699f144e1d660e78e139b578331abec5c3c35334454f03e832c8d6e2984df5d450ecb5d33582a78808a9c78f26ebcd1244ef52e3fa6dca115c1f0cb56e38eae0e5b39f5fd863dffd0b2fb5b958f2d739db312fc667a17b031c4c9f8c5a2ad577984cc4146c437580efd2152173fe0d5782cc2ae9831a8d9a04177256018ff7631e0b0d8a99cb28f008b320421e27a74c31359188663456d85e098c1ebd281701097b6ae5a871e5ccc02058a501416cb91c12cef5be6f1914370e563f1a1b2aa41f4b8ee84cd32a1d509e529787d14a445438d807ecd620e2fa26de0da6426864784d4a28f54103e609283b99ee9b2b699c980bbb7882c3ea68ddc90802ac232f2c8e84291987bf3c5240921b59cfa214969317673d0be7f34b1ca0e15ea73c7175401ce550be106b49e62f8db68695e740e0f3a3556a19f3c8e6b91ac1cc23e863fcd0f0d9eb7047aa631e0d2eb9bcc6b: +b9ced0412593fefed95e94ac965e5b23ff9d4b0e797db02bf497994d3b793e60c1629a723189959337f5535201e5d395ba0a03ea8c17660d0f8b6f6e6404bb12:c1629a723189959337f5535201e5d395ba0a03ea8c17660d0f8b6f6e6404bb12:555bb39c1899d57cabe428064c2d925f5fc4cf7059b95fb89a8e9e3a7e426c6c922d9e4d76984ea2383cabb4f2befd89c1f20eaa8a00dbe787cfa70ae2ae6aa90331cbbe580fa5a02184ed05e6c8e89d576af28aeeaf7c4e2500f358a00971a0a75920e854849bf332142975404f598c32e96982043d992bcd1a4fe819bb5634ad03467afc4ce05073f88ba1ba4ae8653a04665cf3f71690fe13343885bc5ebc0e5e62d882f43b7c68900ac9438bf4a81ce90169ec129ee63e2c675a1a5a67e27cc798c48cc23f51078f463b3b7cc14e3bcfd2e9b82c75240934cbdc50c4308f282f193122995606f40135100a291c55afdf8934eb8b61d81421674124dec3b88f9a73110a9e616f5b826b9d343f3ac0e9d7bdf4fd8b648b40f0098b3897a3a1cd65a64570059b8bc5c6743883074c88623c1f5a88c58969e21c692aca236833d3470b3eb09815e1138e9d0650c390eee977422193b00918be8a97cc6199b451b05b5730d1d13358cf74610678f7ac7f7895cc2efc456e03873b:f1b797ded8a6942b12626848340fb719fcddafd98f33e2992d357bfdd35933c7ac561e5b2f939464338c5666854ca885c4d046eb2c54e48a1b5ed266ad34de05555bb39c1899d57cabe428064c2d925f5fc4cf7059b95fb89a8e9e3a7e426c6c922d9e4d76984ea2383cabb4f2befd89c1f20eaa8a00dbe787cfa70ae2ae6aa90331cbbe580fa5a02184ed05e6c8e89d576af28aeeaf7c4e2500f358a00971a0a75920e854849bf332142975404f598c32e96982043d992bcd1a4fe819bb5634ad03467afc4ce05073f88ba1ba4ae8653a04665cf3f71690fe13343885bc5ebc0e5e62d882f43b7c68900ac9438bf4a81ce90169ec129ee63e2c675a1a5a67e27cc798c48cc23f51078f463b3b7cc14e3bcfd2e9b82c75240934cbdc50c4308f282f193122995606f40135100a291c55afdf8934eb8b61d81421674124dec3b88f9a73110a9e616f5b826b9d343f3ac0e9d7bdf4fd8b648b40f0098b3897a3a1cd65a64570059b8bc5c6743883074c88623c1f5a88c58969e21c692aca236833d3470b3eb09815e1138e9d0650c390eee977422193b00918be8a97cc6199b451b05b5730d1d13358cf74610678f7ac7f7895cc2efc456e03873b: +81da168f02d46bb87cda845da43f8a6cba2c016878d6f49c6f061a60f155a04aaff86e98093ca4c71b1b804c5fe451cfdf868250dea30345fa4b89bb09b6a53b:aff86e98093ca4c71b1b804c5fe451cfdf868250dea30345fa4b89bb09b6a53b:6bc6726a34a64aae76ab08c92b179e54ff5d2e65eb2c6c659ae8703cc245cbc2cf45a12b22c468ae61fd9a6627ad0626c9b1e5af412cb483eaee1db11b29f0a510c13e38020e09ae0eee762537a3e9d1a0c7b033d097fdc1f4f82629a9de9ef38da1cf96a940357d5f2e0e7e8dbc29db728a1e6aad876e5e053113d06420272b87cf0c40dfe03a544de96c7aea13ba0029b57b48d99dcc6a650492d78c4cdd1b28e1a115a7e3e7a7cb21333d4ff80858dfb67782c16354b8716596560d7d8e389eb15a052a0bf5d16eb54fb3e4973ad4984e72a187f5347d5b262c32b1647e42b6a53837096cc78c2a05ce1c6e12493a03f1a667584cb97f4fcd57ee944c65b7eed25f7ae0f3f6cede173fdfacf5af1db143730d18096664914ba4cfc6966f392022781c66a9417ca2680b51f63e4fba424ecfdbc6a2f01787d0e7484f8a8ab390aeaa6d1f7ed325d82feaa1692a4984fae43da87329b045da8f0a4f56b695aa935de152ce0385153720979a2b7006d405fcb0fba09e23b85fd19b:4aaca947e3f22cc8b8588ee030ace8f6b5f5711c2974f20cc18c3b655b07a5bc1366b59a1708032d12cae01ab794f8cbcc1a330874a75035db1d69422d2fc00c6bc6726a34a64aae76ab08c92b179e54ff5d2e65eb2c6c659ae8703cc245cbc2cf45a12b22c468ae61fd9a6627ad0626c9b1e5af412cb483eaee1db11b29f0a510c13e38020e09ae0eee762537a3e9d1a0c7b033d097fdc1f4f82629a9de9ef38da1cf96a940357d5f2e0e7e8dbc29db728a1e6aad876e5e053113d06420272b87cf0c40dfe03a544de96c7aea13ba0029b57b48d99dcc6a650492d78c4cdd1b28e1a115a7e3e7a7cb21333d4ff80858dfb67782c16354b8716596560d7d8e389eb15a052a0bf5d16eb54fb3e4973ad4984e72a187f5347d5b262c32b1647e42b6a53837096cc78c2a05ce1c6e12493a03f1a667584cb97f4fcd57ee944c65b7eed25f7ae0f3f6cede173fdfacf5af1db143730d18096664914ba4cfc6966f392022781c66a9417ca2680b51f63e4fba424ecfdbc6a2f01787d0e7484f8a8ab390aeaa6d1f7ed325d82feaa1692a4984fae43da87329b045da8f0a4f56b695aa935de152ce0385153720979a2b7006d405fcb0fba09e23b85fd19b: +af2e60da0f29bb1614fc3f193cc353331986b73f3f9a0aec9421b9473d6a4b6ac8bfe2835822199c6127b806fabeef0cb9ff59f3c81ff0cb89c556f55106af6a:c8bfe2835822199c6127b806fabeef0cb9ff59f3c81ff0cb89c556f55106af6a:7dbb77b88bda94f344416a06b096566c6e8b393931a8243a6cab75c361fde7dc536aec40cded83296a89e8c3bef7d787cfc49401a7b9183f138d5000619ff073c05e2f841d6008358f10a2da7dcfac3d4d70c20d2ec34c7b6d5cd1a734d6bbb11c5fd8d2bce32ac810ef82b4188aa8ea3cfc3032233dc0e2600e9db6e18bc22b10044a31c15baceaf5554de89d2a3466807f244414d080ff2963956c6e83c8e144ed0066088b476ddcb564403447d9159f9089aba2b4d5575c4d8ae66fc8690e7349ed40832e6369c024563ec493bfcc0fc9ac787ac841397fe133167283d80c42f006a99d39e82979da3fa9334bd9ede0d14b41b7466bcebbe8171bc804a645d3723274a1b92bf82fd993358744de92441903d436fd47f23d40052a3829367f202f0553b5e49b76c5e03fa6ce7c3cf5eeb21de967bec4dd355925384ebf96697e823762bac4d43a767c241a4cef724a970d00ff3a8ab3b83eed840075c74e90f306e330013260962161e9d0910de183622ce9a6b8d5144280550fc7:50f9f941a8da9f6240f76d2fa3b06dd6b2292ed32d1c05218097d34d8a19dfe553f76ae3c6b4a2ed20852128461540decf418f52d38e64037eec7771bd1afe007dbb77b88bda94f344416a06b096566c6e8b393931a8243a6cab75c361fde7dc536aec40cded83296a89e8c3bef7d787cfc49401a7b9183f138d5000619ff073c05e2f841d6008358f10a2da7dcfac3d4d70c20d2ec34c7b6d5cd1a734d6bbb11c5fd8d2bce32ac810ef82b4188aa8ea3cfc3032233dc0e2600e9db6e18bc22b10044a31c15baceaf5554de89d2a3466807f244414d080ff2963956c6e83c8e144ed0066088b476ddcb564403447d9159f9089aba2b4d5575c4d8ae66fc8690e7349ed40832e6369c024563ec493bfcc0fc9ac787ac841397fe133167283d80c42f006a99d39e82979da3fa9334bd9ede0d14b41b7466bcebbe8171bc804a645d3723274a1b92bf82fd993358744de92441903d436fd47f23d40052a3829367f202f0553b5e49b76c5e03fa6ce7c3cf5eeb21de967bec4dd355925384ebf96697e823762bac4d43a767c241a4cef724a970d00ff3a8ab3b83eed840075c74e90f306e330013260962161e9d0910de183622ce9a6b8d5144280550fc7: +605f90b53d8e4a3b48b97d745439f2a0807d83b8502e8e2979f03e8d376ac9feaa3fae4cfa6f6bfd14ba0afa36dcb1a2656f36541ad6b3e67f1794b06360a62f:aa3fae4cfa6f6bfd14ba0afa36dcb1a2656f36541ad6b3e67f1794b06360a62f:3bcdcac292ac9519024aaecee2b3e999ff5d3445e9f1eb60940f06b91275b6c5db2722ed4d82fe89605226530f3e6b0737b308cde8956184944f388a80042f6cba274c0f7d1192a0a96b0da6e2d6a61b76518fbee555773a414590a928b4cd545fccf58172f35857120eb96e75c5c8ac9ae3add367d51d34ac403446360ec10f553ea9f14fb2b8b78cba18c3e506b2f04097063a43b2d36431cce02caf11c5a4db8c821752e52985d5af1bfbf4c61572e3fadae3ad424acd81662ea5837a1143b9669391d7b9cfe230cffb3a7bb03f6591c25a4f01c0d2d4aca3e74db1997d3739c851f0327db919ff6e77f6c8a20fdd3e1594e92d01901ab9aef194fc893e70d78c8ae0f480001a515d4f9923ae6278e8927237d05db23e984c92a683882f57b1f1882a74a193ab6912ff241b9ffa662a0d47f29205f084dbde845baaeb5dd36ae6439a437642fa763b57e8dbe84e55813f0151e97e5b9de768b234b8db15c496d4bfcfa1388788972bb50ce030bc6e0ccf4fa7d00d343782f6ba8de0:dd0212e63288cbe14a4569b4d891da3c7f92727c5e7f9a801cf9d6827085e7095b669d7d45f882ca5f0745dccd24d87a57181320191e5b7a47c3f7f2dccbd7073bcdcac292ac9519024aaecee2b3e999ff5d3445e9f1eb60940f06b91275b6c5db2722ed4d82fe89605226530f3e6b0737b308cde8956184944f388a80042f6cba274c0f7d1192a0a96b0da6e2d6a61b76518fbee555773a414590a928b4cd545fccf58172f35857120eb96e75c5c8ac9ae3add367d51d34ac403446360ec10f553ea9f14fb2b8b78cba18c3e506b2f04097063a43b2d36431cce02caf11c5a4db8c821752e52985d5af1bfbf4c61572e3fadae3ad424acd81662ea5837a1143b9669391d7b9cfe230cffb3a7bb03f6591c25a4f01c0d2d4aca3e74db1997d3739c851f0327db919ff6e77f6c8a20fdd3e1594e92d01901ab9aef194fc893e70d78c8ae0f480001a515d4f9923ae6278e8927237d05db23e984c92a683882f57b1f1882a74a193ab6912ff241b9ffa662a0d47f29205f084dbde845baaeb5dd36ae6439a437642fa763b57e8dbe84e55813f0151e97e5b9de768b234b8db15c496d4bfcfa1388788972bb50ce030bc6e0ccf4fa7d00d343782f6ba8de0: +9e2c3d189838f4dd52ef0832886874c5ca493983ddadc07cbc570af2ee9d6209f68d3b81e73557ee1f08bd2d3f46a4718256a0f3cd8d2e03eb8fe882aab65c69:f68d3b81e73557ee1f08bd2d3f46a4718256a0f3cd8d2e03eb8fe882aab65c69:19485f5238ba82eadf5eff14ca75cd42e5d56fea69d5718cfb5b1d40d760899b450e66884558f3f25b7c3de9afc4738d7ac09da5dd4689bbfac07836f5e0be432b1ddcf1b1a075bc9815d0debc865d90bd5a0c5f5604d9b46ace816c57694ecc3d40d8f84df0ede2bc4d577775a027f725de0816f563fa88f88e077720ebb6ac02574604819824db7474d4d0b22cd1bc05768e0fb867ca1c1a7b90b34ab7a41afc66957266ac0c915934aaf31c0cf6927a4f03f23285e6f24afd5813849bb08c203ac2d0336dcbf80d77f6cf7120edfbcdf181db107ec8e00f32449c1d3f5c049a92694b4ea2c6ebe5e2b0f64b5ae50ad3374d246b3270057e724a27cf263b633ab65ecb7f5c266b8007618b10ac9ac83db0febc04fd863d9661ab6e58494766f71b9a867c5a7a4555f667c1af2e54588f162a41ce756407cc4161d607b6e0682980934caa1bef036f7330d9eef01ecc553583fee5994e533a46ca916f60f8b961ae01d20f7abf0df6141b604de733c636b42018cd5f1d1ef4f84cee40fc:38a31b6b465084738262a26c065fe5d9e2886bf9dd35cde05df9bad0cc7db401c750aa19e66090bce25a3c721201e60502c8c10454346648af065eab0ee7d80f19485f5238ba82eadf5eff14ca75cd42e5d56fea69d5718cfb5b1d40d760899b450e66884558f3f25b7c3de9afc4738d7ac09da5dd4689bbfac07836f5e0be432b1ddcf1b1a075bc9815d0debc865d90bd5a0c5f5604d9b46ace816c57694ecc3d40d8f84df0ede2bc4d577775a027f725de0816f563fa88f88e077720ebb6ac02574604819824db7474d4d0b22cd1bc05768e0fb867ca1c1a7b90b34ab7a41afc66957266ac0c915934aaf31c0cf6927a4f03f23285e6f24afd5813849bb08c203ac2d0336dcbf80d77f6cf7120edfbcdf181db107ec8e00f32449c1d3f5c049a92694b4ea2c6ebe5e2b0f64b5ae50ad3374d246b3270057e724a27cf263b633ab65ecb7f5c266b8007618b10ac9ac83db0febc04fd863d9661ab6e58494766f71b9a867c5a7a4555f667c1af2e54588f162a41ce756407cc4161d607b6e0682980934caa1bef036f7330d9eef01ecc553583fee5994e533a46ca916f60f8b961ae01d20f7abf0df6141b604de733c636b42018cd5f1d1ef4f84cee40fc: +575f8fb6c7465e92c250caeec1786224bc3eed729e463953a394c9849cba908f71bfa98f5bea790ff183d924e6655cea08d0aafb617f46d23a17a657f0a9b8b2:71bfa98f5bea790ff183d924e6655cea08d0aafb617f46d23a17a657f0a9b8b2:2cc372e25e53a138793064610e7ef25d9d7422e18e249675a72e79167f43baf452cbacb50182faf80798cc38597a44b307a536360b0bc1030f8397b94cbf147353dd2d671cb8cab219a2d7b9eb828e9635d2eab6eb08182cb03557783fd282aaf7b471747c84acf72debe4514524f8447bafccccec0a840feca9755ff9adb60301c2f25d4e3ba621df5ad72100c45d7a4b91559c725ab56bb29830e35f5a6faf87db23001f11ffba9c0c15440302065827a7d7aaaeab7b446abce333c0d30c3eae9c9da63eb1c0391d4269b12c45b660290611ac29c91dbd80dc6ed302a4d191f2923922f032ab1ac10ca7323b5241c5751c3c004ac39eb1267aa10017ed2dac6c934a250dda8cb06d5be9f563b827bf3c8d95fd7d2a7e7cc3acbee92538bd7ddfba3ab2dc9f791fac76cdf9cd6a6923534cf3e067108f6aa03e320d954085c218038a70cc768b972e49952b9fe171ee1be2a52cd469b8d36b84ee902cd9410db2777192e90070d2e7c56cb6a45f0a839c78c219203b6f1b33cb4504c6a7996427741e6874cf45c5fa5a38765a1ebf1796ce16e63ee509612c40f088cbceffa3affbc13b75a1b9c02c61a180a7e83b17884fe0ec0f2fe57c47e73a22f753eaf50fca655ebb19896b827a3474911c67853c58b4a78fd085a23239b9737ef8a7baff11ddce5f2cae0543f8b45d144ae6918b9a75293ec78ea618cd2cd08c971301cdfa0a9275c1bf441d4c1f878a2e733ce0a33b6ecdacbbf0bdb5c3643fa45a013979cd01396962897421129a88757c0d88b5ac7e44fdbd938ba4bc37de4929d53751fbb43d4e09a80e735244acada8e6749f77787f33763c7472df52934591591fb226c503c8be61a920a7d37eb1686b62216957844c43c484e58745775553:903b484cb24bc503cdced844614073256c6d5aa45f1f9f62c7f22e5649212bc1d6ef9eaa617b6b835a6de2beff2faac83d37a4a5fc5cc3b556f56edde2651f022cc372e25e53a138793064610e7ef25d9d7422e18e249675a72e79167f43baf452cbacb50182faf80798cc38597a44b307a536360b0bc1030f8397b94cbf147353dd2d671cb8cab219a2d7b9eb828e9635d2eab6eb08182cb03557783fd282aaf7b471747c84acf72debe4514524f8447bafccccec0a840feca9755ff9adb60301c2f25d4e3ba621df5ad72100c45d7a4b91559c725ab56bb29830e35f5a6faf87db23001f11ffba9c0c15440302065827a7d7aaaeab7b446abce333c0d30c3eae9c9da63eb1c0391d4269b12c45b660290611ac29c91dbd80dc6ed302a4d191f2923922f032ab1ac10ca7323b5241c5751c3c004ac39eb1267aa10017ed2dac6c934a250dda8cb06d5be9f563b827bf3c8d95fd7d2a7e7cc3acbee92538bd7ddfba3ab2dc9f791fac76cdf9cd6a6923534cf3e067108f6aa03e320d954085c218038a70cc768b972e49952b9fe171ee1be2a52cd469b8d36b84ee902cd9410db2777192e90070d2e7c56cb6a45f0a839c78c219203b6f1b33cb4504c6a7996427741e6874cf45c5fa5a38765a1ebf1796ce16e63ee509612c40f088cbceffa3affbc13b75a1b9c02c61a180a7e83b17884fe0ec0f2fe57c47e73a22f753eaf50fca655ebb19896b827a3474911c67853c58b4a78fd085a23239b9737ef8a7baff11ddce5f2cae0543f8b45d144ae6918b9a75293ec78ea618cd2cd08c971301cdfa0a9275c1bf441d4c1f878a2e733ce0a33b6ecdacbbf0bdb5c3643fa45a013979cd01396962897421129a88757c0d88b5ac7e44fdbd938ba4bc37de4929d53751fbb43d4e09a80e735244acada8e6749f77787f33763c7472df52934591591fb226c503c8be61a920a7d37eb1686b62216957844c43c484e58745775553: diff --git a/ed25519-dalek/VALIDATIONVECTORS b/ed25519-dalek/VALIDATIONVECTORS new file mode 100644 index 000000000..f08d2919b --- /dev/null +++ b/ed25519-dalek/VALIDATIONVECTORS @@ -0,0 +1,11136 @@ +[ + { + "_comment": "This test vector comes from https://github.com/C2SP/CCTV/blob/5ea85644bd035c555900a2f707f7e4c31ea65ced/ed25519vectors/ed25519vectors.json", + "number": 0, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 1, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 2, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 3, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 4, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "00000000000000000000000000000000000000000000000000000000000000005e176f12cfb0d4e6eb6929b19ae4c998ef05c1c2cf628a9b1fa1c21312627108", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 5, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "00000000000000000000000000000000000000000000000000000000000000009472a69cd9a701a50d130ed52189e2455b23767db52cacb8716fb896ffeeac09", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 6, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56bc02e2b9e63e385c058bf62b14b3a2b29ccefe8e38ddb536bc3f9865320a3d801", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 7, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56bbbfd00bd9c259d8d222d15e67a3d8228585050dbb9b9585be20d8fadc721da03", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 8, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 9, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 10, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 11, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 12, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 13, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 14, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 15, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 16, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f1cb421dfbd92aa6c30d550bff53c81cf650ace6deb96a8ec22d2fef84dbbe20b", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 17, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fad7a355469b5c87e550469f6b2de409ee723acd584bf35f86b80c384e8ceb702", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 18, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5e176f12cfb0d4e6eb6929b19ae4c998ef05c1c2cf628a9b1fa1c21312627108", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 19, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9472a69cd9a701a50d130ed52189e2455b23767db52cacb8716fb896ffeeac09", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 20, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 21, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 22, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 23, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 24, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 25, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 26, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "000000000000000000000000000000000000000000000000000000000000008075b3d7e9547febbdbf3fde21df901c7ca1fc59e8b689a4ae283919e78cf62b03", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 27, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0000000000000000000000000000000000000000000000000000000000000080050abffcd4d8ccbb4b8d6bf6649f5aa99e8de5cc182a7409633856ff53f49e0c", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 28, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94639734cf989e314e9e049fc01a3864d191fed8f231b12fee6fa50aaadba44b0e", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 29, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94732d9e0279fe001d90327efa319816e3e4506b78432b8b4e1f2fdc4b960d700f", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 30, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 31, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 32, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 33, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 34, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 35, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 36, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 37, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 38, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7117c2ec783065c50f2c930cfc9d318c9737991acb260b49e2ca815474532709", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 39, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1f5fae114eb0c534b5aed0a892d0a0e1d429df6a025c5ae08012e0ffce78310c", + "msg": "ed25519vectors 27", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 40, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff75b3d7e9547febbdbf3fde21df901c7ca1fc59e8b689a4ae283919e78cf62b03", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 41, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff050abffcd4d8ccbb4b8d6bf6649f5aa99e8de5cc182a7409633856ff53f49e0c", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 42, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 39", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 43, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 44, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 45, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 46, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 47, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 48, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000000edfd6f478b59eab2545cf8f3d48c6574d2b4e8abd948148da5c62479113b8d0f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 49, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000000879e8751046a31d163df68051bbd909e6d26c8414883ba3475bf00e17c1e7b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 50, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350608f32d206a7c0b7efa9a59e66546e8f1f599ef843fb502c9cc3c4ae8b7c11e05", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 51, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506030b03796b78f7afeadfccaedc9d09ce6d487d1ece1f16b1ae2b59b7e5c40603", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 52, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 53, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 54, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 55, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 56, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 57, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 58, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 59, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 60, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080c85efbb96e35e1b671722d5d8de687d4e148ea15ec566be6a1f3cfb8a10a9d06", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 61, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "01000000000000000000000000000000000000000000000000000000000000804b18627cef9707137b02358c8b73769381269bf7cac9c473483c83c46a615d09", + "msg": "ed25519vectors 29", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 62, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080edfd6f478b59eab2545cf8f3d48c6574d2b4e8abd948148da5c62479113b8d0f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 63, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080879e8751046a31d163df68051bbd909e6d26c8414883ba3475bf00e17c1e7b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 64, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 65, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 66, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f97f5fc03f658b5b733cf20c4ea5577e8e5988ee90cb2a3c919c2a05dd2fcde04", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 67, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f2786a72a405895f7b3b4752eac49c8973270173a495ec475b34933dc05d7e904", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 68, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fedfd6f478b59eab2545cf8f3d48c6574d2b4e8abd948148da5c62479113b8d0f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 69, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f879e8751046a31d163df68051bbd909e6d26c8414883ba3475bf00e17c1e7b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 70, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 71, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 72, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff87a0755495e4b763c07eeebdd510eb7d7b167bf13bf1489785fa2be61543890e", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 73, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffafdefad9d081387fa502d650442ed15619fc936d41444fd5c4292691a16f1d06", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 74, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffedfd6f478b59eab2545cf8f3d48c6574d2b4e8abd948148da5c62479113b8d0f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 75, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff879e8751046a31d163df68051bbd909e6d26c8414883ba3475bf00e17c1e7b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 76, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 77, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 78, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 79, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 22", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 80, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 81, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 82, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 83, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 84, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05aa80ce94a6f94b9e01abfc089182b3d85548437339d7ad2e3d804f60a87a8605", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 85, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21bba68b891fdce7ad8fa923bc884aa33eeea4f341ae5ee527cb7d99a23040ab0e", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 86, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 87, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 88, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 89, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 90, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 91, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc852cd7e84d7f4609fc08f069561f201161369e38e508562ea21f0c6f582873f500", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 92, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11efaa29ea31bbaf7b896625bd0fbe78f6bb7f3cf093407794dd2cd6096e3fd103", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 93, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 94, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 95, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 96, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 97, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 98, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a57f5931a402c5cda578690e33a33ba0458eec51036b5c01c5cd486a58c0d290f", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 99, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee8093711b51dce8d4ef35fd239caecd236d2ca58604bc779880708568423a9700", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 100, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 23", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 101, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 102, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 103, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 104, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 105, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa6913952aa42c06cd8759d2175fa60c29fba5d9767291b8cda0f58d186320d604", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 106, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de0b20981a60242434fb7351f2ebc29b90bbd45c90eae5377379d780156e297409", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 107, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 108, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 109, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 110, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 111, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 112, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 113, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 114, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5639fc07db8ae613081841876d58857e3014e5f2efdeec154ae0318b2586f601", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 115, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f1509e3a68b74a8fd2b4e271b7c584a0e3cb857b6c3473e8fdf3436a2a2d0cc04", + "msg": "ed25519vectors 31", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 116, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9f09162ea121fb3e2d1270dd30ade8b5bcfdcfd1dcf624ac22cf60af9610c6c02", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 117, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9ecf8dc78bf5c647c714a00acf11719551952b488c2c9df967c7d48b479420e0e", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 118, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 119, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 120, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 121, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 20", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 122, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 123, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 124, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 39", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 125, + "key": "0000000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 126, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff24d6a9e426c0871c55d7163f0fe34e776bec47e582548d9bba074102c81fce02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 127, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff35036672b82d501137113e048abbd4f44090e3aaa7e262f555e3e78fec78e507", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 128, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5639fc07db8ae613081841876d58857e3014e5f2efdeec154ae0318b2586f601", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 129, + "key": "10eb7c3acfb2bed3e0d6ab89bf5a3d6afddd1176ce4812e38d9fd485058fdb1f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1509e3a68b74a8fd2b4e271b7c584a0e3cb857b6c3473e8fdf3436a2a2d0cc04", + "msg": "ed25519vectors 31", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 130, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 131, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 132, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 133, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 134, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 135, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 136, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "00000000000000000000000000000000000000000000000000000000000000005635c691e820339382bb85c151038e4b1815ceaaeb76bfa90cb7bf3382ec510b", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 137, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0000000000000000000000000000000000000000000000000000000000000000d2abf247722e6b4213f1890beb32c730b02a929e22a1a8de5fe84fa1e8bec40b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 138, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b2d155343b4933733be02419ac0ad255666ea0ad80d9998cc7c6086f4cf453507", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 139, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b25e180a8f97db7419c7adb79f5063f045cb18fc6af517852e3687be84bd7e803", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 140, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 141, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 142, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 143, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 27", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 144, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 145, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 146, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 147, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 148, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9b8a1787d3747a0740ed283e74e2c478d4b681f0aa2676a5c694889696138205", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 149, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f938dd30260e6bce7f9422c05def45ba6732946a9f1236aff3a187902d7128808", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 150, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5635c691e820339382bb85c151038e4b1815ceaaeb76bfa90cb7bf3382ec510b", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 151, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd2abf247722e6b4213f1890beb32c730b02a929e22a1a8de5fe84fa1e8bec40b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 152, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 153, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 154, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 155, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 156, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 157, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 158, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0000000000000000000000000000000000000000000000000000000000000080fc5d42211dbee053d3bac3913e05f32c8026274b1926b55706c621eefaa7c805", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 159, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "00000000000000000000000000000000000000000000000000000000000000807ecde75a10d2cf5c13c49b78e4026148484c48d151616ae934cf4ec66f0e3702", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 160, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9468966bbfc7bcce00aeebb561f0197cb0b823ec3f17056333fce73486dc3cbe06", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 161, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9426c8d0de0953df46bc0049fed1261b7c06189e84e5c14985454485ba5a4fb501", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 162, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 163, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 164, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 165, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 166, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 167, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 168, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 169, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 170, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff28d80ed8be5636443022fa8a24dbe8f649bea0e6edc5a6a65b29db14caa1b80e", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 171, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3cb05c8a71d4d341e74340536fea96cd93577c8044879400da68b577ed7d7207", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 172, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc5d42211dbee053d3bac3913e05f32c8026274b1926b55706c621eefaa7c805", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 173, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ecde75a10d2cf5c13c49b78e4026148484c48d151616ae934cf4ec66f0e3702", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 174, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 175, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 176, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 177, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 178, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 179, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 180, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000000164aae8ae8d165867053dd1c3806319e064523aa053b1d7003463de8c5fcba0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 181, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000000f94cd85e18f5b89bfc21b4d29b43e30038f84228fe81eff5b7d735073ba29909", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 182, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a35063cb743a485cffaa684d0d66a5ae347d17a5638e90dc2be541023114a5961f805", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 183, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a35061fc409b236539503e78560d6183d748c8a6d3e635e87c9397531394f3cb3f902", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 184, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 185, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 186, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 34", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 187, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 188, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 189, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 190, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 191, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 192, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080001bb260c36aea3c94ff5785b5a44d99a88c33e02dceb9fdfe9ae57aad604b03", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 193, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080b38e0b9773175cdae4741a4973fa1ac1bbcd7263c5f28a3cf2a5bedca4d31106", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 194, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080164aae8ae8d165867053dd1c3806319e064523aa053b1d7003463de8c5fcba0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 195, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080f94cd85e18f5b89bfc21b4d29b43e30038f84228fe81eff5b7d735073ba29909", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 196, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 197, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 198, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f522d2c5eddb07da5dc5f2207a513322ee5860d4b5f94103ca604060d3672f402", + "msg": "ed25519vectors 24", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 199, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffba7ac98b395cf8ffaecd3676b362f25f404252b7cbf07837b6bf780d2897b0c", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 200, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f164aae8ae8d165867053dd1c3806319e064523aa053b1d7003463de8c5fcba0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 201, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ff94cd85e18f5b89bfc21b4d29b43e30038f84228fe81eff5b7d735073ba29909", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 202, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 203, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 204, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe29cfd8591462aa4ba19c79672667e0665bfb240f29de8ab80b43497f12b340e", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 205, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbe2295259b59b14675c8403202c2fe88c9d9eaf761f00f67db0dd24b67b09b01", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 206, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff164aae8ae8d165867053dd1c3806319e064523aa053b1d7003463de8c5fcba0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 207, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "eefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff94cd85e18f5b89bfc21b4d29b43e30038f84228fe81eff5b7d735073ba29909", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 208, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 209, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 210, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 22", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 211, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 212, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 213, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 214, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 215, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 216, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05486fb2a5d2cb002b460db9c56c36954aebaa4e6062f300beebb2749e32274106", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 217, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21b9d3fadc566a3fb952d94b93f7add4e9e017bcf843058986b5ec9bec0638ba05", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 218, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 219, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 220, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 221, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 222, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 223, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85b4f602297e877cbbe446de71c9868e98c04a56e9bc409f60beaa400e7c633600", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 224, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11a106ed973e5cdc868eace49e639ee52f4ca53fc715f8ec612e0917f4204f920e", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 225, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 226, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 227, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 228, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 229, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 230, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a1873e9ebb328202c033407e8b9f67e528093ea899da61e9ede6999b358de0f08", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 231, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee1eb53c48312206ed56a5f83ef3fd7b6ca3012fd4c2fb08aceea83ad251358000", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 232, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 233, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 234, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 235, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 236, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 237, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0826b7ce39c8491fabdd6759f89e5a424c344ecb7d94636b268e61a2a90ab20a", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 238, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72deff8aa11cfa5ea34bc35398cf040ad303d96d5b5bd818963f69cdda872d536904", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 239, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 240, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 241, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 242, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 243, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 244, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 245, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 38", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 246, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f109d35eafa88df6c5770dd5ef7023b3965891d0c4050d2e9c7906613229d6c0e", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 247, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f86e5c516a446a3c8e69728091c2be6eb479dfe18bb36efd34e08fd8acc730407", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 248, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf99f45ef3994a163d7cd58c2cead128afd1e3f3bc1a8ff98cbf1bc35ed609d420b", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 249, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf96f525d28c69be17ff4c0922ec4de39da15d46baad32dde92e4c37201b5cbd103", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 250, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 251, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 252, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 253, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 254, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 255, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 38", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 256, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 257, + "key": "0000000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 258, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb2323a8aa3bc6edc5f2f3590ba2db757d50bf47c9f16cd1fd6a7db0f4ca24e0b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 259, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa9189abccf6d929dc864b3eec19e26e4cc94b244565779a7f85ddb8e03c3c108", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 260, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff109d35eafa88df6c5770dd5ef7023b3965891d0c4050d2e9c7906613229d6c0e", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 261, + "key": "dd1483c5304d412c1f29547640a5c2950222ee8931b7ed1c72602b7afa7024e0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff86e5c516a446a3c8e69728091c2be6eb479dfe18bb36efd34e08fd8acc730407", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 262, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 263, + "key": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 264, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 265, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 266, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "0000000000000000000000000000000000000000000000000000000000000000ef1195f0610612912016b3ee33054829bcea20ae4de1e9343b1c4e2e15649003", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 267, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b2d471882773a677af1e3824e757a33f8ddf7bbeaf3d28a09595eb8daa0d74a03", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 268, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 269, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 20", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 270, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 271, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 272, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 273, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 274, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 275, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 276, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 277, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 278, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fa83f56d4ca92da1f056c0bbaa0cc73cb350790210431ad647415c6a71242860c", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 279, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fef1195f0610612912016b3ee33054829bcea20ae4de1e9343b1c4e2e15649003", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 280, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 281, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 282, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 283, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 30", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 284, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 285, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "00000000000000000000000000000000000000000000000000000000000000800a4940ad86a3df965346037e94d0796fa785353be5f5d25b5c3c1a507c63bf0d", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 286, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9426cc293b14d304864a4cd689cbcc23cb13fcb1098f9c434cc9ca7439c9cf2505", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 287, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 288, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 289, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 290, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 291, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 292, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 293, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 294, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 295, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 296, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 297, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff944508fdd2e7908fed1b0bbbef3342fd911990128cbaa8714b0d28a617d4b508", + "msg": "ed25519vectors 19", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 298, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0a4940ad86a3df965346037e94d0796fa785353be5f5d25b5c3c1a507c63bf0d", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 299, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 300, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 301, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 302, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 23", + "flags": [ + "low_order_R", + "low_order_A" + ] + }, + { + "number": 303, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A" + ] + }, + { + "number": 304, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "0100000000000000000000000000000000000000000000000000000000000000330b30d6c1f07511e2208d233b6a34d4ed7109da2dea615bcd97daee3a842704", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R" + ] + }, + { + "number": 305, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350640657f1cb030f12543549bbabd848dc6403d354e7c99c4d0dcee9f63c9033b00", + "msg": "ed25519vectors 5", + "flags": null + }, + { + "number": 306, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 307, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 308, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 309, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 310, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 311, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 312, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 313, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "non_canonical_A" + ] + }, + { + "number": 314, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 315, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_R" + ] + }, + { + "number": 316, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "01000000000000000000000000000000000000000000000000000000000000802d32f9eeccaa31dba2ff4ab4e196b61e2ee1648073bbb5f599dcff4f7ea02900", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "non_canonical_R" + ] + }, + { + "number": 317, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "0100000000000000000000000000000000000000000000000000000000000080330b30d6c1f07511e2208d233b6a34d4ed7109da2dea615bcd97daee3a842704", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 318, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_R" + ] + }, + { + "number": 319, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f367b7a92fea8539e8793cf812e799e8ed342c635592e74323a8dfd38a06aea0b", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "non_canonical_R" + ] + }, + { + "number": 320, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f330b30d6c1f07511e2208d233b6a34d4ed7109da2dea615bcd97daee3a842704", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 321, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 18", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_R" + ] + }, + { + "number": 322, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "eefffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8ee37866245b5ef5bb4863572672809b98d93997190c514ccff477ebcf82f0d", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "non_canonical_R" + ] + }, + { + "number": 323, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff330b30d6c1f07511e2208d233b6a34d4ed7109da2dea615bcd97daee3a842704", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 324, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 325, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 326, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 327, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 328, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 329, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 330, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 331, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 332, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 19", + "flags": [ + "low_order_R", + "low_order_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 333, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 334, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 335, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05aac16c21847c8f77ede0e03571488e65c01bc418470acebc90a5f65a69c3c60f", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 336, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21fd3eacd8d7a35408e669bbf20fa791fc50be2a753015c51a7ff9554c4c540902", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 337, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 338, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 339, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 340, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 341, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 342, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 343, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 344, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 345, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 346, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 347, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 348, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc8578b7a7a27ec214b774ab6434c7afe22bc3e6fa5f12d24e81dfbd99085789170b", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 349, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f114aa4b690ec5d1502a0c77d89ede55349d93b2f4df581bc979f8f0adbe60da300", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 350, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 351, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 37", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 352, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 353, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 354, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 355, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 356, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 357, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 358, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 359, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 360, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 361, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037afe03e5c298e079a79794c3a820a61614325041fc4c1be84e6169092dd4e42a01", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 362, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0eedf2a56e3f9f022ace42aa6116f576e76d0f752df8a5c879feb2288236a882d03", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 363, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 364, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 365, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 366, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 367, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 368, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 369, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 370, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 371, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 372, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 373, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 374, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa6245db2e055cd96ba42d2e1330ef131eefb5502759cc731c8cf787d7fd2b5a0c", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 375, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de5efb4cbf95ba7a317033c634a3bd174c2e36f6fb3a0b1d96608de7cfe4374d05", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 376, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 377, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 378, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 379, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 380, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 381, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 382, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 383, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 384, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 385, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 386, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 387, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd2c8bb23568fc2c2ab61436089349253db3045d05634c2f50f67a88ab426e709", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 388, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9598a4afbe7b2a777d59b9dd15ed248f498090c35ea40d691bab0cee574467807", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_residue" + ] + }, + { + "number": 389, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 390, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 391, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 392, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 393, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 394, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 395, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 396, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 397, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 398, + "key": "0100000000000000000000000000000000000000000000000000000000000000", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 399, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcffc829608ae700722e38df9eb9761d200a3c86e7ef6dde961ba9cc8691cbc07", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 400, + "key": "ef75b20e7540e3dff77404193652ba2bd13df99c1508eee1515e27ae25f28076", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd2c8bb23568fc2c2ab61436089349253db3045d05634c2f50f67a88ab426e709", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 401, + "key": "0100000000000000000000000000000000000000000000000000000000000080", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 402, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 403, + "key": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 404, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 405, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 406, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 407, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 408, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0000000000000000000000000000000000000000000000000000000000000000620683477c6eae0f5f962cfb675dc5f112275e7207521b05f57d861fb8dfa804", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 409, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0000000000000000000000000000000000000000000000000000000000000000ab98e2715f01f57e976deea3afb2c51e93c46f5f7e054a3764fd076682034004", + "msg": "ed25519vectors 35", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 410, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b8043872d01ef87b42d987e20d1f5604f591441bec276cb285e00c60c3854a307", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 411, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56bd79e8fd671739b78d219e13e1b578516549b9c90c988249f62d1d6a2b40ea606", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 412, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 413, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 414, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9d21c5ce09b181f21ab1407e47442069d686bde3a0d7d250f0746e9835319f0a", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 415, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f806f1e38871587c8ed5631faf0f941c72744d2733d285b0d26eb5c7f79982b02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 416, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f620683477c6eae0f5f962cfb675dc5f112275e7207521b05f57d861fb8dfa804", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 417, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fab98e2715f01f57e976deea3afb2c51e93c46f5f7e054a3764fd076682034004", + "msg": "ed25519vectors 35", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 418, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 419, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 420, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 421, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 422, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0000000000000000000000000000000000000000000000000000000000000080367dbd8f23ed46b14c764374ffd8542122d8a7b57b50e54851e702e70ca6660f", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 423, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "00000000000000000000000000000000000000000000000000000000000000807df52a3fa4bde9595e64e46ee493b1f14777427d518e42f19b6e5a9d891a0004", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 424, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94cf6ffd24d41962558b5ec187dd97dd62faa0e79f56e10b9588663b310ece9800", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 425, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94d205a702b93f4292e22186bd167770bfa3278f37a46264a735b31e757393e50f", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 426, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 427, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 428, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff797080e0e516f4ce696c1f6508c4211246c8734fe1c740830bc07b428001007", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 429, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff881c2e6337a2fc68add023c1c3b77016cefb8304d735cca7571edde70fca1408", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 430, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff367dbd8f23ed46b14c764374ffd8542122d8a7b57b50e54851e702e70ca6660f", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 431, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7df52a3fa4bde9595e64e46ee493b1f14777427d518e42f19b6e5a9d891a0004", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 432, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 433, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 434, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 435, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 436, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "010000000000000000000000000000000000000000000000000000000000000048435f31d933b4c6418d7d48d1223ddf2005f6ff4c6555c5850313295f5f4507", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 437, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0100000000000000000000000000000000000000000000000000000000000000b1daaf7afa2140df3989634cfeb1dd0704b1feab734e6032a97f08ff33650704", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 438, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350606eafe34c35b824e46e082060ca75777e699beb94810d8195d570395c050470f", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 439, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506046f0694bed0011b9085a74ca8f2aded381a9392b8182a6475ce4067fe6a7b07", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 440, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 441, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 442, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0100000000000000000000000000000000000000000000000000000000000080c57b6e27f4d1afcbc43510891ee7816e69732bdac3893a4c4d75a698ec76fd09", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 443, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0100000000000000000000000000000000000000000000000000000000000080ef0227e52e05478966a93698d9ddcdf73008388227b82a9a3f4311cff41ebd01", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 444, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "010000000000000000000000000000000000000000000000000000000000008048435f31d933b4c6418d7d48d1223ddf2005f6ff4c6555c5850313295f5f4507", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 445, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "0100000000000000000000000000000000000000000000000000000000000080b1daaf7afa2140df3989634cfeb1dd0704b1feab734e6032a97f08ff33650704", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 446, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 447, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 448, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f69d1960a5be23a7e46d14e609465c4fb82f3a486b4cf9ba3cc00d79f371a3002", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 449, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fc5563d65a243389fca7e1e6da4223a97871ece326555c70d323ade5764f6420c", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 450, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f48435f31d933b4c6418d7d48d1223ddf2005f6ff4c6555c5850313295f5f4507", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 451, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fb1daaf7afa2140df3989634cfeb1dd0704b1feab734e6032a97f08ff33650704", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 452, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 453, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 454, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01e3f5bcb8f8809336ac1034f88ea2e77c63713da62cdd73a7f5c7550ca89208", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 455, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff161119954a491e61643a5f8ba93edccf16b52d784f8a896e5d7ba53b73c84504", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 456, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff48435f31d933b4c6418d7d48d1223ddf2005f6ff4c6555c5850313295f5f4507", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 457, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb1daaf7afa2140df3989634cfeb1dd0704b1feab734e6032a97f08ff33650704", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 458, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 459, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 460, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 18", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 461, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 462, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05008fba896e3cc7324a5b000fd0b903492c2ae0ae71dff7af176665ba205f3901", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 463, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc057c047ff30db9b92cac61791c64666eb0f6f11dd840d7d05b927c85f50533600e", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 464, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21f7d88566da564c6fa777235d8864b9df8d63ee4369bcc3dbf0f421fdfe9d7309", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 465, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21ddfb80c3b500d19d9a01010fb34cf3c00c7bc6e972e7d672e19ec969bd5b1908", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 466, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 467, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 468, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 469, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 470, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85a12ee75b7ce36d925ba81778453a97d8344a8decfdd797ee6d398a2c6820260e", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 471, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc8527d64d53fa7d8a7a56ab4dcfce52e6411ff5c5466029d30aa4159afad83f2409", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 472, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1123de7ac4b146e4fb8b492be4fcc69c95022bb9bba7eff6839101409bd5c5d50a", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 473, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f116f03b9c47f23619e95184c7914c139f4a66906150bdc0635512421be6e282004", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 474, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 475, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 476, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 477, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 478, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037abeb9fdccdf6e0bb47df7c1cba374f20e53e2af651a4a69d9fa8554bcd539e50b", + "msg": "ed25519vectors 24", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 479, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037ab6cdec95505f3fc3a3c58d45a591399c735e98c0cadaba2b61ee8b93f54d4105", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 480, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee27f196298cd2b5aec8b6545b122eb01dc4c87aff398c5152ed458036643f6a0a", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 481, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee035953cc64888fcdb0e70de5779b546a4c56b2d8f579748b4ce963887eb36705", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 482, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 483, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 484, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 485, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 486, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fab582b7398d6916f262ad46ab12895cd197ae7a89fd94530ad4071a5d71ee870b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 487, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8fb5bb6032e801fdce885ff4f83560b6f56e66d3d9ad3a33eb9280190b2c670a", + "msg": "ed25519vectors 41", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 488, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72def9a498ab4b8a710de4a88867179af3a355b93c22f79f39581f7fb196e72f3400", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 489, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72dec0096ae4cafa9e22026530dc5fd2efd3159c8b1e4bcbfee4bb18049c43a33a03", + "msg": "ed25519vectors 41", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 490, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 491, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 492, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 493, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 494, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffa4a318b4063e408dec239cc0589533d04f801fe25009c1edd4c0a3b25097600", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 495, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd3092366957eb289ec452b34bb6783c1790a339ad5d004d9f6d435325bdc2c0a", + "msg": "ed25519vectors 30", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 496, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf95a0b32dab50849741c136247a6109cfa76dc577cdec798e467689e43613dfc00", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 497, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9b452dd12a8b87cd3b6a527364a5e6f99eead5739469d5d120d95e50394681605", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 498, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 499, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 500, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1e9a40075f4b371d6575911abeb73574e1ce0ada5640bda601486ef92ef7ed0d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 501, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2f9a3ea3657c36624cec77ed3facee69b3eeeb32131c6b87ba0a76993d3a3a06", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 502, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa4a318b4063e408dec239cc0589533d04f801fe25009c1edd4c0a3b25097600", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 503, + "key": "6718d0a3d58deaeaefa655eae3f119071deaa2cfebfd0ca28b670f879d657086", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd3092366957eb289ec452b34bb6783c1790a339ad5d004d9f6d435325bdc2c0a", + "msg": "ed25519vectors 30", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 504, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 35", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 505, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 506, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 507, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 27", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 508, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "00000000000000000000000000000000000000000000000000000000000000006d14fb942d5ff13cef4d783375f3abef9aea3d9bcecc1a0866415dae3509d507", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 509, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "00000000000000000000000000000000000000000000000000000000000000005f5f7ffd508fc84bd8fb5d9e90a3abc24b2cbacc03b00ca42c28e7b879c5d90d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 510, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b08a85cdeab6f57330926e2eb3891c1017863d51e99f8d8f732ee42f5433c7507", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 511, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b097c3f79437cd87c6061fb032f792cd8cf46cbb4ce390b4decb9c1bf5e70ad0b", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 512, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 513, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 514, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fcf5dd993590903346c6c7dbbdab784f8eb498e7074896ff06f98221870663b07", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 515, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fca87bba547ac145cd6e813328df6df16ac5a137df85037b1c5ad2877464e840d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 516, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f6d14fb942d5ff13cef4d783375f3abef9aea3d9bcecc1a0866415dae3509d507", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 517, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5f5f7ffd508fc84bd8fb5d9e90a3abc24b2cbacc03b00ca42c28e7b879c5d90d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 518, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 519, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 520, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 521, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 522, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "0000000000000000000000000000000000000000000000000000000000000080bf79045665b39525ad5ec9e9ade82bd5bc33fb049b13503dfb97aacc4ad0ae0e", + "msg": "ed25519vectors 31", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 523, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "00000000000000000000000000000000000000000000000000000000000000806b115a2573c0a4de9f3411a96c31e1919e57bfc3e5c27faefebcdd47768b9a05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 524, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9450b2750dbb4ca36a55e8561ae5f39235db090de324b3c60126ad1f5c1d1ae30a", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 525, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9416e0b2ca09fe5b8ba05f5f8d3b4ab0e39b79b549775a9e136fd9d6fedf3b8609", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 526, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 527, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 528, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9bc693ae3af4296f60ffd9afb577cabb05c2dff634a5d483e5a8c094dd068403", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 529, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2f93b9ac542ae80e1054d7f7aff2c72cfcb5140130c37c92d4eb389c806d1509", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 530, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffbf79045665b39525ad5ec9e9ade82bd5bc33fb049b13503dfb97aacc4ad0ae0e", + "msg": "ed25519vectors 31", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 531, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff6b115a2573c0a4de9f3411a96c31e1919e57bfc3e5c27faefebcdd47768b9a05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 532, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 533, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 534, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 535, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 536, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000000092a325759ff830a4d19c0f0cce6364311dc1e7e4bc1efaa8a54632082c05cf0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 537, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000000048e9799d7754086f6eca319160c0d2ef1d35617c0151c719806495eb1026ac05", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 538, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350610dba6a8317cea9cda386e05f66eabb4248890064325c1d7a567a3443ce26606", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 539, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506ceeddc384993fffb6ea69400f4a1529ddbd0f43c6322bf53d9ec144e9127680d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 540, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 541, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 542, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "0100000000000000000000000000000000000000000000000000000000000080cdd1248e749ceac01f109bce3ce41507e49ba65d6a42baa443d77aa63113cd0f", + "msg": "ed25519vectors 18", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 543, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000008063e6cef756c8afdf5e0b364b01afa219cedeadb53d76c1ac58140dc8a7b37106", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 544, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000008092a325759ff830a4d19c0f0cce6364311dc1e7e4bc1efaa8a54632082c05cf0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 545, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "010000000000000000000000000000000000000000000000000000000000008048e9799d7754086f6eca319160c0d2ef1d35617c0151c719806495eb1026ac05", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 546, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 547, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 548, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd4859f5c56a843a885bd86045dfcda0bf117f95c07c298f45664ad2f7f043106", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 549, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f4ee43c88b8d6703511f5a818428fd65e564301e1840c7ede88cf15ffac567a01", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 550, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f92a325759ff830a4d19c0f0cce6364311dc1e7e4bc1efaa8a54632082c05cf0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 551, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f48e9799d7754086f6eca319160c0d2ef1d35617c0151c719806495eb1026ac05", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 552, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 553, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 554, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2b502e797c4ce38333e3166e4e102483cd6ea5eea07bd0347a85d303c64e8b07", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 555, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2de8d820b140fdd27706ee8011913f9542adf9641f0b2913054c4ed3c2c1be06", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 556, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92a325759ff830a4d19c0f0cce6364311dc1e7e4bc1efaa8a54632082c05cf0f", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 557, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff48e9799d7754086f6eca319160c0d2ef1d35617c0151c719806495eb1026ac05", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 558, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 559, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 560, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 561, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 562, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc051f8c6e2af77751e5474253bfac76ad7d3e16be0be2ff499ac17b66beafb7270e", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 563, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc0510eb9a2150d3683d1d873d608d7fb395b5968b379a0ec726bbbfbe453114fd01", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 564, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21a66d971845a5eed7cd0432182614117196429d78205aa912a4272b134ab1740c", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 565, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d219c41f676f85cd5a5eee282112170365be8a4820e7cc4d13fdb88b1bf1f106c0b", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 566, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 567, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 568, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 569, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 570, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85c70ad24a368812eb8a9fd7bb0e300f492a0a9dbcda01df2829bca14ccf5bf10f", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 571, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85840364150cb09a830180d30ac7907c0a858eef2a282dc539e6fd73d8a6dfad0f", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 572, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11e35ad3a31ecbff623f4733dded01086ed68e2bdaaa53171f4b8748a26514400d", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 573, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f115f11918f318e44147d456b9e33399dd987efaa7fb06b2485e1dd2f2e0c1e4b04", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 574, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 575, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 576, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 577, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 578, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a3c8b7f81b7fccdb4c6bc85121bc77ac9b2f2b22f3241501b1521195c86f3820f", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 579, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a3b8d3ce4adae6f057f2f0b1ad9b46678443d6c79779a69254a6d112ddf435b0c", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 580, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee9e7960e86abadeb7d5e1d2492122d925685b47203130aa8e629d093c61ada90d", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 581, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee40bdefba7a8c40c0580426e32719149f9600226b48f5e27dae52b6fbbdcf5805", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 582, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 583, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 584, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 585, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 586, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa7c1368a43039c42ac2dbb604b9617df90b4d2022deee87dd75d32faf83b9b901", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 587, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03faacf8c3c342a85ff0684df2e0dbdacf3a81417755cb9f5005d22bedf43fd8c803", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 588, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de1a33a7d03bde08688f729ab233eced41ff1db67eaa08157c3a1a27a00670c701", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 589, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de54af5f2d4dd8095dbea5873cc38d78ea426817d2fd61e9de5ec5165c93e62f09", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 590, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 591, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 592, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 593, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 594, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f9dff20f0d2acccc37928a00eb22a115047b52bcc2ab4b79b4432873d20172800", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 595, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fd082268d79821ab3a47487f2de6f64a13c921c0ec23e89e57cd596e56f61fe0a", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 596, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf96c95b94a5ed966fe1ac4f858c49fe690ab5f2d3a4571548d943cd31375e3f20b", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 597, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9e8df7d32a60fca528b0606d03f8bd6e57619183cb72e99da237d97f87213d301", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 598, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 599, + "key": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 600, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff681dcf4473cd9f43e21c3392dde10617a686de272c1014020896c9f458986202", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 601, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff35ec9aadea22201caf2fadcc24f4818d1202723a9a354e7b351094f746706300", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 602, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9dff20f0d2acccc37928a00eb22a115047b52bcc2ab4b79b4432873d20172800", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 603, + "key": "eca00a6a1b1f522ff2217691059915b097b73bc69bef396c36ddcd559b79e2b0", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd082268d79821ab3a47487f2de6f64a13c921c0ec23e89e57cd596e56f61fe0a", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 604, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 605, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 606, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 607, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 608, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "000000000000000000000000000000000000000000000000000000000000000031ac3ed1453a28af252ff542be21a4c0ef8b97c74940e51766b1855dbe02350d", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 609, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0000000000000000000000000000000000000000000000000000000000000000420360a0c176d4586f28edbbcafc6e5d63d8f70954510ade434219770a86f204", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 610, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b07fe06280ad617d2c94c06e2b20983e035b2848443f7de550e5358bea36f0c03", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 611, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b945fc1469dbba776f427c47e386524dc1916bf9aad21268232b7f49b15310c06", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 612, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 613, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 614, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f8afc6fda146d589fa805b824266862baa309bb1ec071226b06ba4eaff9763c0e", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 615, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ffa0b5b45eb2cb24cab8a910bfbcb08641410d64790b516c583b63940d25a9504", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 616, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f31ac3ed1453a28af252ff542be21a4c0ef8b97c74940e51766b1855dbe02350d", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 617, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f420360a0c176d4586f28edbbcafc6e5d63d8f70954510ade434219770a86f204", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 618, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 619, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 620, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 621, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 622, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "000000000000000000000000000000000000000000000000000000000000008069c99316215043ec75ea5a3d4e1357e3d0c5602366e82b24de319a520b585106", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 623, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0000000000000000000000000000000000000000000000000000000000000080c9a28760bfdbaf4f028fe8d8ecb8c34db3b7c0c71d24e26734b2c841e8fac207", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 624, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94e8b6da4567e7bfba5829e7a1197f8062462342ba28f67b2cbcf14a28af6e970a", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 625, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a948f8fa9222af828b040bcd86187c66d23faa97d1a51be5d5126bfd78688897b00", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 626, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 627, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 628, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff09b548baa15c220f0c456454bc0b3501750239f69aad45100932d36f0e9f3200", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 629, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa537bd259769d9113a834f55e1f42b160fad630daf58c8f9c7e80d8e5daa1302", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 630, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff69c99316215043ec75ea5a3d4e1357e3d0c5602366e82b24de319a520b585106", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 631, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc9a28760bfdbaf4f028fe8d8ecb8c34db3b7c0c71d24e26734b2c841e8fac207", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 632, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 633, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 634, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 635, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 636, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0100000000000000000000000000000000000000000000000000000000000000c46cc62cf59c79dc96ec34243a10a14750194479376a49cc84651a23a488ee05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 637, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "01000000000000000000000000000000000000000000000000000000000000007cbd8c879c5bf2335aa640bc7becf0547146c5becaae73560e9e80c036f2d502", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 638, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506104c833a1253a48cd66e54cab38543281b75e53c8bccb6a1dccd45eb251f1307", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 639, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506f3ae4bb3afa88c3285c8b1241cf6df8316bb4b35e71346248582cd627121ad02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 640, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 641, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 642, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "01000000000000000000000000000000000000000000000000000000000000809dfcac23338d3f13dc0ff5de059db61934190741f1f00836d7b735975892e002", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 643, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080230333f78f5b3eacd737fb60742c5c041e1ea56410ac40cc56b5b40968cc1209", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 644, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "0100000000000000000000000000000000000000000000000000000000000080c46cc62cf59c79dc96ec34243a10a14750194479376a49cc84651a23a488ee05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 645, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "01000000000000000000000000000000000000000000000000000000000000807cbd8c879c5bf2335aa640bc7becf0547146c5becaae73560e9e80c036f2d502", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 646, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 647, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 648, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f3a63dbb9c17d6ca41a6e1ce55b0a99bf8025eb49cc4640b3de424cb665fba20c", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 649, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f5b028c7e15842ffa8f6a8effc6f3a447419f4228cbfba57ebdf522573ed38f08", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 650, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fc46cc62cf59c79dc96ec34243a10a14750194479376a49cc84651a23a488ee05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 651, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7cbd8c879c5bf2335aa640bc7becf0547146c5becaae73560e9e80c036f2d502", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 652, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 653, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 654, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff92d85e93707e2f67157e9e4b3e289b823be4ccec80abd861efb9ba2e4c32510e", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 655, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffaced0fbc977b44ec36d82176d929c9878bc6a90dbabdac84f071fa6daf97050a", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 656, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc46cc62cf59c79dc96ec34243a10a14750194479376a49cc84651a23a488ee05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 657, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7cbd8c879c5bf2335aa640bc7becf0547146c5becaae73560e9e80c036f2d502", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 658, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 659, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 660, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 661, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 662, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc053fe4d58f46c5232b61f8e315b21a99832e7edb9875c9c2cfd0d77626215b580a", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 663, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc053d8acb56c081e29da3329a1f78ceff08c5f925cde1c64690dbf91d5260bcd50b", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 664, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21ea7f1306764d7e910babd66ac6b9ed1b7db6c0381fbefe5d98b70a2c8fe97407", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 665, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2110ac576cd0481197776c0121a40caf560b3fc593fa0982e1e274007955fe530a", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 666, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 667, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 668, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 669, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 670, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc858c6564558b985cc383035bfb3572083c323717acb6c014db50b4a539a1e8900a", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 671, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc851feb0bd9cb3ea94d28ecce323f06901a96b3ea2f9e5b885aafa13d571ae4f70b", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 672, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11fa299c89564128d4fe83c4758eb9c28990407191109ad31f0ca2b1548da63404", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 673, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f119a4fca0c7482f8d9f37923d8702d104d07b549e08225193b2818a6380e9ab40f", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 674, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 675, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 676, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 677, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 678, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037ae37e2cac72091af68b51b43b40f15e499c41621707e1fb30cb17362333cbba09", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 679, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a1e7d219f4540986f8904c6a16a2b74967c013b9ff1a99e6b9fdbb4835c19d70d", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 680, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee9101d1fb7d624768ec8ea7e31aca21042f3495ad5e48fdd151423f5c5f216c04", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 681, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0eef282a24a316fe5449ea437d32470df2c968f2f27688653d1e026ad3d3bfb530c", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 682, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 683, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 684, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 685, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 686, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fabfad7e6fdf808e46ddaaa65ad1e5fc4751473c239f63c49c2e017d7209058900", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 687, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa750d023533f655c6f32c38992a8a30f9f20c59bda30682a7f5f692764724e604", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 688, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72def2c459284b532cb7a74779ced5cc538521b7e466561e8abdcda7f64238404200", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 689, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de55ba20be6f48cddf9d90aef69958f1c53baa96226c0d788f25b13754d1a33207", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 690, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 691, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 692, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 693, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 694, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ff14a0b307122c632de6f34f1107225f88b1e21893f4d6719ddefd90f44b11f05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 695, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f517fa7eb17544d51490f2417a13f0d85919dd5998cc3c465b8c3614f4651d20d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 696, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9a05c2ebdd26e6d36b0d39a6dc8cad91ac0934700d6b796b6d7499d6eb81f1301", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 697, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9e97e9b1f47281ed688a320de5912618b62c9dac64d5971e2aab2d487038cc90b", + "msg": "ed25519vectors 18", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 698, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 699, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 700, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff248f13d1b0c2af4782513a8c33da39dd7cf9caf4ee3c85e58dbcbaec928aee0b", + "msg": "ed25519vectors 20", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 701, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff10e1e32f76302558b064ad4873824195afc9fbdd1a6aa20a8dd05cd54f708f00", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 702, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14a0b307122c632de6f34f1107225f88b1e21893f4d6719ddefd90f44b11f05", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 703, + "key": "015ff595e4e0add00dde896efa66ea4f6848c4396410c693c92232aa64861d4f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff517fa7eb17544d51490f2417a13f0d85919dd5998cc3c465b8c3614f4651d20d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 704, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 705, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 30", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 706, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 707, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 708, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0000000000000000000000000000000000000000000000000000000000000000ff3d622b55aad17c5c7aad97a56a7ada9eda2a92a14a4c73e349d8da4f64c70a", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 709, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "00000000000000000000000000000000000000000000000000000000000000000734b8823047a23fb776be86db7b3f4bb1c9e49bc29b352c760002bdc8e54d02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 710, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b55a1b09e210288e47a4796def776679cdec5a64bd2bb9bc69932c3bd47b96109", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 711, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b074fc0dd361fa65cf275443e324c504017fa8e80bba2a1c5ad46f116c3dac901", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 712, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 713, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 714, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fa6f79db3f81348fd22224e50a25621f810d038de2060250f8a4937f3b4cc5208", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 715, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f59c48433c25fcb5f435c328aff1bad6eaf88cc0d7586a723ba3dc921f5009f0a", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 716, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fff3d622b55aad17c5c7aad97a56a7ada9eda2a92a14a4c73e349d8da4f64c70a", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 717, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0734b8823047a23fb776be86db7b3f4bb1c9e49bc29b352c760002bdc8e54d02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 718, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 719, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 720, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 721, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 722, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0000000000000000000000000000000000000000000000000000000000000080216c38d9eae130fee53569d8a1750b2f2ef49185cddd7cf43379e84a3ef50d04", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 723, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "000000000000000000000000000000000000000000000000000000000000008026d690d9305a0d0a44ebb4e82d11b7fb6e0850fde3b27cdf662dfd300393eb01", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 724, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9452834a44fb880f6b87a7e173a2856a90f987bef39f1d95b066a528099af13302", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 725, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a94a69145f508ef4ce1a0fd25025d82516e06e492ef088de45da784f8a863ebe401", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 726, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 727, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 728, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff56668e1aa7f6b00250315677063e6f347c869cc31c7a9f31ed42d02e1bdd9e0d", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 729, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff368ce93ef4a864890115ed9cb1341fa32fa0996911fe07c1496e8c9a3df43a08", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 730, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff216c38d9eae130fee53569d8a1750b2f2ef49185cddd7cf43379e84a3ef50d04", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 731, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff26d690d9305a0d0a44ebb4e82d11b7fb6e0850fde3b27cdf662dfd300393eb01", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 732, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 733, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 734, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 735, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 736, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0100000000000000000000000000000000000000000000000000000000000000cdf25d18d1d94aa074c5277cafc39c51286021e21678ccc919bd6f326cfcb709", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 737, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "01000000000000000000000000000000000000000000000000000000000000004071f5e71c483f0886dd678575b498d03177d51ad542edf113b6214b93c79b0b", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 738, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506bc1f0d2c7b653d5aaf07a71c130d8aff5bef8653d6984f2b223081ac24a62005", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 739, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506134ff3e6e5e3fce6d8f46295871735f1700c2674d3892a7f06f055533336a002", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 740, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 741, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 742, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "010000000000000000000000000000000000000000000000000000000000008040ab130e002935091a7eac0f1476b9b5e60411ead58a3c0e95765c234752f702", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 743, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0100000000000000000000000000000000000000000000000000000000000080f28144c16a59ecedbbe82aa3481cf42279d82c6c669beb6c59622e94bcc03808", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 744, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "0100000000000000000000000000000000000000000000000000000000000080cdf25d18d1d94aa074c5277cafc39c51286021e21678ccc919bd6f326cfcb709", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 745, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "01000000000000000000000000000000000000000000000000000000000000804071f5e71c483f0886dd678575b498d03177d51ad542edf113b6214b93c79b0b", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 746, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 747, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 25", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 748, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f4524c928a583ec7cbddab4765dbdaf532c7fd278a5c4fd933e9c4c01c2f58302", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 749, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f335ec19261efdcd25bbe64dde6dcc7815b237bf53ffedc45d44351d9690e0e0b", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 750, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fcdf25d18d1d94aa074c5277cafc39c51286021e21678ccc919bd6f326cfcb709", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 751, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f4071f5e71c483f0886dd678575b498d03177d51ad542edf113b6214b93c79b0b", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 752, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 753, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 754, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff69a153a2d8922b9fcfbc06a425e6a50f28dfe3799f91cb5f983b16eadf930405", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 755, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb61ad06789857c7a7c9025df6b6321483f533c775ababa02b57ea2508507340c", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 756, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcdf25d18d1d94aa074c5277cafc39c51286021e21678ccc919bd6f326cfcb709", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 757, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4071f5e71c483f0886dd678575b498d03177d51ad542edf113b6214b93c79b0b", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 758, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 759, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 760, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 761, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 762, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05dd5e46f50f59e854fda2b2ae82c6f0c64da07146d4b7d388a9c0acec0387de06", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 763, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc057a8afc08cd56ba356afe59be2d03de9d4d0f44cd72c00f85ddb1e844275b9601", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 764, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d21e25115117021871ba256c845f462422e380099235eb48e8fc898ef6b49ee5a0c", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 765, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d214f406acc5ef89838ac824d84529e2557b738d678e3b9070634232af8e8a16d02", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 766, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 767, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 768, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 769, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 770, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc85e12d9510d58203c89c7d06a611815a2b390a6f363885b90da266c85135bc5c05", + "msg": "ed25519vectors 17", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 771, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850bbeccb5223743bd17f3a73dac85074bce77ce102d031b2e2a897a8b66ec650b", + "msg": "ed25519vectors 39", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 772, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f11701a598b9a02ae60505dd0c2938a1a0c2d6ffd4676cfb49125b19e9cb358da06", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 773, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f111a1ba75dc71a1c3275e4dd3115b1638f67d16f1440d16dcc2c0188bbb17d6206", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 774, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 775, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 776, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 777, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 778, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a1d48955627f685fca00a5d62886fa4cae966af752251034904358448891d9000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 779, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a19775c38558dafa093e9e2492933bcd4dd13656d43b75c7d13b450a986cc360d", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 780, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee91cfdeb875d86bf70f14733791c85add6b98dc813842c1338c48ea3e53e4aa0f", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 781, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee3939ad4e3797f4d869b51cb36f6b937987df797d46b851c6abc76ef707c60503", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 782, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 783, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 784, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 785, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 786, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03faf51deee4ffb00d126b97ff2d901b8e7de8bfb8a96e1dfabf4949a30b1c28ec01", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 787, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa4b4f0d7171f609289d3bbb7cbcefb424a13b468e848d58fddbb73429040c7906", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 788, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de1bdf452e3274bda9648c0e27ac7139f6c99c7ff2e96637afe541ce414e378b05", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 789, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de83458650b497c3f7226cb93e9324df567b1adda39378e844230453b95aa8c801", + "msg": "ed25519vectors", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 790, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 791, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 792, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 793, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 794, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f96d76d748c70430e986190b547bef03c36d3e53d4834f5c60b23d392695bbe06", + "msg": "ed25519vectors 22", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 795, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7ff899fcb87a689f9a17bb3d7a54ab6bbd060f3f3061502f1fa6a1fc2a8eee0603", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 796, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9e9bcd5643add13de8c05d9e630359815212df872304bef491f58f867bd542709", + "msg": "ed25519vectors 15", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 797, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf904864848c5ff5361609e941b2136012ac88139a34707e12cadf6645dff0b1008", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 798, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 799, + "key": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 800, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff77de70f3611eb29ee726ca74d20267c184a35f0fbc4261458eaad86f545d5b03", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 801, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff5c1a58a253fdd422102558a41077d95055a4f988bb5f475006a41a79d3a2ba01", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 802, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff96d76d748c70430e986190b547bef03c36d3e53d4834f5c60b23d392695bbe06", + "msg": "ed25519vectors 22", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 803, + "key": "86e72f5c2a7215151059aa151c0ee6f8e2155d301402f35d7498f078629a8f79", + "sig": "ecfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff899fcb87a689f9a17bb3d7a54ab6bbd060f3f3061502f1fa6a1fc2a8eee0603", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 804, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 805, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 806, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0000000000000000000000000000000000000000000000000000000000000000819aa7c9081f2e43b7524fdd27ef578f48dd9f02371b31f8013bd0c5321c660f", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 807, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b9dbda34f2ac60ee9d893b9b16f898617e81347886067f49d79d37740bb42a80b", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 808, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 809, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 810, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "36684ea91032ba5b1dbab2d02f4debc74c3327f2b3802e2e4d371aa42b12b56b05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 811, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 812, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f1630a351114792030905842b0d440c30c3c3c08f8e275cc32718756675d10f06", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 813, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f819aa7c9081f2e43b7524fdd27ef578f48dd9f02371b31f8013bd0c5321c660f", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 814, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 815, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 19", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 816, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 817, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0000000000000000000000000000000000000000000000000000000000000080008207ec4d9a9b8aaeee217ecb5d87a958de17beb51faec53236e7f7e07e6c05", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 818, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9467f05af9575f4d1a13f23973e28c591c4944c7dec5e4178c71a88110cc175006", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 819, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 820, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 821, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b797b156efcd45a4e2454d2fd0b21438b3ccd80d4c7fd1d1b2c8e55bd4ed4a9405ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 822, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 823, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff48ed3504f9d9a85115643ab1fefe191b70c39dc708708236227941792dc8c502", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 824, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff008207ec4d9a9b8aaeee217ecb5d87a958de17beb51faec53236e7f7e07e6c05", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 825, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 826, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 827, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 828, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_A" + ] + }, + { + "number": 829, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 830, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0100000000000000000000000000000000000000000000000000000000000000ce34fe4edd707095877049d405f52b52a726b4cbef9b8a1f950340d521fe110d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A" + ] + }, + { + "number": 831, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "01000000000000000000000000000000000000000000000000000000000000007798d1693338d7c46e61a3aae05bd23a89fdf7b62b83efdd062dd19a39d8d505", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 832, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a3506ccbd210592f2a2b70a9c9ba91f97d642a2e51b9a67ec788188039228a24e0e09", + "msg": "ed25519vectors 23", + "flags": [ + "low_order_component_A" + ] + }, + { + "number": 833, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350660f862046e40dcc3af08e1b97b6cd10ee44158cbccab65668862e844ace00500", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 834, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 12", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 835, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 836, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 837, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 838, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 839, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "b62cf890de42c413b11b1411c9f01f1c4d77aa87ef182258d1251f69af2a350605ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 840, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 24", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 841, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 16", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 842, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "010000000000000000000000000000000000000000000000000000000000008041bd7afd3d12b42f00f9ac87804fceeea002eb2800665b0fe8acd0cf53ee3207", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 843, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0100000000000000000000000000000000000000000000000000000000000080739deeff2a8c311e6172a2e9d05f6d8a048df123aa27e1015bda974e6b32b306", + "msg": "ed25519vectors 21", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 844, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "0100000000000000000000000000000000000000000000000000000000000080ce34fe4edd707095877049d405f52b52a726b4cbef9b8a1f950340d521fe110d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 845, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "01000000000000000000000000000000000000000000000000000000000000807798d1693338d7c46e61a3aae05bd23a89fdf7b62b83efdd062dd19a39d8d505", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 846, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 847, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 848, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f736cd390d6a2cb3d3a40bbbe09c87fa3caced72cdd853bfbf047adf1dec92207", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 849, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fbe39026eed2d5f2b23510d25bc1a7bface53b1d7b949facee0c7f6d1121bbe02", + "msg": "ed25519vectors 23", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 850, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fce34fe4edd707095877049d405f52b52a726b4cbef9b8a1f950340d521fe110d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 851, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f7798d1693338d7c46e61a3aae05bd23a89fdf7b62b83efdd062dd19a39d8d505", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 852, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 853, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 854, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8a4fe32e72294d34ff5060efff2141687dd52117f36311af924b73638f7bc604", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 855, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2e6065b5a7c4aa919800747605e99800c074041d01eecca3ac39b78ef00da906", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 856, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffce34fe4edd707095877049d405f52b52a726b4cbef9b8a1f950340d521fe110d", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 857, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7798d1693338d7c46e61a3aae05bd23a89fdf7b62b83efdd062dd19a39d8d505", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 858, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 859, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "01000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 860, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 861, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 862, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 863, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 864, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 865, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 866, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc05dcf76895217bf0dacec839953c960ee6d7840b9fa8ec66377df8a2e2db722305", + "msg": "ed25519vectors 10", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 867, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d211566a1ad3f92ada58707e452dcd290efc6a1951aaefe43be3b4663e38c3ac002", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 868, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc050000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 869, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 870, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "5ae36d433a7bd0efb150b6b04610d1986e3044c46b6ad69bae17aaf76b608d2105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 871, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 872, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 873, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc8507e25ac429f3fda828fd20bbe35e9d834875b64098f05e40d1bbe63f20b9c50d", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 874, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f113fc2c91b53d127bfc4fb6910467e737fc5a6463963ca4df83d0c82a419299e06", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 875, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "26e8958fc2b227b045c3f489f2ef98f0d5dfac05d3c63339b13802886d53fc850000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 876, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 877, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "fa9dde274f4820efb19a890f8ba2d8791710a4303ceef4aedf9dddc4e81a1f1105ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 878, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 879, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 880, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a3540a57b2ba00d60510ca5174b63f5ad6289f50241887ec114583b643dfe6003", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 881, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0eef081c939b0fb2f42749cd392be91b90b20875f6a7abd4019a470299569f16f01", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 882, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac037a0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 9", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 883, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 884, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "f36121d8b0b7df104e6576f0745d2786e8ef5bcfc3110b512062223b17e5e0ee05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 13", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 885, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 11", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 886, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 887, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa8c7fe7a9b40ddb9617a6ca678729b53ad7c9916531c829288e416e56fbb74809", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 888, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de73da5e09d360debd54177128d8b403f3d8cdd80ec83cd60b138b515d89d5cb0a", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 889, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "c7176a703d4dd84fba3c0b760d10670f2a2053fa2c39ccc64ec7fd7792ac03fa0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 890, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 19", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 891, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "931c92bcc5842f104eaf494fb9ef2e6791cfbb3b9495296451e85508949f72de05ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 892, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 893, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 894, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 895, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 896, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f63ec463daf4a74749995e1bca07d169051630e9cf36860b86536f5c7f6e87405", + "msg": "ed25519vectors 36", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 897, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f8fcc9e160cf71f1343cf2a6cc8d51cae1a9dc2e3debc99d97ec1190782406e05", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 898, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf92adec0cbdc3718697e370f88b291cbe1965f51921474e0fe35973dbc471c3e01", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_component_R", + "low_order_component_A", + "low_order_residue" + ] + }, + { + "number": 899, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf9327f51a83cacea96d1f3fc6be0e2682f22ce35400ccb707aa30a7321ed6dff05", + "msg": "ed25519vectors 3", + "flags": [ + "low_order_component_R", + "low_order_component_A" + ] + }, + { + "number": 900, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 901, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 902, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A" + ] + }, + { + "number": 903, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 4", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A" + ] + }, + { + "number": 904, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 14", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 905, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "37d3076f21bd3bec4ee4ebee360fe0e3b288557810e7dda72edae09650d5caf905ba9a796274d80437afa36f1236563f2f3b0aa84cecddc3d20914615ba4fe02", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "reencoded_k" + ] + }, + { + "number": 906, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 907, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 5", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 908, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0d5f3d4d7d4fd1b055ea05193ec32458d796b69aca128d34d5e4dbaec8a86e0c", + "msg": "ed25519vectors 2", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R" + ] + }, + { + "number": 909, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff472e9141da7cc7352acd9c8688b89b9c2ab873aa6c4270e9c9830051f861860f", + "msg": "ed25519vectors 6", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R" + ] + }, + { + "number": 910, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff63ec463daf4a74749995e1bca07d169051630e9cf36860b86536f5c7f6e87405", + "msg": "ed25519vectors 36", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 911, + "key": "fe894df18abf1c20088bfbe6c9ad45d42ec20663eaf7111eaea1d851da0d7f89", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8fcc9e160cf71f1343cf2a6cc8d51cae1a9dc2e3debc99d97ec1190782406e05", + "msg": "ed25519vectors 7", + "flags": [ + "low_order_R", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_R", + "reencoded_k" + ] + }, + { + "number": 912, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 1", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "low_order_residue", + "non_canonical_A", + "non_canonical_R" + ] + }, + { + "number": 913, + "key": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "sig": "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000", + "msg": "ed25519vectors 8", + "flags": [ + "low_order_R", + "low_order_A", + "low_order_component_R", + "low_order_component_A", + "non_canonical_A", + "non_canonical_R" + ] + } +] diff --git a/ed25519-dalek/benches/ed25519_benchmarks.rs b/ed25519-dalek/benches/ed25519_benchmarks.rs new file mode 100644 index 000000000..efa419ceb --- /dev/null +++ b/ed25519-dalek/benches/ed25519_benchmarks.rs @@ -0,0 +1,100 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2018-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +use criterion::{criterion_group, Criterion}; + +mod ed25519_benches { + use super::*; + use ed25519_dalek::Signature; + use ed25519_dalek::Signer; + use ed25519_dalek::SigningKey; + use rand::prelude::ThreadRng; + use rand::thread_rng; + + fn sign(c: &mut Criterion) { + let mut csprng: ThreadRng = thread_rng(); + let keypair: SigningKey = SigningKey::generate(&mut csprng); + let msg: &[u8] = b""; + + c.bench_function("Ed25519 signing", move |b| b.iter(|| keypair.sign(msg))); + } + + fn verify(c: &mut Criterion) { + let mut csprng: ThreadRng = thread_rng(); + let keypair: SigningKey = SigningKey::generate(&mut csprng); + let msg: &[u8] = b""; + let sig: Signature = keypair.sign(msg); + + c.bench_function("Ed25519 signature verification", move |b| { + b.iter(|| keypair.verify(msg, &sig)) + }); + } + + fn verify_strict(c: &mut Criterion) { + let mut csprng: ThreadRng = thread_rng(); + let keypair: SigningKey = SigningKey::generate(&mut csprng); + let msg: &[u8] = b""; + let sig: Signature = keypair.sign(msg); + + c.bench_function("Ed25519 strict signature verification", move |b| { + b.iter(|| keypair.verify_strict(msg, &sig)) + }); + } + + #[cfg(feature = "batch")] + fn verify_batch_signatures(c: &mut Criterion) { + use ed25519_dalek::verify_batch; + + static BATCH_SIZES: [usize; 8] = [4, 8, 16, 32, 64, 96, 128, 256]; + + // Benchmark batch verification for all the above batch sizes + let mut group = c.benchmark_group("Ed25519 batch signature verification"); + for size in BATCH_SIZES { + let name = format!("size={size}"); + group.bench_function(name, |b| { + let mut csprng: ThreadRng = thread_rng(); + let keypairs: Vec = (0..size) + .map(|_| SigningKey::generate(&mut csprng)) + .collect(); + let msg: &[u8] = b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"; + let messages: Vec<&[u8]> = (0..size).map(|_| msg).collect(); + let signatures: Vec = keypairs.iter().map(|key| key.sign(msg)).collect(); + let verifying_keys: Vec<_> = + keypairs.iter().map(|key| key.verifying_key()).collect(); + + b.iter(|| verify_batch(&messages[..], &signatures[..], &verifying_keys[..])); + }); + } + } + + // If the above function isn't defined, make a placeholder function + #[cfg(not(feature = "batch"))] + fn verify_batch_signatures(_: &mut Criterion) {} + + fn key_generation(c: &mut Criterion) { + let mut csprng: ThreadRng = thread_rng(); + + c.bench_function("Ed25519 keypair generation", move |b| { + b.iter(|| SigningKey::generate(&mut csprng)) + }); + } + + criterion_group! { + name = ed25519_benches; + config = Criterion::default(); + targets = + sign, + verify, + verify_strict, + verify_batch_signatures, + key_generation, + } +} + +criterion::criterion_main!(ed25519_benches::ed25519_benches); diff --git a/ed25519-dalek/docs/assets/ed25519-malleability.png b/ed25519-dalek/docs/assets/ed25519-malleability.png new file mode 100644 index 000000000..fe5896e99 Binary files /dev/null and b/ed25519-dalek/docs/assets/ed25519-malleability.png differ diff --git a/ed25519-dalek/docs/assets/rustdoc-include-katex-header.html b/ed25519-dalek/docs/assets/rustdoc-include-katex-header.html new file mode 100644 index 000000000..d240432aa --- /dev/null +++ b/ed25519-dalek/docs/assets/rustdoc-include-katex-header.html @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/ed25519-dalek/src/batch.rs b/ed25519-dalek/src/batch.rs new file mode 100644 index 000000000..fa79677d5 --- /dev/null +++ b/ed25519-dalek/src/batch.rs @@ -0,0 +1,241 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Batch signature verification. + +use alloc::vec::Vec; + +use core::iter::once; + +use curve25519_dalek::constants; +use curve25519_dalek::edwards::EdwardsPoint; +use curve25519_dalek::scalar::Scalar; +use curve25519_dalek::traits::IsIdentity; +use curve25519_dalek::traits::VartimeMultiscalarMul; + +pub use curve25519_dalek::digest::Digest; + +use merlin::Transcript; + +use rand_core::RngCore; + +use sha2::Sha512; + +use crate::errors::InternalError; +use crate::errors::SignatureError; +use crate::signature::InternalSignature; +use crate::VerifyingKey; + +/// An implementation of `rand_core::RngCore` which does nothing. This is necessary because merlin +/// demands an `Rng` as input to `TranscriptRngBuilder::finalize()`. Using this with `finalize()` +/// yields a PRG whose input is the hashed transcript. +struct ZeroRng; + +impl rand_core::RngCore for ZeroRng { + fn next_u32(&mut self) -> u32 { + rand_core::impls::next_u32_via_fill(self) + } + + fn next_u64(&mut self) -> u64 { + rand_core::impls::next_u64_via_fill(self) + } + + /// A no-op function which leaves the destination bytes for randomness unchanged. + /// + /// In this case, the internal merlin code is initialising the destination + /// by doing `[0u8; …]`, which means that when we call + /// `merlin::TranscriptRngBuilder.finalize()`, rather than rekeying the + /// STROBE state based on external randomness, we're doing an + /// `ENC_{state}(00000000000000000000000000000000)` operation, which is + /// identical to the STROBE `MAC` operation. + fn fill_bytes(&mut self, _dest: &mut [u8]) {} + + fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core::Error> { + self.fill_bytes(dest); + Ok(()) + } +} + +// `TranscriptRngBuilder::finalize()` requires a `CryptoRng` +impl rand_core::CryptoRng for ZeroRng {} + +// We write our own gen() function so we don't need to pull in the rand crate +fn gen_u128(rng: &mut R) -> u128 { + let mut buf = [0u8; 16]; + rng.fill_bytes(&mut buf); + u128::from_le_bytes(buf) +} + +/// Verify a batch of `signatures` on `messages` with their respective `verifying_keys`. +/// +/// # Inputs +/// +/// * `messages` is a slice of byte slices, one per signed message. +/// * `signatures` is a slice of `Signature`s. +/// * `verifying_keys` is a slice of `VerifyingKey`s. +/// +/// # Returns +/// +/// * A `Result` whose `Ok` value is an empty tuple and whose `Err` value is a +/// `SignatureError` containing a description of the internal error which +/// occurred. +/// +/// ## On Deterministic Nonces +/// +/// The nonces for batch signature verification are derived purely from the inputs to this function +/// themselves. +/// +/// In any sigma protocol it is wise to include as much context pertaining +/// to the public state in the protocol as possible, to avoid malleability +/// attacks where an adversary alters publics in an algebraic manner that +/// manages to satisfy the equations for the protocol in question. +/// +/// For ed25519 batch verification we include the following as scalars in the protocol transcript: +/// +/// * All of the computed `H(R||A||M)`s to the protocol transcript, and +/// * All of the `s` components of each signature. +/// +/// The former, while not quite as elegant as adding the `R`s, `A`s, and +/// `M`s separately, saves us a bit of context hashing since the +/// `H(R||A||M)`s need to be computed for the verification equation anyway. +/// +/// The latter prevents a malleability attack wherein an adversary, without access +/// to the signing key(s), can take any valid signature, `(s,R)`, and swap +/// `s` with `s' = -z1`. This doesn't constitute a signature forgery, merely +/// a vulnerability, as the resulting signature will not pass single +/// signature verification. (Thanks to Github users @real_or_random and +/// @jonasnick for pointing out this malleability issue.) +/// +/// # Examples +/// +/// ``` +/// use ed25519_dalek::{ +/// verify_batch, SigningKey, VerifyingKey, Signer, Signature, +/// }; +/// use rand::rngs::OsRng; +/// +/// # fn main() { +/// let mut csprng = OsRng; +/// let signing_keys: Vec<_> = (0..64).map(|_| SigningKey::generate(&mut csprng)).collect(); +/// let msg: &[u8] = b"They're good dogs Brant"; +/// let messages: Vec<_> = (0..64).map(|_| msg).collect(); +/// let signatures: Vec<_> = signing_keys.iter().map(|key| key.sign(&msg)).collect(); +/// let verifying_keys: Vec<_> = signing_keys.iter().map(|key| key.verifying_key()).collect(); +/// +/// let result = verify_batch(&messages, &signatures, &verifying_keys); +/// assert!(result.is_ok()); +/// # } +/// ``` +#[allow(non_snake_case)] +pub fn verify_batch( + messages: &[&[u8]], + signatures: &[ed25519::Signature], + verifying_keys: &[VerifyingKey], +) -> Result<(), SignatureError> { + // Return an Error if any of the vectors were not the same size as the others. + if signatures.len() != messages.len() + || signatures.len() != verifying_keys.len() + || verifying_keys.len() != messages.len() + { + return Err(InternalError::ArrayLength { + name_a: "signatures", + length_a: signatures.len(), + name_b: "messages", + length_b: messages.len(), + name_c: "verifying_keys", + length_c: verifying_keys.len(), + } + .into()); + } + + // Make a transcript which logs all inputs to this function + let mut transcript: Transcript = Transcript::new(b"ed25519 batch verification"); + + // We make one optimization in the transcript: since we will end up computing H(R || A || M) + // for each (R, A, M) triplet, we will feed _that_ into our transcript rather than each R, A, M + // individually. Since R and A are fixed-length, this modification is secure so long as SHA-512 + // is collision-resistant. + // It suffices to take `verifying_keys[i].as_bytes()` even though a `VerifyingKey` has two + // fields, and `as_bytes()` only returns the bytes of the first. This is because of an + // invariant guaranteed by `VerifyingKey`: the second field is always the (unique) + // decompression of the first. Thus, the serialized first field is a unique representation of + // the entire `VerifyingKey`. + let hrams: Vec<[u8; 64]> = (0..signatures.len()) + .map(|i| { + // Compute H(R || A || M), where + // R = sig.R + // A = verifying key + // M = msg + let mut h: Sha512 = Sha512::default(); + h.update(signatures[i].r_bytes()); + h.update(verifying_keys[i].as_bytes()); + h.update(messages[i]); + *h.finalize().as_ref() + }) + .collect(); + + // Update transcript with the hashes above. This covers verifying_keys, messages, and the R + // half of signatures + for hram in hrams.iter() { + transcript.append_message(b"hram", hram); + } + // Update transcript with the rest of the data. This covers the s half of the signatures + for sig in signatures { + transcript.append_message(b"sig.s", sig.s_bytes()); + } + + // All function inputs have now been hashed into the transcript. Finalize it and use it as + // randomness for the batch verification. + let mut rng = transcript.build_rng().finalize(&mut ZeroRng); + + // Convert all signatures to `InternalSignature` + let signatures = signatures + .iter() + .map(InternalSignature::try_from) + .collect::, _>>()?; + // Convert the H(R || A || M) values into scalars + let hrams: Vec = hrams + .iter() + .map(Scalar::from_bytes_mod_order_wide) + .collect(); + + // Select a random 128-bit scalar for each signature. + let zs: Vec = signatures + .iter() + .map(|_| Scalar::from(gen_u128(&mut rng))) + .collect(); + + // Compute the basepoint coefficient, ∑ s[i]z[i] (mod l) + let B_coefficient: Scalar = signatures + .iter() + .map(|sig| sig.s) + .zip(zs.iter()) + .map(|(s, z)| z * s) + .sum(); + + // Multiply each H(R || A || M) by the random value + let zhrams = hrams.iter().zip(zs.iter()).map(|(hram, z)| hram * z); + + let Rs = signatures.iter().map(|sig| sig.R.decompress()); + let As = verifying_keys.iter().map(|pk| Some(pk.point)); + let B = once(Some(constants::ED25519_BASEPOINT_POINT)); + + // Compute (-∑ z[i]s[i] (mod l)) B + ∑ z[i]R[i] + ∑ (z[i]H(R||A||M)[i] (mod l)) A[i] = 0 + let id = EdwardsPoint::optional_multiscalar_mul( + once(-B_coefficient).chain(zs.iter().cloned()).chain(zhrams), + B.chain(Rs).chain(As), + ) + .ok_or(InternalError::Verify)?; + + if id.is_identity() { + Ok(()) + } else { + Err(InternalError::Verify.into()) + } +} diff --git a/ed25519-dalek/src/constants.rs b/ed25519-dalek/src/constants.rs new file mode 100644 index 000000000..4dc48a04b --- /dev/null +++ b/ed25519-dalek/src/constants.rs @@ -0,0 +1,32 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Common constants such as buffer sizes for keypairs and signatures. + +/// The length of a ed25519 `Signature`, in bytes. +pub const SIGNATURE_LENGTH: usize = 64; + +/// The length of a ed25519 `SecretKey`, in bytes. +pub const SECRET_KEY_LENGTH: usize = 32; + +/// The length of an ed25519 `PublicKey`, in bytes. +pub const PUBLIC_KEY_LENGTH: usize = 32; + +/// The length of an ed25519 `Keypair`, in bytes. +pub const KEYPAIR_LENGTH: usize = SECRET_KEY_LENGTH + PUBLIC_KEY_LENGTH; + +/// The length of the "key" portion of an "expanded" ed25519 secret key, in bytes. +const EXPANDED_SECRET_KEY_KEY_LENGTH: usize = 32; + +/// The length of the "nonce" portion of an "expanded" ed25519 secret key, in bytes. +const EXPANDED_SECRET_KEY_NONCE_LENGTH: usize = 32; + +/// The length of an "expanded" ed25519 key, `ExpandedSecretKey`, in bytes. +pub const EXPANDED_SECRET_KEY_LENGTH: usize = + EXPANDED_SECRET_KEY_KEY_LENGTH + EXPANDED_SECRET_KEY_NONCE_LENGTH; diff --git a/ed25519-dalek/src/context.rs b/ed25519-dalek/src/context.rs new file mode 100644 index 000000000..2a27edd9d --- /dev/null +++ b/ed25519-dalek/src/context.rs @@ -0,0 +1,112 @@ +use crate::{InternalError, SignatureError}; + +/// Ed25519 contexts as used by Ed25519ph. +/// +/// Contexts are domain separator strings that can be used to isolate uses of +/// the algorithm between different protocols (which is very hard to reliably do +/// otherwise) and between different uses within the same protocol. +/// +/// To create a context, call either of the following: +/// +/// - [`SigningKey::with_context`](crate::SigningKey::with_context) +/// - [`VerifyingKey::with_context`](crate::VerifyingKey::with_context) +/// +/// For more information, see [RFC8032 § 8.3](https://www.rfc-editor.org/rfc/rfc8032#section-8.3). +/// +/// # Example +/// +#[cfg_attr(all(feature = "digest", feature = "rand_core"), doc = "```")] +#[cfg_attr( + any(not(feature = "digest"), not(feature = "rand_core")), + doc = "```ignore" +)] +/// # fn main() { +/// use ed25519_dalek::{Signature, SigningKey, VerifyingKey, Sha512}; +/// # use curve25519_dalek::digest::Digest; +/// # use rand::rngs::OsRng; +/// use ed25519_dalek::{DigestSigner, DigestVerifier}; +/// +/// # let mut csprng = OsRng; +/// # let signing_key = SigningKey::generate(&mut csprng); +/// # let verifying_key = signing_key.verifying_key(); +/// let context_str = b"Local Channel 3"; +/// let prehashed_message = Sha512::default().chain_update(b"Stay tuned for more news at 7"); +/// +/// // Signer +/// let signing_context = signing_key.with_context(context_str).unwrap(); +/// let signature = signing_context.sign_digest(prehashed_message.clone()); +/// +/// // Verifier +/// let verifying_context = verifying_key.with_context(context_str).unwrap(); +/// let verified: bool = verifying_context +/// .verify_digest(prehashed_message, &signature) +/// .is_ok(); +/// +/// # assert!(verified); +/// # } +/// ``` +#[derive(Clone, Debug)] +pub struct Context<'k, 'v, K> { + /// Key this context is being used with. + key: &'k K, + + /// Context value: a bytestring no longer than 255 octets. + value: &'v [u8], +} + +impl<'k, 'v, K> Context<'k, 'v, K> { + /// Maximum length of the context value in octets. + pub const MAX_LENGTH: usize = 255; + + /// Create a new Ed25519ph context. + pub(crate) fn new(key: &'k K, value: &'v [u8]) -> Result { + if value.len() <= Self::MAX_LENGTH { + Ok(Self { key, value }) + } else { + Err(SignatureError::from(InternalError::PrehashedContextLength)) + } + } + + /// Borrow the key. + pub fn key(&self) -> &'k K { + self.key + } + + /// Borrow the context string value. + pub fn value(&self) -> &'v [u8] { + self.value + } +} + +#[cfg(all(test, feature = "digest"))] +mod test { + #![allow(clippy::unwrap_used)] + + use crate::{Signature, SigningKey, VerifyingKey}; + use curve25519_dalek::digest::Digest; + use ed25519::signature::{DigestSigner, DigestVerifier}; + use rand::rngs::OsRng; + use sha2::Sha512; + + #[test] + fn context_correctness() { + let mut csprng = OsRng; + let signing_key: SigningKey = SigningKey::generate(&mut csprng); + let verifying_key: VerifyingKey = signing_key.verifying_key(); + + let context_str = b"Local Channel 3"; + let prehashed_message = Sha512::default().chain_update(b"Stay tuned for more news at 7"); + + // Signer + let signing_context = signing_key.with_context(context_str).unwrap(); + let signature: Signature = signing_context.sign_digest(prehashed_message.clone()); + + // Verifier + let verifying_context = verifying_key.with_context(context_str).unwrap(); + let verified: bool = verifying_context + .verify_digest(prehashed_message, &signature) + .is_ok(); + + assert!(verified); + } +} diff --git a/ed25519-dalek/src/errors.rs b/ed25519-dalek/src/errors.rs new file mode 100644 index 000000000..7cba06db5 --- /dev/null +++ b/ed25519-dalek/src/errors.rs @@ -0,0 +1,119 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Errors which may occur when parsing keys and/or signatures to or from wire formats. + +// rustc seems to think the typenames in match statements (e.g. in +// Display) should be snake cased, for some reason. +#![allow(non_snake_case)] + +use core::fmt; +use core::fmt::Display; + +#[cfg(feature = "std")] +use std::error::Error; + +/// Internal errors. Most application-level developers will likely not +/// need to pay any attention to these. +#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)] +pub(crate) enum InternalError { + PointDecompression, + ScalarFormat, + /// An error in the length of bytes handed to a constructor. + /// + /// To use this, pass a string specifying the `name` of the type which is + /// returning the error, and the `length` in bytes which its constructor + /// expects. + BytesLength { + name: &'static str, + length: usize, + }, + /// The verification equation wasn't satisfied + Verify, + /// Two arrays did not match in size, making the called signature + /// verification method impossible. + #[cfg(feature = "batch")] + ArrayLength { + name_a: &'static str, + length_a: usize, + name_b: &'static str, + length_b: usize, + name_c: &'static str, + length_c: usize, + }, + /// An ed25519ph signature can only take up to 255 octets of context. + #[cfg(feature = "digest")] + PrehashedContextLength, + /// A mismatched (public, secret) key pair. + MismatchedKeypair, +} + +impl Display for InternalError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + InternalError::PointDecompression => write!(f, "Cannot decompress Edwards point"), + InternalError::ScalarFormat => write!(f, "Cannot use scalar with high-bit set"), + InternalError::BytesLength { name: n, length: l } => { + write!(f, "{} must be {} bytes in length", n, l) + } + InternalError::Verify => write!(f, "Verification equation was not satisfied"), + #[cfg(feature = "batch")] + InternalError::ArrayLength { + name_a: na, + length_a: la, + name_b: nb, + length_b: lb, + name_c: nc, + length_c: lc, + } => write!( + f, + "Arrays must be the same length: {} has length {}, + {} has length {}, {} has length {}.", + na, la, nb, lb, nc, lc + ), + #[cfg(feature = "digest")] + InternalError::PrehashedContextLength => write!( + f, + "An ed25519ph signature can only take up to 255 octets of context" + ), + InternalError::MismatchedKeypair => write!(f, "Mismatched Keypair detected"), + } + } +} + +#[cfg(feature = "std")] +impl Error for InternalError {} + +/// Errors which may occur while processing signatures and keypairs. +/// +/// This error may arise due to: +/// +/// * Being given bytes with a length different to what was expected. +/// +/// * A problem decompressing `r`, a curve point, in the `Signature`, or the +/// curve point for a `PublicKey`. +/// +/// * A problem with the format of `s`, a scalar, in the `Signature`. This +/// is only raised if the high-bit of the scalar was set. (Scalars must +/// only be constructed from 255-bit integers.) +/// +/// * Failure of a signature to satisfy the verification equation. +pub type SignatureError = ed25519::signature::Error; + +impl From for SignatureError { + #[cfg(not(feature = "std"))] + fn from(_err: InternalError) -> SignatureError { + SignatureError::new() + } + + #[cfg(feature = "std")] + fn from(err: InternalError) -> SignatureError { + SignatureError::from_source(err) + } +} diff --git a/ed25519-dalek/src/hazmat.rs b/ed25519-dalek/src/hazmat.rs new file mode 100644 index 000000000..784961304 --- /dev/null +++ b/ed25519-dalek/src/hazmat.rs @@ -0,0 +1,266 @@ +//! Low-level interfaces to ed25519 functions +//! +//! # ⚠️ Warning: Hazmat +//! +//! These primitives are easy-to-misuse low-level interfaces. +//! +//! If you are an end user / non-expert in cryptography, **do not use any of these functions**. +//! Failure to use them correctly can lead to catastrophic failures including **full private key +//! recovery.** + +// Permit dead code because 1) this module is only public when the `hazmat` feature is set, and 2) +// even without `hazmat` we still need this module because this is where `ExpandedSecretKey` is +// defined. +#![allow(dead_code)] + +use crate::{InternalError, SignatureError}; + +use curve25519_dalek::scalar::{clamp_integer, Scalar}; + +#[cfg(feature = "zeroize")] +use zeroize::{Zeroize, ZeroizeOnDrop}; + +// These are used in the functions that are made public when the hazmat feature is set +use crate::{Signature, VerifyingKey}; +use curve25519_dalek::digest::{generic_array::typenum::U64, Digest}; + +/// Contains the secret scalar and domain separator used for generating signatures. +/// +/// This is used internally for signing. +/// +/// In the usual Ed25519 signing algorithm, `scalar` and `hash_prefix` are defined such that +/// `scalar || hash_prefix = H(sk)` where `sk` is the signing key and `H` is SHA-512. +/// **WARNING:** Deriving the values for these fields in any other way can lead to full key +/// recovery, as documented in [`raw_sign`] and [`raw_sign_prehashed`]. +/// +/// Instances of this secret are automatically overwritten with zeroes when they fall out of scope. +pub struct ExpandedSecretKey { + /// The secret scalar used for signing + pub scalar: Scalar, + /// The domain separator used when hashing the message to generate the pseudorandom `r` value + pub hash_prefix: [u8; 32], +} + +#[cfg(feature = "zeroize")] +impl Drop for ExpandedSecretKey { + fn drop(&mut self) { + self.scalar.zeroize(); + self.hash_prefix.zeroize() + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for ExpandedSecretKey {} + +// Some conversion methods for `ExpandedSecretKey`. The signing methods are defined in +// `signing.rs`, since we need them even when `not(feature = "hazmat")` +impl ExpandedSecretKey { + /// Construct an `ExpandedSecretKey` from an array of 64 bytes. In the spec, the bytes are the + /// output of a SHA-512 hash. This clamps the first 32 bytes and uses it as a scalar, and uses + /// the second 32 bytes as a domain separator for hashing. + pub fn from_bytes(bytes: &[u8; 64]) -> Self { + // TODO: Use bytes.split_array_ref once it’s in MSRV. + let mut scalar_bytes: [u8; 32] = [0u8; 32]; + let mut hash_prefix: [u8; 32] = [0u8; 32]; + scalar_bytes.copy_from_slice(&bytes[00..32]); + hash_prefix.copy_from_slice(&bytes[32..64]); + + // For signing, we'll need the integer, clamped, and converted to a Scalar. See + // PureEdDSA.keygen in RFC 8032 Appendix A. + let scalar = Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes)); + + ExpandedSecretKey { + scalar, + hash_prefix, + } + } + + /// Construct an `ExpandedSecretKey` from a slice of 64 bytes. + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `ExpandedSecretKey` or whose error value is an + /// `SignatureError` describing the error that occurred, namely that the given slice's length + /// is not 64. + pub fn from_slice(bytes: &[u8]) -> Result { + // Try to coerce bytes to a [u8; 64] + bytes.try_into().map(Self::from_bytes).map_err(|_| { + InternalError::BytesLength { + name: "ExpandedSecretKey", + length: 64, + } + .into() + }) + } +} + +impl TryFrom<&[u8]> for ExpandedSecretKey { + type Error = SignatureError; + + fn try_from(bytes: &[u8]) -> Result { + Self::from_slice(bytes) + } +} + +/// Compute an ordinary Ed25519 signature over the given message. `CtxDigest` is the digest used to +/// calculate the pseudorandomness needed for signing. According to the Ed25519 spec, `CtxDigest = +/// Sha512`. +/// +/// # ⚠️ Unsafe +/// +/// Do NOT use this function unless you absolutely must. Using the wrong values in +/// `ExpandedSecretKey` can leak your signing key. See +/// [here](https://github.com/MystenLabs/ed25519-unsafe-libs) for more details on this attack. +pub fn raw_sign( + esk: &ExpandedSecretKey, + message: &[u8], + verifying_key: &VerifyingKey, +) -> Signature +where + CtxDigest: Digest, +{ + esk.raw_sign::(message, verifying_key) +} + +/// Compute a signature over the given prehashed message, the Ed25519ph algorithm defined in +/// [RFC8032 §5.1][rfc8032]. `MsgDigest` is the digest function used to hash the signed message. +/// `CtxDigest` is the digest function used to calculate the pseudorandomness needed for signing. +/// According to the Ed25519 spec, `MsgDigest = CtxDigest = Sha512`. +/// +/// # ⚠️ Unsafe +// +/// Do NOT use this function unless you absolutely must. Using the wrong values in +/// `ExpandedSecretKey` can leak your signing key. See +/// [here](https://github.com/MystenLabs/ed25519-unsafe-libs) for more details on this attack. +/// +/// # Inputs +/// +/// * `esk` is the [`ExpandedSecretKey`] being used for signing +/// * `prehashed_message` is an instantiated hash digest with 512-bits of +/// output which has had the message to be signed previously fed into its +/// state. +/// * `verifying_key` is a [`VerifyingKey`] which corresponds to this secret key. +/// * `context` is an optional context string, up to 255 bytes inclusive, +/// which may be used to provide additional domain separation. If not +/// set, this will default to an empty string. +/// +/// `scalar` and `hash_prefix` are usually selected such that `scalar || hash_prefix = H(sk)` where +/// `sk` is the signing key +/// +/// # Returns +/// +/// A `Result` whose `Ok` value is an Ed25519ph [`Signature`] on the +/// `prehashed_message` if the context was 255 bytes or less, otherwise +/// a `SignatureError`. +/// +/// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 +#[cfg(feature = "digest")] +#[allow(non_snake_case)] +pub fn raw_sign_prehashed( + esk: &ExpandedSecretKey, + prehashed_message: MsgDigest, + verifying_key: &VerifyingKey, + context: Option<&[u8]>, +) -> Result +where + MsgDigest: Digest, + CtxDigest: Digest, +{ + esk.raw_sign_prehashed::(prehashed_message, verifying_key, context) +} + +/// The ordinary non-batched Ed25519 verification check, rejecting non-canonical R +/// values.`CtxDigest` is the digest used to calculate the pseudorandomness needed for signing. +/// According to the Ed25519 spec, `CtxDigest = Sha512`. +pub fn raw_verify( + vk: &VerifyingKey, + message: &[u8], + signature: &ed25519::Signature, +) -> Result<(), SignatureError> +where + CtxDigest: Digest, +{ + vk.raw_verify::(message, signature) +} + +/// The batched Ed25519 verification check, rejecting non-canonical R values. `MsgDigest` is the +/// digest used to hash the signed message. `CtxDigest` is the digest used to calculate the +/// pseudorandomness needed for signing. According to the Ed25519 spec, `MsgDigest = CtxDigest = +/// Sha512`. +#[cfg(feature = "digest")] +#[allow(non_snake_case)] +pub fn raw_verify_prehashed( + vk: &VerifyingKey, + prehashed_message: MsgDigest, + context: Option<&[u8]>, + signature: &ed25519::Signature, +) -> Result<(), SignatureError> +where + MsgDigest: Digest, + CtxDigest: Digest, +{ + vk.raw_verify_prehashed::(prehashed_message, context, signature) +} + +#[cfg(test)] +mod test { + #![allow(clippy::unwrap_used)] + + use super::*; + + use rand::{rngs::OsRng, CryptoRng, RngCore}; + + // Pick distinct, non-spec 512-bit hash functions for message and sig-context hashing + type CtxDigest = blake2::Blake2b512; + type MsgDigest = sha3::Sha3_512; + + impl ExpandedSecretKey { + // Make a random expanded secret key for testing purposes. This is NOT how you generate + // expanded secret keys IRL. They're the hash of a seed. + fn random(mut rng: R) -> Self { + let mut bytes = [0u8; 64]; + rng.fill_bytes(&mut bytes); + ExpandedSecretKey::from_bytes(&bytes) + } + } + + // Check that raw_sign and raw_verify work when a non-spec CtxDigest is used + #[test] + fn sign_verify_nonspec() { + // Generate the keypair + let rng = OsRng; + let esk = ExpandedSecretKey::random(rng); + let vk = VerifyingKey::from(&esk); + + let msg = b"Then one day, a piano fell on my head"; + + // Sign and verify + let sig = raw_sign::(&esk, msg, &vk); + raw_verify::(&vk, msg, &sig).unwrap(); + } + + // Check that raw_sign_prehashed and raw_verify_prehashed work when distinct, non-spec + // MsgDigest and CtxDigest are used + #[cfg(feature = "digest")] + #[test] + fn sign_verify_prehashed_nonspec() { + use curve25519_dalek::digest::Digest; + + // Generate the keypair + let rng = OsRng; + let esk = ExpandedSecretKey::random(rng); + let vk = VerifyingKey::from(&esk); + + // Hash the message + let msg = b"And then I got trampled by a herd of buffalo"; + let mut h = MsgDigest::new(); + h.update(msg); + + let ctx_str = &b"consequences"[..]; + + // Sign and verify prehashed + let sig = raw_sign_prehashed::(&esk, h.clone(), &vk, Some(ctx_str)) + .unwrap(); + raw_verify_prehashed::(&vk, h, Some(ctx_str), &sig).unwrap(); + } +} diff --git a/ed25519-dalek/src/lib.rs b/ed25519-dalek/src/lib.rs new file mode 100644 index 000000000..21d8737ba --- /dev/null +++ b/ed25519-dalek/src/lib.rs @@ -0,0 +1,294 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! A Rust implementation of ed25519 key generation, signing, and verification. +//! +//! # Example +//! +//! Creating an ed25519 signature on a message is simple. +//! +//! First, we need to generate a `SigningKey`, which includes both public and +//! secret halves of an asymmetric key. To do so, we need a cryptographically +//! secure pseudorandom number generator (CSPRNG). For this example, we'll use +//! the operating system's builtin PRNG: +//! +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] +//! # fn main() { +//! // $ cargo add ed25519_dalek --features rand_core +//! use rand::rngs::OsRng; +//! use ed25519_dalek::SigningKey; +//! use ed25519_dalek::Signature; +//! +//! let mut csprng = OsRng; +//! let signing_key: SigningKey = SigningKey::generate(&mut csprng); +//! # } +//! ``` +//! +//! We can now use this `signing_key` to sign a message: +//! +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] +//! # fn main() { +//! # use rand::rngs::OsRng; +//! # use ed25519_dalek::SigningKey; +//! # let mut csprng = OsRng; +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); +//! use ed25519_dalek::{Signature, Signer}; +//! let message: &[u8] = b"This is a test of the tsunami alert system."; +//! let signature: Signature = signing_key.sign(message); +//! # } +//! ``` +//! +//! As well as to verify that this is, indeed, a valid signature on +//! that `message`: +//! +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] +//! # fn main() { +//! # use rand::rngs::OsRng; +//! # use ed25519_dalek::{SigningKey, Signature, Signer}; +//! # let mut csprng = OsRng; +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = signing_key.sign(message); +//! use ed25519_dalek::Verifier; +//! assert!(signing_key.verify(message, &signature).is_ok()); +//! # } +//! ``` +//! +//! Anyone else, given the `public` half of the `signing_key` can also easily +//! verify this signature: +//! +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] +//! # fn main() { +//! # use rand::rngs::OsRng; +//! # use ed25519_dalek::SigningKey; +//! # use ed25519_dalek::Signature; +//! # use ed25519_dalek::Signer; +//! use ed25519_dalek::{VerifyingKey, Verifier}; +//! # let mut csprng = OsRng; +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = signing_key.sign(message); +//! +//! let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! assert!(verifying_key.verify(message, &signature).is_ok()); +//! # } +//! ``` +//! +//! ## Serialisation +//! +//! `VerifyingKey`s, `SecretKey`s, `SigningKey`s, and `Signature`s can be serialised +//! into byte-arrays by calling `.to_bytes()`. It's perfectly acceptable and +//! safe to transfer and/or store those bytes. (Of course, never transfer your +//! secret key to anyone else, since they will only need the public key to +//! verify your signatures!) +//! +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] +//! # fn main() { +//! # use rand::rngs::OsRng; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey}; +//! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; +//! # let mut csprng = OsRng; +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = signing_key.sign(message); +//! +//! let verifying_key_bytes: [u8; PUBLIC_KEY_LENGTH] = signing_key.verifying_key().to_bytes(); +//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = signing_key.to_bytes(); +//! let signing_key_bytes: [u8; KEYPAIR_LENGTH] = signing_key.to_keypair_bytes(); +//! let signature_bytes: [u8; SIGNATURE_LENGTH] = signature.to_bytes(); +//! # } +//! ``` +//! +//! And similarly, decoded from bytes with `::from_bytes()`: +//! +#![cfg_attr(feature = "rand_core", doc = "```")] +#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")] +//! # use core::convert::{TryFrom, TryInto}; +//! # use rand::rngs::OsRng; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey, SecretKey, SignatureError}; +//! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH}; +//! # fn do_test() -> Result<(SigningKey, VerifyingKey, Signature), SignatureError> { +//! # let mut csprng = OsRng; +//! # let signing_key_orig: SigningKey = SigningKey::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature_orig: Signature = signing_key_orig.sign(message); +//! # let verifying_key_bytes: [u8; PUBLIC_KEY_LENGTH] = signing_key_orig.verifying_key().to_bytes(); +//! # let signing_key_bytes: [u8; SECRET_KEY_LENGTH] = signing_key_orig.to_bytes(); +//! # let signature_bytes: [u8; SIGNATURE_LENGTH] = signature_orig.to_bytes(); +//! # +//! let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&verifying_key_bytes)?; +//! let signing_key: SigningKey = SigningKey::from_bytes(&signing_key_bytes); +//! let signature: Signature = Signature::try_from(&signature_bytes[..])?; +//! # +//! # Ok((signing_key, verifying_key, signature)) +//! # } +//! # fn main() { +//! # do_test(); +//! # } +//! ``` +//! +//! ### PKCS#8 Key Encoding +//! +//! PKCS#8 is a private key format with support for multiple algorithms. +//! It can be encoded as binary (DER) or text (PEM). +//! +//! You can recognize PEM-encoded PKCS#8 keys by the following: +//! +//! ```text +//! -----BEGIN PRIVATE KEY----- +//! ``` +//! +//! To use PKCS#8, you need to enable the `pkcs8` crate feature. +//! +//! The following traits can be used to decode/encode [`SigningKey`] and +//! [`VerifyingKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the +//! toplevel of the crate: +//! +//! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8 +//! - [`pkcs8::EncodePrivateKey`]: encode private keys to PKCS#8 +//! - [`pkcs8::DecodePublicKey`]: decode public keys from PKCS#8 +//! - [`pkcs8::EncodePublicKey`]: encode public keys to PKCS#8 +//! +//! #### Example +//! +//! NOTE: this requires the `pem` crate feature. +//! +#![cfg_attr(feature = "pem", doc = "```")] +#![cfg_attr(not(feature = "pem"), doc = "```ignore")] +//! use ed25519_dalek::{VerifyingKey, pkcs8::DecodePublicKey}; +//! +//! let pem = "-----BEGIN PUBLIC KEY----- +//! MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= +//! -----END PUBLIC KEY-----"; +//! +//! let verifying_key = VerifyingKey::from_public_key_pem(pem) +//! .expect("invalid public key PEM"); +//! ``` +//! +//! ### Using Serde +//! +//! If you prefer the bytes to be wrapped in another serialisation format, all +//! types additionally come with built-in [serde](https://serde.rs) support by +//! building `ed25519-dalek` via: +//! +//! ```bash +//! $ cargo build --features="serde" +//! ``` +//! +//! They can be then serialised into any of the wire formats which serde supports. +//! For example, using [bincode](https://github.com/TyOverby/bincode): +//! +#![cfg_attr(all(feature = "rand_core", feature = "serde"), doc = "```")] +#![cfg_attr(not(all(feature = "rand_core", feature = "serde")), doc = "```ignore")] +//! # fn main() { +//! # use rand::rngs::OsRng; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; +//! use bincode::serialize; +//! # let mut csprng = OsRng; +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); +//! # let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = signing_key.sign(message); +//! # let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! # let verified: bool = verifying_key.verify(message, &signature).is_ok(); +//! +//! let encoded_verifying_key: Vec = serialize(&verifying_key).unwrap(); +//! let encoded_signature: Vec = serialize(&signature).unwrap(); +//! # } +//! ``` +//! +//! After sending the `encoded_verifying_key` and `encoded_signature`, the +//! recipient may deserialise them and verify: +//! +#![cfg_attr(all(feature = "rand_core", feature = "serde"), doc = "```")] +#![cfg_attr(not(all(feature = "rand_core", feature = "serde")), doc = "```ignore")] +//! # fn main() { +//! # use rand::rngs::OsRng; +//! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey}; +//! # use bincode::serialize; +//! use bincode::deserialize; +//! +//! # let mut csprng = OsRng; +//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng); +//! let message: &[u8] = b"This is a test of the tsunami alert system."; +//! # let signature: Signature = signing_key.sign(message); +//! # let verifying_key: VerifyingKey = signing_key.verifying_key(); +//! # let verified: bool = verifying_key.verify(message, &signature).is_ok(); +//! # let encoded_verifying_key: Vec = serialize(&verifying_key).unwrap(); +//! # let encoded_signature: Vec = serialize(&signature).unwrap(); +//! let decoded_verifying_key: VerifyingKey = deserialize(&encoded_verifying_key).unwrap(); +//! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap(); +//! +//! # assert_eq!(verifying_key, decoded_verifying_key); +//! # assert_eq!(signature, decoded_signature); +//! # +//! let verified: bool = decoded_verifying_key.verify(&message, &decoded_signature).is_ok(); +//! +//! assert!(verified); +//! # } +//! ``` + +#![no_std] +#![warn(future_incompatible, rust_2018_idioms)] +#![deny(missing_docs)] // refuse to compile if documentation is missing +#![deny(clippy::unwrap_used)] // don't allow unwrap +#![cfg_attr(not(test), forbid(unsafe_code))] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] +#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] + +#[cfg(feature = "batch")] +extern crate alloc; + +#[cfg(any(feature = "std", test))] +#[macro_use] +extern crate std; + +pub use ed25519; + +#[cfg(feature = "batch")] +mod batch; +mod constants; +#[cfg(feature = "digest")] +mod context; +mod errors; +mod signature; +mod signing; +mod verifying; + +#[cfg(feature = "hazmat")] +pub mod hazmat; +#[cfg(not(feature = "hazmat"))] +mod hazmat; + +#[cfg(feature = "digest")] +pub use curve25519_dalek::digest::Digest; +#[cfg(feature = "digest")] +pub use sha2::Sha512; + +#[cfg(feature = "batch")] +pub use crate::batch::*; +pub use crate::constants::*; +#[cfg(feature = "digest")] +pub use crate::context::Context; +pub use crate::errors::*; +pub use crate::signing::*; +pub use crate::verifying::*; + +// Re-export the `Signer` and `Verifier` traits from the `signature` crate +#[cfg(feature = "digest")] +pub use ed25519::signature::{DigestSigner, DigestVerifier}; +pub use ed25519::signature::{Signer, Verifier}; +pub use ed25519::Signature; + +#[cfg(feature = "pkcs8")] +pub use ed25519::pkcs8; diff --git a/ed25519-dalek/src/signature.rs b/ed25519-dalek/src/signature.rs new file mode 100644 index 000000000..af8276834 --- /dev/null +++ b/ed25519-dalek/src/signature.rs @@ -0,0 +1,177 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! An ed25519 signature. + +use core::fmt::Debug; + +use curve25519_dalek::edwards::CompressedEdwardsY; +use curve25519_dalek::scalar::Scalar; + +use crate::constants::*; +use crate::errors::*; + +/// An ed25519 signature. +/// +/// # Note +/// +/// These signatures, unlike the ed25519 signature reference implementation, are +/// "detached"—that is, they do **not** include a copy of the message which has +/// been signed. +#[allow(non_snake_case)] +#[derive(Copy, Eq, PartialEq)] +pub(crate) struct InternalSignature { + /// `R` is an `EdwardsPoint`, formed by using an hash function with + /// 512-bits output to produce the digest of: + /// + /// - the nonce half of the `ExpandedSecretKey`, and + /// - the message to be signed. + /// + /// This digest is then interpreted as a `Scalar` and reduced into an + /// element in ℤ/lℤ. The scalar is then multiplied by the distinguished + /// basepoint to produce `R`, and `EdwardsPoint`. + pub(crate) R: CompressedEdwardsY, + + /// `s` is a `Scalar`, formed by using an hash function with 512-bits output + /// to produce the digest of: + /// + /// - the `r` portion of this `Signature`, + /// - the `PublicKey` which should be used to verify this `Signature`, and + /// - the message to be signed. + /// + /// This digest is then interpreted as a `Scalar` and reduced into an + /// element in ℤ/lℤ. + pub(crate) s: Scalar, +} + +impl Clone for InternalSignature { + fn clone(&self) -> Self { + *self + } +} + +impl Debug for InternalSignature { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "Signature( R: {:?}, s: {:?} )", &self.R, &self.s) + } +} + +/// Ensures that the scalar `s` of a signature is within the bounds [0, 2^253). +/// +/// **Unsafe**: This version of `check_scalar` permits signature malleability. See README. +#[cfg(feature = "legacy_compatibility")] +#[inline(always)] +fn check_scalar(bytes: [u8; 32]) -> Result { + // The highest 3 bits must not be set. No other checking for the + // remaining 2^253 - 2^252 + 27742317777372353535851937790883648493 + // potential non-reduced scalars is performed. + // + // This is compatible with ed25519-donna and libsodium when + // -DED25519_COMPAT is NOT specified. + if bytes[31] & 224 != 0 { + return Err(InternalError::ScalarFormat.into()); + } + + // You cannot do arithmetic with scalars construct with Scalar::from_bits. We only use this + // scalar for EdwardsPoint::vartime_double_scalar_mul_basepoint, which is an accepted usecase. + // The `from_bits` method is deprecated because it's unsafe. We know this. + #[allow(deprecated)] + Ok(Scalar::from_bits(bytes)) +} + +/// Ensures that the scalar `s` of a signature is within the bounds [0, ℓ) +#[cfg(not(feature = "legacy_compatibility"))] +#[inline(always)] +fn check_scalar(bytes: [u8; 32]) -> Result { + match Scalar::from_canonical_bytes(bytes).into() { + None => Err(InternalError::ScalarFormat.into()), + Some(x) => Ok(x), + } +} + +impl InternalSignature { + /// Construct a `Signature` from a slice of bytes. + /// + /// # Scalar Malleability Checking + /// + /// As originally specified in the ed25519 paper (cf. the "Malleability" + /// section of the README in this repo), no checks whatsoever were performed + /// for signature malleability. + /// + /// Later, a semi-functional, hacky check was added to most libraries to + /// "ensure" that the scalar portion, `s`, of the signature was reduced `mod + /// \ell`, the order of the basepoint: + /// + /// ```ignore + /// if signature.s[31] & 224 != 0 { + /// return Err(); + /// } + /// ``` + /// + /// This bit-twiddling ensures that the most significant three bits of the + /// scalar are not set: + /// + /// ```python,ignore + /// >>> 0b00010000 & 224 + /// 0 + /// >>> 0b00100000 & 224 + /// 32 + /// >>> 0b01000000 & 224 + /// 64 + /// >>> 0b10000000 & 224 + /// 128 + /// ``` + /// + /// However, this check is hacky and insufficient to check that the scalar is + /// fully reduced `mod \ell = 2^252 + 27742317777372353535851937790883648493` as + /// it leaves us with a guanteed bound of 253 bits. This means that there are + /// `2^253 - 2^252 + 2774231777737235353585193779088364849311` remaining scalars + /// which could cause malleabilllity. + /// + /// RFC8032 [states](https://tools.ietf.org/html/rfc8032#section-5.1.7): + /// + /// > To verify a signature on a message M using public key A, [...] + /// > first split the signature into two 32-octet halves. Decode the first + /// > half as a point R, and the second half as an integer S, in the range + /// > 0 <= s < L. Decode the public key A as point A'. If any of the + /// > decodings fail (including S being out of range), the signature is + /// > invalid. + /// + /// However, by the time this was standardised, most libraries in use were + /// only checking the most significant three bits. (See also the + /// documentation for [`crate::VerifyingKey::verify_strict`].) + #[inline] + #[allow(non_snake_case)] + pub fn from_bytes(bytes: &[u8; SIGNATURE_LENGTH]) -> Result { + // TODO: Use bytes.split_array_ref once it’s in MSRV. + let mut R_bytes: [u8; 32] = [0u8; 32]; + let mut s_bytes: [u8; 32] = [0u8; 32]; + R_bytes.copy_from_slice(&bytes[00..32]); + s_bytes.copy_from_slice(&bytes[32..64]); + + Ok(InternalSignature { + R: CompressedEdwardsY(R_bytes), + s: check_scalar(s_bytes)?, + }) + } +} + +impl TryFrom<&ed25519::Signature> for InternalSignature { + type Error = SignatureError; + + fn try_from(sig: &ed25519::Signature) -> Result { + InternalSignature::from_bytes(&sig.to_bytes()) + } +} + +impl From for ed25519::Signature { + fn from(sig: InternalSignature) -> ed25519::Signature { + ed25519::Signature::from_components(*sig.R.as_bytes(), *sig.s.as_bytes()) + } +} diff --git a/ed25519-dalek/src/signing.rs b/ed25519-dalek/src/signing.rs new file mode 100644 index 000000000..e63d34bb7 --- /dev/null +++ b/ed25519-dalek/src/signing.rs @@ -0,0 +1,908 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! ed25519 signing keys. + +use core::fmt::Debug; + +#[cfg(feature = "pkcs8")] +use ed25519::pkcs8; + +#[cfg(any(test, feature = "rand_core"))] +use rand_core::CryptoRngCore; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +use sha2::Sha512; +use subtle::{Choice, ConstantTimeEq}; + +use curve25519_dalek::{ + digest::{generic_array::typenum::U64, Digest}, + edwards::{CompressedEdwardsY, EdwardsPoint}, + scalar::Scalar, +}; + +use ed25519::signature::{KeypairRef, Signer, Verifier}; + +#[cfg(feature = "digest")] +use crate::context::Context; +#[cfg(feature = "digest")] +use signature::DigestSigner; + +#[cfg(feature = "zeroize")] +use zeroize::{Zeroize, ZeroizeOnDrop}; + +use crate::{ + constants::{KEYPAIR_LENGTH, SECRET_KEY_LENGTH}, + errors::{InternalError, SignatureError}, + hazmat::ExpandedSecretKey, + signature::InternalSignature, + verifying::VerifyingKey, + Signature, +}; + +/// ed25519 secret key as defined in [RFC8032 § 5.1.5]: +/// +/// > The private key is 32 octets (256 bits, corresponding to b) of +/// > cryptographically secure random data. +/// +/// [RFC8032 § 5.1.5]: https://www.rfc-editor.org/rfc/rfc8032#section-5.1.5 +pub type SecretKey = [u8; SECRET_KEY_LENGTH]; + +/// ed25519 signing key which can be used to produce signatures. +// Invariant: `verifying_key` is always the public key of +// `secret_key`. This prevents the signing function oracle attack +// described in https://github.com/MystenLabs/ed25519-unsafe-libs +#[derive(Clone)] +pub struct SigningKey { + /// The secret half of this signing key. + pub(crate) secret_key: SecretKey, + /// The public half of this signing key. + pub(crate) verifying_key: VerifyingKey, +} + +/// # Example +/// +/// ``` +/// # extern crate ed25519_dalek; +/// # +/// use ed25519_dalek::SigningKey; +/// use ed25519_dalek::SECRET_KEY_LENGTH; +/// use ed25519_dalek::SignatureError; +/// +/// # fn doctest() -> Result { +/// let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = [ +/// 157, 097, 177, 157, 239, 253, 090, 096, +/// 186, 132, 074, 244, 146, 236, 044, 196, +/// 068, 073, 197, 105, 123, 050, 105, 025, +/// 112, 059, 172, 003, 028, 174, 127, 096, ]; +/// +/// let signing_key: SigningKey = SigningKey::from_bytes(&secret_key_bytes); +/// assert_eq!(signing_key.to_bytes(), secret_key_bytes); +/// +/// # Ok(signing_key) +/// # } +/// # +/// # fn main() { +/// # let result = doctest(); +/// # assert!(result.is_ok()); +/// # } +/// ``` +impl SigningKey { + /// Construct a [`SigningKey`] from a [`SecretKey`] + /// + #[inline] + pub fn from_bytes(secret_key: &SecretKey) -> Self { + let verifying_key = VerifyingKey::from(&ExpandedSecretKey::from(secret_key)); + Self { + secret_key: *secret_key, + verifying_key, + } + } + + /// Convert this [`SigningKey`] into a [`SecretKey`] + #[inline] + pub fn to_bytes(&self) -> SecretKey { + self.secret_key + } + + /// Convert this [`SigningKey`] into a [`SecretKey`] reference + #[inline] + pub fn as_bytes(&self) -> &SecretKey { + &self.secret_key + } + + /// Construct a [`SigningKey`] from the bytes of a `VerifyingKey` and `SecretKey`. + /// + /// # Inputs + /// + /// * `bytes`: an `&[u8]` of length [`KEYPAIR_LENGTH`], representing the + /// scalar for the secret key, and a compressed Edwards-Y coordinate of a + /// point on curve25519, both as bytes. (As obtained from + /// [`SigningKey::to_bytes`].) + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA [`SigningKey`] or whose error value + /// is an `SignatureError` describing the error that occurred. + #[inline] + pub fn from_keypair_bytes(bytes: &[u8; 64]) -> Result { + let (secret_key, verifying_key) = bytes.split_at(SECRET_KEY_LENGTH); + let signing_key = SigningKey::try_from(secret_key)?; + let verifying_key = VerifyingKey::try_from(verifying_key)?; + + if signing_key.verifying_key() != verifying_key { + return Err(InternalError::MismatchedKeypair.into()); + } + + Ok(signing_key) + } + + /// Convert this signing key to a 64-byte keypair. + /// + /// # Returns + /// + /// An array of bytes, `[u8; KEYPAIR_LENGTH]`. The first + /// `SECRET_KEY_LENGTH` of bytes is the `SecretKey`, and the next + /// `PUBLIC_KEY_LENGTH` bytes is the `VerifyingKey` (the same as other + /// libraries, such as [Adam Langley's ed25519 Golang + /// implementation](https://github.com/agl/ed25519/)). It is guaranteed that + /// the encoded public key is the one derived from the encoded secret key. + pub fn to_keypair_bytes(&self) -> [u8; KEYPAIR_LENGTH] { + let mut bytes: [u8; KEYPAIR_LENGTH] = [0u8; KEYPAIR_LENGTH]; + + bytes[..SECRET_KEY_LENGTH].copy_from_slice(&self.secret_key); + bytes[SECRET_KEY_LENGTH..].copy_from_slice(self.verifying_key.as_bytes()); + bytes + } + + /// Get the [`VerifyingKey`] for this [`SigningKey`]. + pub fn verifying_key(&self) -> VerifyingKey { + self.verifying_key + } + + /// Create a signing context that can be used for Ed25519ph with + /// [`DigestSigner`]. + #[cfg(feature = "digest")] + pub fn with_context<'k, 'v>( + &'k self, + context_value: &'v [u8], + ) -> Result, SignatureError> { + Context::new(self, context_value) + } + + /// Generate an ed25519 signing key. + /// + /// # Example + /// + #[cfg_attr(feature = "rand_core", doc = "```")] + #[cfg_attr(not(feature = "rand_core"), doc = "```ignore")] + /// # fn main() { + /// use rand::rngs::OsRng; + /// use ed25519_dalek::{Signature, SigningKey}; + /// + /// let mut csprng = OsRng; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// # } + /// ``` + /// + /// # Input + /// + /// A CSPRNG with a `fill_bytes()` method, e.g. `rand_os::OsRng`. + /// + /// The caller must also supply a hash function which implements the + /// `Digest` and `Default` traits, and which returns 512 bits of output. + /// The standard hash function used for most ed25519 libraries is SHA-512, + /// which is available with `use sha2::Sha512` as in the example above. + /// Other suitable hash functions include Keccak-512 and Blake2b-512. + #[cfg(any(test, feature = "rand_core"))] + pub fn generate(csprng: &mut R) -> SigningKey { + let mut secret = SecretKey::default(); + csprng.fill_bytes(&mut secret); + Self::from_bytes(&secret) + } + + /// Sign a `prehashed_message` with this [`SigningKey`] using the + /// Ed25519ph algorithm defined in [RFC8032 §5.1][rfc8032]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// + /// # Returns + /// + /// An Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Note + /// + /// The RFC only permits SHA-512 to be used for prehashing, i.e., `MsgDigest = Sha512`. This + /// function technically works, and is probably safe to use, with any secure hash function with + /// 512-bit digests, but anything outside of SHA-512 is NOT specification-compliant. We expose + /// [`crate::Sha512`] for user convenience. + /// + /// # Examples + /// + #[cfg_attr(all(feature = "rand_core", feature = "digest"), doc = "```")] + #[cfg_attr( + any(not(feature = "rand_core"), not(feature = "digest")), + doc = "```ignore" + )] + /// use ed25519_dalek::Digest; + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::Signature; + /// use sha2::Sha512; + /// use rand::rngs::OsRng; + /// + /// # fn main() { + /// let mut csprng = OsRng; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// let message: &[u8] = b"All I want is to pet all of the dogs."; + /// + /// // Create a hash digest object which we'll feed the message into: + /// let mut prehashed: Sha512 = Sha512::new(); + /// + /// prehashed.update(message); + /// # } + /// ``` + /// + /// If you want, you can optionally pass a "context". It is generally a + /// good idea to choose a context and try to make it unique to your project + /// and this specific usage of signatures. + /// + /// For example, without this, if you were to [convert your OpenPGP key + /// to a Bitcoin key][terrible_idea] (just as an example, and also Don't + /// Ever Do That) and someone tricked you into signing an "email" which was + /// actually a Bitcoin transaction moving all your magic internet money to + /// their address, it'd be a valid transaction. + /// + /// By adding a context, this trick becomes impossible, because the context + /// is concatenated into the hash, which is then signed. So, going with the + /// previous example, if your bitcoin wallet used a context of + /// "BitcoinWalletAppTxnSigning" and OpenPGP used a context (this is likely + /// the least of their safety problems) of "GPGsCryptoIsntConstantTimeLol", + /// then the signatures produced by both could never match the other, even + /// if they signed the exact same message with the same key. + /// + /// Let's add a context for good measure (remember, you'll want to choose + /// your own!): + /// + #[cfg_attr(all(feature = "rand_core", feature = "digest"), doc = "```")] + #[cfg_attr( + any(not(feature = "rand_core"), not(feature = "digest")), + doc = "```ignore" + )] + /// # use ed25519_dalek::Digest; + /// # use ed25519_dalek::SigningKey; + /// # use ed25519_dalek::Signature; + /// # use ed25519_dalek::SignatureError; + /// # use sha2::Sha512; + /// # use rand::rngs::OsRng; + /// # + /// # fn do_test() -> Result { + /// # let mut csprng = OsRng; + /// # let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// # let message: &[u8] = b"All I want is to pet all of the dogs."; + /// # let mut prehashed: Sha512 = Sha512::new(); + /// # prehashed.update(message); + /// # + /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; + /// + /// let sig: Signature = signing_key.sign_prehashed(prehashed, Some(context))?; + /// # + /// # Ok(sig) + /// # } + /// # fn main() { + /// # do_test(); + /// # } + /// ``` + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + /// [terrible_idea]: https://github.com/isislovecruft/scripts/blob/master/gpgkey2bc.py + #[cfg(feature = "digest")] + pub fn sign_prehashed( + &self, + prehashed_message: MsgDigest, + context: Option<&[u8]>, + ) -> Result + where + MsgDigest: Digest, + { + ExpandedSecretKey::from(&self.secret_key).raw_sign_prehashed::( + prehashed_message, + &self.verifying_key, + context, + ) + } + + /// Verify a signature on a message with this signing key's public key. + pub fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> { + self.verifying_key.verify(message, signature) + } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph [`Signature`] on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// [`SigningKey`] on the `prehashed_message`. + /// + /// # Note + /// + /// The RFC only permits SHA-512 to be used for prehashing, i.e., `MsgDigest = Sha512`. This + /// function technically works, and is probably safe to use, with any secure hash function with + /// 512-bit digests, but anything outside of SHA-512 is NOT specification-compliant. We expose + /// [`crate::Sha512`] for user convenience. + /// + /// # Examples + /// + #[cfg_attr(all(feature = "rand_core", feature = "digest"), doc = "```")] + #[cfg_attr( + any(not(feature = "rand_core"), not(feature = "digest")), + doc = "```ignore" + )] + /// use ed25519_dalek::Digest; + /// use ed25519_dalek::SigningKey; + /// use ed25519_dalek::Signature; + /// use ed25519_dalek::SignatureError; + /// use sha2::Sha512; + /// use rand::rngs::OsRng; + /// + /// # fn do_test() -> Result<(), SignatureError> { + /// let mut csprng = OsRng; + /// let signing_key: SigningKey = SigningKey::generate(&mut csprng); + /// let message: &[u8] = b"All I want is to pet all of the dogs."; + /// + /// let mut prehashed: Sha512 = Sha512::new(); + /// prehashed.update(message); + /// + /// let context: &[u8] = b"Ed25519DalekSignPrehashedDoctest"; + /// + /// let sig: Signature = signing_key.sign_prehashed(prehashed, Some(context))?; + /// + /// // The sha2::Sha512 struct doesn't implement Copy, so we'll have to create a new one: + /// let mut prehashed_again: Sha512 = Sha512::default(); + /// prehashed_again.update(message); + /// + /// let verified = signing_key.verifying_key().verify_prehashed(prehashed_again, Some(context), &sig); + /// + /// assert!(verified.is_ok()); + /// + /// # verified + /// # } + /// # + /// # fn main() { + /// # do_test(); + /// # } + /// ``` + /// + /// [rfc8032]: https://tools.ietf.org/html/rfc8032#section-5.1 + #[cfg(feature = "digest")] + pub fn verify_prehashed( + &self, + prehashed_message: MsgDigest, + context: Option<&[u8]>, + signature: &Signature, + ) -> Result<(), SignatureError> + where + MsgDigest: Digest, + { + self.verifying_key + .verify_prehashed(prehashed_message, context, signature) + } + + /// Strictly verify a signature on a message with this signing key's public key. + /// + /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures + /// + /// This version of verification is technically non-RFC8032 compliant. The + /// following explains why. + /// + /// 1. Scalar Malleability + /// + /// The authors of the RFC explicitly stated that verification of an ed25519 + /// signature must fail if the scalar `s` is not properly reduced mod \ell: + /// + /// > To verify a signature on a message M using public key A, with F + /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or + /// > Ed25519ph is being used, C being the context, first split the + /// > signature into two 32-octet halves. Decode the first half as a + /// > point R, and the second half as an integer S, in the range + /// > 0 <= s < L. Decode the public key A as point A'. If any of the + /// > decodings fail (including S being out of range), the signature is + /// > invalid.) + /// + /// All `verify_*()` functions within ed25519-dalek perform this check. + /// + /// 2. Point malleability + /// + /// The authors of the RFC added in a malleability check to step #3 in + /// §5.1.7, for small torsion components in the `R` value of the signature, + /// *which is not strictly required*, as they state: + /// + /// > Check the group equation \[8\]\[S\]B = \[8\]R + \[8\]\[k\]A'. It's + /// > sufficient, but not required, to instead check \[S\]B = R + \[k\]A'. + /// + /// # History of Malleability Checks + /// + /// As originally defined (cf. the "Malleability" section in the README of + /// this repo), ed25519 signatures didn't consider *any* form of + /// malleability to be an issue. Later the scalar malleability was + /// considered important. Still later, particularly with interests in + /// cryptocurrency design and in unique identities (e.g. for Signal users, + /// Tor onion services, etc.), the group element malleability became a + /// concern. + /// + /// However, libraries had already been created to conform to the original + /// definition. One well-used library in particular even implemented the + /// group element malleability check, *but only for batch verification*! + /// Which meant that even using the same library, a single signature could + /// verify fine individually, but suddenly, when verifying it with a bunch + /// of other signatures, the whole batch would fail! + /// + /// # "Strict" Verification + /// + /// This method performs *both* of the above signature malleability checks. + /// + /// It must be done as a separate method because one doesn't simply get to + /// change the definition of a cryptographic primitive ten years + /// after-the-fact with zero consideration for backwards compatibility in + /// hardware and protocols which have it already have the older definition + /// baked in. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify_strict( + &self, + message: &[u8], + signature: &Signature, + ) -> Result<(), SignatureError> { + self.verifying_key.verify_strict(message, signature) + } + + /// Convert this signing key into a byte representation of an unreduced, unclamped Curve25519 + /// scalar. This is NOT the same thing as `self.to_scalar().to_bytes()`, since `to_scalar()` + /// performs a clamping step, which changes the value of the resulting scalar. + /// + /// This can be used for performing X25519 Diffie-Hellman using Ed25519 keys. The bytes output + /// by this function are a valid corresponding [`StaticSecret`](https://docs.rs/x25519-dalek/2.0.0/x25519_dalek/struct.StaticSecret.html#impl-From%3C%5Bu8;+32%5D%3E-for-StaticSecret) + /// for the X25519 public key given by `self.verifying_key().to_montgomery()`. + /// + /// # Note + /// + /// We do NOT recommend using a signing/verifying key for encryption. Signing keys are usually + /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can + /// help it, use a separate key for encryption. + /// + /// For more information on the security of systems which use the same keys for both signing + /// and Diffie-Hellman, see the paper + /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). + pub fn to_scalar_bytes(&self) -> [u8; 32] { + // Per the spec, the ed25519 secret key sk is expanded to + // (scalar_bytes, hash_prefix) = SHA-512(sk) + // where the two outputs are both 32 bytes. scalar_bytes is what we return. Its clamped and + // reduced form is what we use for signing (see impl ExpandedSecretKey) + let mut buf = [0u8; 32]; + let scalar_and_hash_prefix = Sha512::default().chain_update(self.secret_key).finalize(); + buf.copy_from_slice(&scalar_and_hash_prefix[..32]); + buf + } + + /// Convert this signing key into a Curve25519 scalar. This is computed by clamping and + /// reducing the output of [`Self::to_scalar_bytes`]. + /// + /// This can be used anywhere where a Curve25519 scalar is used as a private key, e.g., in + /// [`crypto_box`](https://docs.rs/crypto_box/0.9.1/crypto_box/struct.SecretKey.html#impl-From%3CScalar%3E-for-SecretKey). + /// + /// # Note + /// + /// We do NOT recommend using a signing/verifying key for encryption. Signing keys are usually + /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can + /// help it, use a separate key for encryption. + /// + /// For more information on the security of systems which use the same keys for both signing + /// and Diffie-Hellman, see the paper + /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). + pub fn to_scalar(&self) -> Scalar { + // Per the spec, the ed25519 secret key sk is expanded to + // (scalar_bytes, hash_prefix) = SHA-512(sk) + // where the two outputs are both 32 bytes. To use for signing, scalar_bytes must be + // clamped and reduced (see ExpandedSecretKey::from_bytes). We return the clamped and + // reduced form. + ExpandedSecretKey::from(&self.secret_key).scalar + } +} + +impl AsRef for SigningKey { + fn as_ref(&self) -> &VerifyingKey { + &self.verifying_key + } +} + +impl Debug for SigningKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("SigningKey") + .field("verifying_key", &self.verifying_key) + .finish_non_exhaustive() // avoids printing `secret_key` + } +} + +impl KeypairRef for SigningKey { + type VerifyingKey = VerifyingKey; +} + +impl Signer for SigningKey { + /// Sign a message with this signing key's secret key. + fn try_sign(&self, message: &[u8]) -> Result { + let expanded: ExpandedSecretKey = (&self.secret_key).into(); + Ok(expanded.raw_sign::(message, &self.verifying_key)) + } +} + +/// Equivalent to [`SigningKey::sign_prehashed`] with `context` set to [`None`]. +/// +/// # Note +/// +/// The RFC only permits SHA-512 to be used for prehashing. This function technically works, and is +/// probably safe to use, with any secure hash function with 512-bit digests, but anything outside +/// of SHA-512 is NOT specification-compliant. We expose [`crate::Sha512`] for user convenience. +#[cfg(feature = "digest")] +impl DigestSigner for SigningKey +where + D: Digest, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result { + self.sign_prehashed(msg_digest, None) + } +} + +/// Equivalent to [`SigningKey::sign_prehashed`] with `context` set to [`Some`] +/// containing `self.value()`. +/// +/// # Note +/// +/// The RFC only permits SHA-512 to be used for prehashing. This function technically works, and is +/// probably safe to use, with any secure hash function with 512-bit digests, but anything outside +/// of SHA-512 is NOT specification-compliant. We expose [`crate::Sha512`] for user convenience. +#[cfg(feature = "digest")] +impl DigestSigner for Context<'_, '_, SigningKey> +where + D: Digest, +{ + fn try_sign_digest(&self, msg_digest: D) -> Result { + self.key().sign_prehashed(msg_digest, Some(self.value())) + } +} + +impl Verifier for SigningKey { + /// Verify a signature on a message with this signing key's public key. + fn verify(&self, message: &[u8], signature: &Signature) -> Result<(), SignatureError> { + self.verifying_key.verify(message, signature) + } +} + +impl From for SigningKey { + #[inline] + fn from(secret: SecretKey) -> Self { + Self::from_bytes(&secret) + } +} + +impl From<&SecretKey> for SigningKey { + #[inline] + fn from(secret: &SecretKey) -> Self { + Self::from_bytes(secret) + } +} + +impl TryFrom<&[u8]> for SigningKey { + type Error = SignatureError; + + fn try_from(bytes: &[u8]) -> Result { + SecretKey::try_from(bytes) + .map(|bytes| Self::from_bytes(&bytes)) + .map_err(|_| { + InternalError::BytesLength { + name: "SecretKey", + length: SECRET_KEY_LENGTH, + } + .into() + }) + } +} + +impl ConstantTimeEq for SigningKey { + fn ct_eq(&self, other: &Self) -> Choice { + self.secret_key.ct_eq(&other.secret_key) + } +} + +impl PartialEq for SigningKey { + fn eq(&self, other: &Self) -> bool { + self.ct_eq(other).into() + } +} + +impl Eq for SigningKey {} + +#[cfg(feature = "zeroize")] +impl Drop for SigningKey { + fn drop(&mut self) { + self.secret_key.zeroize(); + } +} + +#[cfg(feature = "zeroize")] +impl ZeroizeOnDrop for SigningKey {} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl pkcs8::EncodePrivateKey for SigningKey { + fn to_pkcs8_der(&self) -> pkcs8::Result { + pkcs8::KeypairBytes::from(self).to_pkcs8_der() + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom for SigningKey { + type Error = pkcs8::Error; + + fn try_from(pkcs8_key: pkcs8::KeypairBytes) -> pkcs8::Result { + SigningKey::try_from(&pkcs8_key) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom<&pkcs8::KeypairBytes> for SigningKey { + type Error = pkcs8::Error; + + fn try_from(pkcs8_key: &pkcs8::KeypairBytes) -> pkcs8::Result { + let signing_key = SigningKey::from_bytes(&pkcs8_key.secret_key); + + // Validate the public key in the PKCS#8 document if present + if let Some(public_bytes) = &pkcs8_key.public_key { + let expected_verifying_key = VerifyingKey::from_bytes(public_bytes.as_ref()) + .map_err(|_| pkcs8::Error::KeyMalformed)?; + + if signing_key.verifying_key() != expected_verifying_key { + return Err(pkcs8::Error::KeyMalformed); + } + } + + Ok(signing_key) + } +} + +#[cfg(feature = "pkcs8")] +impl From for pkcs8::KeypairBytes { + fn from(signing_key: SigningKey) -> pkcs8::KeypairBytes { + pkcs8::KeypairBytes::from(&signing_key) + } +} + +#[cfg(feature = "pkcs8")] +impl From<&SigningKey> for pkcs8::KeypairBytes { + fn from(signing_key: &SigningKey) -> pkcs8::KeypairBytes { + pkcs8::KeypairBytes { + secret_key: signing_key.to_bytes(), + public_key: Some(pkcs8::PublicKeyBytes(signing_key.verifying_key.to_bytes())), + } + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for SigningKey { + type Error = pkcs8::Error; + + fn try_from(private_key: pkcs8::PrivateKeyInfo<'_>) -> pkcs8::Result { + pkcs8::KeypairBytes::try_from(private_key)?.try_into() + } +} + +#[cfg(feature = "serde")] +impl Serialize for SigningKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(&self.secret_key) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for SigningKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { + struct SigningKeyVisitor; + + impl<'de> serde::de::Visitor<'de> for SigningKeyVisitor { + type Value = SigningKey; + + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(formatter, concat!("An ed25519 signing (private) key")) + } + + fn visit_bytes(self, bytes: &[u8]) -> Result { + SigningKey::try_from(bytes).map_err(E::custom) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut bytes = [0u8; 32]; + #[allow(clippy::needless_range_loop)] + for i in 0..32 { + bytes[i] = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + + let remaining = (0..) + .map(|_| seq.next_element::()) + .take_while(|el| matches!(el, Ok(Some(_)))) + .count(); + + if remaining > 0 { + return Err(serde::de::Error::invalid_length( + 32 + remaining, + &"expected 32 bytes", + )); + } + + SigningKey::try_from(bytes).map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_bytes(SigningKeyVisitor) + } +} + +/// The spec-compliant way to define an expanded secret key. This computes `SHA512(sk)`, clamps the +/// first 32 bytes and uses it as a scalar, and uses the second 32 bytes as a domain separator for +/// hashing. +impl From<&SecretKey> for ExpandedSecretKey { + #[allow(clippy::unwrap_used)] + fn from(secret_key: &SecretKey) -> ExpandedSecretKey { + let hash = Sha512::default().chain_update(secret_key).finalize(); + ExpandedSecretKey::from_bytes(hash.as_ref()) + } +} + +// +// Signing functions. These are pub(crate) so that the `hazmat` module can use them +// + +impl ExpandedSecretKey { + /// The plain, non-prehashed, signing function for Ed25519. `CtxDigest` is the digest used to + /// calculate the pseudorandomness needed for signing. According to the spec, `CtxDigest = + /// Sha512`, and `self` is derived via the method defined in `impl From<&SigningKey> for + /// ExpandedSecretKey`. + /// + /// This definition is loose in its parameters so that end-users of the `hazmat` module can + /// change how the `ExpandedSecretKey` is calculated and which hash function to use. + #[allow(non_snake_case)] + #[inline(always)] + pub(crate) fn raw_sign( + &self, + message: &[u8], + verifying_key: &VerifyingKey, + ) -> Signature + where + CtxDigest: Digest, + { + let mut h = CtxDigest::new(); + + h.update(self.hash_prefix); + h.update(message); + + let r = Scalar::from_hash(h); + let R: CompressedEdwardsY = EdwardsPoint::mul_base(&r).compress(); + + h = CtxDigest::new(); + h.update(R.as_bytes()); + h.update(verifying_key.as_bytes()); + h.update(message); + + let k = Scalar::from_hash(h); + let s: Scalar = (k * self.scalar) + r; + + InternalSignature { R, s }.into() + } + + /// The prehashed signing function for Ed25519 (i.e., Ed25519ph). `CtxDigest` is the digest + /// function used to calculate the pseudorandomness needed for signing. `MsgDigest` is the + /// digest function used to hash the signed message. According to the spec, `MsgDigest = + /// CtxDigest = Sha512`, and `self` is derived via the method defined in `impl + /// From<&SigningKey> for ExpandedSecretKey`. + /// + /// This definition is loose in its parameters so that end-users of the `hazmat` module can + /// change how the `ExpandedSecretKey` is calculated and which `CtxDigest` function to use. + #[cfg(feature = "digest")] + #[allow(non_snake_case)] + #[inline(always)] + pub(crate) fn raw_sign_prehashed( + &self, + prehashed_message: MsgDigest, + verifying_key: &VerifyingKey, + context: Option<&[u8]>, + ) -> Result + where + CtxDigest: Digest, + MsgDigest: Digest, + { + let mut prehash: [u8; 64] = [0u8; 64]; + + let ctx: &[u8] = context.unwrap_or(b""); // By default, the context is an empty string. + + if ctx.len() > 255 { + return Err(SignatureError::from(InternalError::PrehashedContextLength)); + } + + let ctx_len: u8 = ctx.len() as u8; + + // Get the result of the pre-hashed message. + prehash.copy_from_slice(prehashed_message.finalize().as_slice()); + + // This is the dumbest, ten-years-late, non-admission of fucking up the + // domain separation I have ever seen. Why am I still required to put + // the upper half "prefix" of the hashed "secret key" in here? Why + // can't the user just supply their own nonce and decide for themselves + // whether or not they want a deterministic signature scheme? Why does + // the message go into what's ostensibly the signature domain separation + // hash? Why wasn't there always a way to provide a context string? + // + // ... + // + // This is a really fucking stupid bandaid, and the damned scheme is + // still bleeding from malleability, for fuck's sake. + let mut h = CtxDigest::new() + .chain_update(b"SigEd25519 no Ed25519 collisions") + .chain_update([1]) // Ed25519ph + .chain_update([ctx_len]) + .chain_update(ctx) + .chain_update(self.hash_prefix) + .chain_update(&prehash[..]); + + let r = Scalar::from_hash(h); + let R: CompressedEdwardsY = EdwardsPoint::mul_base(&r).compress(); + + h = CtxDigest::new() + .chain_update(b"SigEd25519 no Ed25519 collisions") + .chain_update([1]) // Ed25519ph + .chain_update([ctx_len]) + .chain_update(ctx) + .chain_update(R.as_bytes()) + .chain_update(verifying_key.as_bytes()) + .chain_update(&prehash[..]); + + let k = Scalar::from_hash(h); + let s: Scalar = (k * self.scalar) + r; + + Ok(InternalSignature { R, s }.into()) + } +} diff --git a/ed25519-dalek/src/verifying.rs b/ed25519-dalek/src/verifying.rs new file mode 100644 index 000000000..246951b44 --- /dev/null +++ b/ed25519-dalek/src/verifying.rs @@ -0,0 +1,684 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! ed25519 public keys. + +use core::fmt::Debug; +use core::hash::{Hash, Hasher}; + +use curve25519_dalek::{ + digest::{generic_array::typenum::U64, Digest}, + edwards::{CompressedEdwardsY, EdwardsPoint}, + montgomery::MontgomeryPoint, + scalar::Scalar, +}; + +use ed25519::signature::Verifier; + +use sha2::Sha512; + +#[cfg(feature = "pkcs8")] +use ed25519::pkcs8; + +#[cfg(feature = "serde")] +use serde::{Deserialize, Deserializer, Serialize, Serializer}; + +#[cfg(feature = "digest")] +use crate::context::Context; +#[cfg(feature = "digest")] +use signature::DigestVerifier; + +use crate::{ + constants::PUBLIC_KEY_LENGTH, + errors::{InternalError, SignatureError}, + hazmat::ExpandedSecretKey, + signature::InternalSignature, + signing::SigningKey, +}; + +/// An ed25519 public key. +/// +/// # Note +/// +/// The `Eq` and `Hash` impls here use the compressed Edwards y encoding, _not_ the algebraic +/// representation. This means if this `VerifyingKey` is non-canonically encoded, it will be +/// considered unequal to the other equivalent encoding, despite the two representing the same +/// point. More encoding details can be found +/// [here](https://hdevalence.ca/blog/2020-10-04-its-25519am). +/// If you want to make sure that signatures produced with respect to those sorts of public keys +/// are rejected, use [`VerifyingKey::verify_strict`]. +// Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 +#[derive(Copy, Clone, Default, Eq)] +pub struct VerifyingKey { + /// Serialized compressed Edwards-y point. + pub(crate) compressed: CompressedEdwardsY, + + /// Decompressed Edwards point used for curve arithmetic operations. + pub(crate) point: EdwardsPoint, +} + +impl Debug for VerifyingKey { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "VerifyingKey({:?}), {:?})", self.compressed, self.point) + } +} + +impl AsRef<[u8]> for VerifyingKey { + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +impl Hash for VerifyingKey { + fn hash(&self, state: &mut H) { + self.as_bytes().hash(state); + } +} + +impl PartialEq for VerifyingKey { + fn eq(&self, other: &VerifyingKey) -> bool { + self.as_bytes() == other.as_bytes() + } +} + +impl From<&ExpandedSecretKey> for VerifyingKey { + /// Derive this public key from its corresponding `ExpandedSecretKey`. + fn from(expanded_secret_key: &ExpandedSecretKey) -> VerifyingKey { + VerifyingKey::from(EdwardsPoint::mul_base(&expanded_secret_key.scalar)) + } +} + +impl From<&SigningKey> for VerifyingKey { + fn from(signing_key: &SigningKey) -> VerifyingKey { + signing_key.verifying_key() + } +} + +impl From for VerifyingKey { + fn from(point: EdwardsPoint) -> VerifyingKey { + VerifyingKey { + point, + compressed: point.compress(), + } + } +} + +impl VerifyingKey { + /// Convert this public key to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; PUBLIC_KEY_LENGTH] { + self.compressed.to_bytes() + } + + /// View this public key as a byte array. + #[inline] + pub fn as_bytes(&self) -> &[u8; PUBLIC_KEY_LENGTH] { + &(self.compressed).0 + } + + /// Construct a `VerifyingKey` from a slice of bytes. + /// + /// # Warning + /// + /// The caller is responsible for ensuring that the bytes passed into this + /// method actually represent a `curve25519_dalek::curve::CompressedEdwardsY` + /// and that said compressed point is actually a point on the curve. + /// + /// # Example + /// + /// ``` + /// use ed25519_dalek::VerifyingKey; + /// use ed25519_dalek::PUBLIC_KEY_LENGTH; + /// use ed25519_dalek::SignatureError; + /// + /// # fn doctest() -> Result { + /// let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = [ + /// 215, 90, 152, 1, 130, 177, 10, 183, 213, 75, 254, 211, 201, 100, 7, 58, + /// 14, 225, 114, 243, 218, 166, 35, 37, 175, 2, 26, 104, 247, 7, 81, 26]; + /// + /// let public_key = VerifyingKey::from_bytes(&public_key_bytes)?; + /// # + /// # Ok(public_key) + /// # } + /// # + /// # fn main() { + /// # doctest(); + /// # } + /// ``` + /// + /// # Returns + /// + /// A `Result` whose okay value is an EdDSA `VerifyingKey` or whose error value + /// is a `SignatureError` describing the error that occurred. + #[inline] + pub fn from_bytes(bytes: &[u8; PUBLIC_KEY_LENGTH]) -> Result { + let compressed = CompressedEdwardsY(*bytes); + let point = compressed + .decompress() + .ok_or(InternalError::PointDecompression)?; + + // Invariant: VerifyingKey.1 is always the decompression of VerifyingKey.0 + Ok(VerifyingKey { compressed, point }) + } + + /// Create a verifying context that can be used for Ed25519ph with + /// [`DigestVerifier`]. + #[cfg(feature = "digest")] + pub fn with_context<'k, 'v>( + &'k self, + context_value: &'v [u8], + ) -> Result, SignatureError> { + Context::new(self, context_value) + } + + /// Returns whether this is a _weak_ public key, i.e., if this public key has low order. + /// + /// A weak public key can be used to generate a signature that's valid for almost every + /// message. [`Self::verify_strict`] denies weak keys, but if you want to check for this + /// property before verification, then use this method. + pub fn is_weak(&self) -> bool { + self.point.is_small_order() + } + + // A helper function that computes `H(R || A || M)` where `H` is the 512-bit hash function + // given by `CtxDigest` (this is SHA-512 in spec-compliant Ed25519). If `context.is_some()`, + // this does the prehashed variant of the computation using its contents. + #[allow(non_snake_case)] + fn compute_challenge( + context: Option<&[u8]>, + R: &CompressedEdwardsY, + A: &CompressedEdwardsY, + M: &[u8], + ) -> Scalar + where + CtxDigest: Digest, + { + let mut h = CtxDigest::new(); + if let Some(c) = context { + h.update(b"SigEd25519 no Ed25519 collisions"); + h.update([1]); // Ed25519ph + h.update([c.len() as u8]); + h.update(c); + } + h.update(R.as_bytes()); + h.update(A.as_bytes()); + h.update(M); + + Scalar::from_hash(h) + } + + // Helper function for verification. Computes the _expected_ R component of the signature. The + // caller compares this to the real R component. If `context.is_some()`, this does the + // prehashed variant of the computation using its contents. + // Note that this returns the compressed form of R and the caller does a byte comparison. This + // means that all our verification functions do not accept non-canonically encoded R values. + // See the validation criteria blog post for more details: + // https://hdevalence.ca/blog/2020-10-04-its-25519am + #[allow(non_snake_case)] + fn recompute_R( + &self, + context: Option<&[u8]>, + signature: &InternalSignature, + M: &[u8], + ) -> CompressedEdwardsY + where + CtxDigest: Digest, + { + let k = Self::compute_challenge::(context, &signature.R, &self.compressed, M); + let minus_A: EdwardsPoint = -self.point; + // Recall the (non-batched) verification equation: -[k]A + [s]B = R + EdwardsPoint::vartime_double_scalar_mul_basepoint(&k, &(minus_A), &signature.s).compress() + } + + /// The ordinary non-batched Ed25519 verification check, rejecting non-canonical R values. (see + /// [`Self::recompute_R`]). `CtxDigest` is the digest used to calculate the pseudorandomness + /// needed for signing. According to the spec, `CtxDigest = Sha512`. + /// + /// This definition is loose in its parameters so that end-users of the `hazmat` module can + /// change how the `ExpandedSecretKey` is calculated and which hash function to use. + #[allow(non_snake_case)] + pub(crate) fn raw_verify( + &self, + message: &[u8], + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + CtxDigest: Digest, + { + let signature = InternalSignature::try_from(signature)?; + + let expected_R = self.recompute_R::(None, &signature, message); + if expected_R == signature.R { + Ok(()) + } else { + Err(InternalError::Verify.into()) + } + } + + /// The prehashed non-batched Ed25519 verification check, rejecting non-canonical R values. + /// (see [`Self::recompute_R`]). `CtxDigest` is the digest used to calculate the + /// pseudorandomness needed for signing. `MsgDigest` is the digest used to hash the signed + /// message. According to the spec, `MsgDigest = CtxDigest = Sha512`. + /// + /// This definition is loose in its parameters so that end-users of the `hazmat` module can + /// change how the `ExpandedSecretKey` is calculated and which hash function to use. + #[cfg(feature = "digest")] + #[allow(non_snake_case)] + pub(crate) fn raw_verify_prehashed( + &self, + prehashed_message: MsgDigest, + context: Option<&[u8]>, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + CtxDigest: Digest, + MsgDigest: Digest, + { + let signature = InternalSignature::try_from(signature)?; + + let ctx: &[u8] = context.unwrap_or(b""); + debug_assert!( + ctx.len() <= 255, + "The context must not be longer than 255 octets." + ); + + let message = prehashed_message.finalize(); + let expected_R = self.recompute_R::(Some(ctx), &signature, &message); + + if expected_R == signature.R { + Ok(()) + } else { + Err(InternalError::Verify.into()) + } + } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph signature on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// [`SigningKey`] on the `prehashed_message`. + /// + /// # Note + /// + /// The RFC only permits SHA-512 to be used for prehashing, i.e., `MsgDigest = Sha512`. This + /// function technically works, and is probably safe to use, with any secure hash function with + /// 512-bit digests, but anything outside of SHA-512 is NOT specification-compliant. We expose + /// [`crate::Sha512`] for user convenience. + #[cfg(feature = "digest")] + #[allow(non_snake_case)] + pub fn verify_prehashed( + &self, + prehashed_message: MsgDigest, + context: Option<&[u8]>, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + MsgDigest: Digest, + { + self.raw_verify_prehashed::(prehashed_message, context, signature) + } + + /// Strictly verify a signature on a message with this keypair's public key. + /// + /// # On The (Multiple) Sources of Malleability in Ed25519 Signatures + /// + /// This version of verification is technically non-RFC8032 compliant. The + /// following explains why. + /// + /// 1. Scalar Malleability + /// + /// The authors of the RFC explicitly stated that verification of an ed25519 + /// signature must fail if the scalar `s` is not properly reduced mod $\ell$: + /// + /// > To verify a signature on a message M using public key A, with F + /// > being 0 for Ed25519ctx, 1 for Ed25519ph, and if Ed25519ctx or + /// > Ed25519ph is being used, C being the context, first split the + /// > signature into two 32-octet halves. Decode the first half as a + /// > point R, and the second half as an integer S, in the range + /// > 0 <= s < L. Decode the public key A as point A'. If any of the + /// > decodings fail (including S being out of range), the signature is + /// > invalid.) + /// + /// All `verify_*()` functions within ed25519-dalek perform this check. + /// + /// 2. Point malleability + /// + /// The authors of the RFC added in a malleability check to step #3 in + /// §5.1.7, for small torsion components in the `R` value of the signature, + /// *which is not strictly required*, as they state: + /// + /// > Check the group equation \[8\]\[S\]B = \[8\]R + \[8\]\[k\]A'. It's + /// > sufficient, but not required, to instead check \[S\]B = R + \[k\]A'. + /// + /// # History of Malleability Checks + /// + /// As originally defined (cf. the "Malleability" section in the README of + /// this repo), ed25519 signatures didn't consider *any* form of + /// malleability to be an issue. Later the scalar malleability was + /// considered important. Still later, particularly with interests in + /// cryptocurrency design and in unique identities (e.g. for Signal users, + /// Tor onion services, etc.), the group element malleability became a + /// concern. + /// + /// However, libraries had already been created to conform to the original + /// definition. One well-used library in particular even implemented the + /// group element malleability check, *but only for batch verification*! + /// Which meant that even using the same library, a single signature could + /// verify fine individually, but suddenly, when verifying it with a bunch + /// of other signatures, the whole batch would fail! + /// + /// # "Strict" Verification + /// + /// This method performs *both* of the above signature malleability checks. + /// + /// It must be done as a separate method because one doesn't simply get to + /// change the definition of a cryptographic primitive ten years + /// after-the-fact with zero consideration for backwards compatibility in + /// hardware and protocols which have it already have the older definition + /// baked in. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + #[allow(non_snake_case)] + pub fn verify_strict( + &self, + message: &[u8], + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + let signature = InternalSignature::try_from(signature)?; + + let signature_R = signature + .R + .decompress() + .ok_or_else(|| SignatureError::from(InternalError::Verify))?; + + // Logical OR is fine here as we're not trying to be constant time. + if signature_R.is_small_order() || self.point.is_small_order() { + return Err(InternalError::Verify.into()); + } + + let expected_R = self.recompute_R::(None, &signature, message); + if expected_R == signature.R { + Ok(()) + } else { + Err(InternalError::Verify.into()) + } + } + + /// Verify a `signature` on a `prehashed_message` using the Ed25519ph algorithm, + /// using strict signture checking as defined by [`Self::verify_strict`]. + /// + /// # Inputs + /// + /// * `prehashed_message` is an instantiated hash digest with 512-bits of + /// output which has had the message to be signed previously fed into its + /// state. + /// * `context` is an optional context string, up to 255 bytes inclusive, + /// which may be used to provide additional domain separation. If not + /// set, this will default to an empty string. + /// * `signature` is a purported Ed25519ph signature on the `prehashed_message`. + /// + /// # Returns + /// + /// Returns `true` if the `signature` was a valid signature created by this + /// [`SigningKey`] on the `prehashed_message`. + /// + /// # Note + /// + /// The RFC only permits SHA-512 to be used for prehashing, i.e., `MsgDigest = Sha512`. This + /// function technically works, and is probably safe to use, with any secure hash function with + /// 512-bit digests, but anything outside of SHA-512 is NOT specification-compliant. We expose + /// [`crate::Sha512`] for user convenience. + #[cfg(feature = "digest")] + #[allow(non_snake_case)] + pub fn verify_prehashed_strict( + &self, + prehashed_message: MsgDigest, + context: Option<&[u8]>, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> + where + MsgDigest: Digest, + { + let signature = InternalSignature::try_from(signature)?; + + let ctx: &[u8] = context.unwrap_or(b""); + debug_assert!( + ctx.len() <= 255, + "The context must not be longer than 255 octets." + ); + + let signature_R = signature + .R + .decompress() + .ok_or_else(|| SignatureError::from(InternalError::Verify))?; + + // Logical OR is fine here as we're not trying to be constant time. + if signature_R.is_small_order() || self.point.is_small_order() { + return Err(InternalError::Verify.into()); + } + + let message = prehashed_message.finalize(); + let expected_R = self.recompute_R::(Some(ctx), &signature, &message); + + if expected_R == signature.R { + Ok(()) + } else { + Err(InternalError::Verify.into()) + } + } + + /// Convert this verifying key into Montgomery form. + /// + /// This can be used for performing X25519 Diffie-Hellman using Ed25519 keys. The output of + /// this function is a valid X25519 public key whose secret key is `sk.to_scalar_bytes()`, + /// where `sk` is a valid signing key for this `VerifyingKey`. + /// + /// # Note + /// + /// We do NOT recommend this usage of a signing/verifying key. Signing keys are usually + /// long-term keys, while keys used for key exchange should rather be ephemeral. If you can + /// help it, use a separate key for encryption. + /// + /// For more information on the security of systems which use the same keys for both signing + /// and Diffie-Hellman, see the paper + /// [On using the same key pair for Ed25519 and an X25519 based KEM](https://eprint.iacr.org/2021/509). + pub fn to_montgomery(&self) -> MontgomeryPoint { + self.point.to_montgomery() + } + + /// Return this verifying key in Edwards form. + pub fn to_edwards(&self) -> EdwardsPoint { + self.point + } +} + +impl Verifier for VerifyingKey { + /// Verify a signature on a message with this keypair's public key. + /// + /// # Return + /// + /// Returns `Ok(())` if the signature is valid, and `Err` otherwise. + fn verify(&self, message: &[u8], signature: &ed25519::Signature) -> Result<(), SignatureError> { + self.raw_verify::(message, signature) + } +} + +/// Equivalent to [`VerifyingKey::verify_prehashed`] with `context` set to [`None`]. +#[cfg(feature = "digest")] +impl DigestVerifier for VerifyingKey +where + MsgDigest: Digest, +{ + fn verify_digest( + &self, + msg_digest: MsgDigest, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + self.verify_prehashed(msg_digest, None, signature) + } +} + +/// Equivalent to [`VerifyingKey::verify_prehashed`] with `context` set to [`Some`] +/// containing `self.value()`. +#[cfg(feature = "digest")] +impl DigestVerifier for Context<'_, '_, VerifyingKey> +where + MsgDigest: Digest, +{ + fn verify_digest( + &self, + msg_digest: MsgDigest, + signature: &ed25519::Signature, + ) -> Result<(), SignatureError> { + self.key() + .verify_prehashed(msg_digest, Some(self.value()), signature) + } +} + +impl TryFrom<&[u8]> for VerifyingKey { + type Error = SignatureError; + + #[inline] + fn try_from(bytes: &[u8]) -> Result { + let bytes = bytes.try_into().map_err(|_| InternalError::BytesLength { + name: "VerifyingKey", + length: PUBLIC_KEY_LENGTH, + })?; + Self::from_bytes(bytes) + } +} + +impl From for EdwardsPoint { + fn from(vk: VerifyingKey) -> EdwardsPoint { + vk.point + } +} + +#[cfg(all(feature = "alloc", feature = "pkcs8"))] +impl pkcs8::EncodePublicKey for VerifyingKey { + fn to_public_key_der(&self) -> pkcs8::spki::Result { + pkcs8::PublicKeyBytes::from(self).to_public_key_der() + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom for VerifyingKey { + type Error = pkcs8::spki::Error; + + fn try_from(pkcs8_key: pkcs8::PublicKeyBytes) -> pkcs8::spki::Result { + VerifyingKey::try_from(&pkcs8_key) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom<&pkcs8::PublicKeyBytes> for VerifyingKey { + type Error = pkcs8::spki::Error; + + fn try_from(pkcs8_key: &pkcs8::PublicKeyBytes) -> pkcs8::spki::Result { + VerifyingKey::from_bytes(pkcs8_key.as_ref()).map_err(|_| pkcs8::spki::Error::KeyMalformed) + } +} + +#[cfg(feature = "pkcs8")] +impl From for pkcs8::PublicKeyBytes { + fn from(verifying_key: VerifyingKey) -> pkcs8::PublicKeyBytes { + pkcs8::PublicKeyBytes::from(&verifying_key) + } +} + +#[cfg(feature = "pkcs8")] +impl From<&VerifyingKey> for pkcs8::PublicKeyBytes { + fn from(verifying_key: &VerifyingKey) -> pkcs8::PublicKeyBytes { + pkcs8::PublicKeyBytes(verifying_key.to_bytes()) + } +} + +#[cfg(feature = "pkcs8")] +impl TryFrom> for VerifyingKey { + type Error = pkcs8::spki::Error; + + fn try_from(public_key: pkcs8::spki::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result { + pkcs8::PublicKeyBytes::try_from(public_key)?.try_into() + } +} + +#[cfg(feature = "serde")] +impl Serialize for VerifyingKey { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + serializer.serialize_bytes(&self.as_bytes()[..]) + } +} + +#[cfg(feature = "serde")] +impl<'d> Deserialize<'d> for VerifyingKey { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'d>, + { + struct VerifyingKeyVisitor; + + impl<'de> serde::de::Visitor<'de> for VerifyingKeyVisitor { + type Value = VerifyingKey; + + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(formatter, concat!("An ed25519 verifying (public) key")) + } + + fn visit_bytes(self, bytes: &[u8]) -> Result { + VerifyingKey::try_from(bytes).map_err(E::custom) + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let mut bytes = [0u8; 32]; + + #[allow(clippy::needless_range_loop)] + for i in 0..32 { + bytes[i] = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(i, &"expected 32 bytes"))?; + } + + let remaining = (0..) + .map(|_| seq.next_element::()) + .take_while(|el| matches!(el, Ok(Some(_)))) + .count(); + + if remaining > 0 { + return Err(serde::de::Error::invalid_length( + 32 + remaining, + &"expected 32 bytes", + )); + } + + VerifyingKey::try_from(&bytes[..]).map_err(serde::de::Error::custom) + } + } + + deserializer.deserialize_bytes(VerifyingKeyVisitor) + } +} diff --git a/ed25519-dalek/tests/ed25519.rs b/ed25519-dalek/tests/ed25519.rs new file mode 100644 index 000000000..edab8a814 --- /dev/null +++ b/ed25519-dalek/tests/ed25519.rs @@ -0,0 +1,679 @@ +// -*- mode: rust; -*- +// +// This file is part of ed25519-dalek. +// Copyright (c) 2017-2019 isis lovecruft +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft + +//! Integration tests for ed25519-dalek. + +#![allow(clippy::items_after_test_module)] + +use ed25519_dalek::*; + +use hex::FromHex; +#[cfg(feature = "digest")] +use hex_literal::hex; + +#[cfg(test)] +mod vectors { + use super::*; + + use curve25519_dalek::{ + constants::ED25519_BASEPOINT_POINT, + edwards::{CompressedEdwardsY, EdwardsPoint}, + scalar::Scalar, + traits::IsIdentity, + }; + + #[cfg(not(feature = "digest"))] + use sha2::{digest::Digest, Sha512}; + + use std::{ + fs::File, + io::{BufRead, BufReader}, + ops::Neg, + }; + + // TESTVECTORS is taken from sign.input.gz in agl's ed25519 Golang + // package. It is a selection of test cases from + // http://ed25519.cr.yp.to/python/sign.input + #[test] + fn against_reference_implementation() { + // TestGolden + let mut line: String; + let mut lineno: usize = 0; + + let f = File::open("TESTVECTORS"); + if f.is_err() { + println!( + "This test is only available when the code has been cloned \ + from the git repository, since the TESTVECTORS file is large \ + and is therefore not included within the distributed crate." + ); + panic!(); + } + let file = BufReader::new(f.unwrap()); + + for l in file.lines() { + lineno += 1; + line = l.unwrap(); + + let parts: Vec<&str> = line.split(':').collect(); + assert_eq!(parts.len(), 5, "wrong number of fields in line {}", lineno); + + let sec_bytes: Vec = FromHex::from_hex(parts[0]).unwrap(); + let pub_bytes: Vec = FromHex::from_hex(parts[1]).unwrap(); + let msg_bytes: Vec = FromHex::from_hex(parts[2]).unwrap(); + let sig_bytes: Vec = FromHex::from_hex(parts[3]).unwrap(); + + let sec_bytes = &sec_bytes[..SECRET_KEY_LENGTH].try_into().unwrap(); + let pub_bytes = &pub_bytes[..PUBLIC_KEY_LENGTH].try_into().unwrap(); + + let signing_key = SigningKey::from_bytes(sec_bytes); + let expected_verifying_key = VerifyingKey::from_bytes(pub_bytes).unwrap(); + assert_eq!(expected_verifying_key, signing_key.verifying_key()); + + // The signatures in the test vectors also include the message + // at the end, but we just want R and S. + let sig1: Signature = Signature::try_from(&sig_bytes[..64]).unwrap(); + let sig2: Signature = signing_key.sign(&msg_bytes); + + assert!(sig1 == sig2, "Signature bytes not equal on line {}", lineno); + assert!( + signing_key.verify(&msg_bytes, &sig2).is_ok(), + "Signature verification failed on line {}", + lineno + ); + assert!( + expected_verifying_key + .verify_strict(&msg_bytes, &sig2) + .is_ok(), + "Signature strict verification failed on line {}", + lineno + ); + } + } + + // From https://tools.ietf.org/html/rfc8032#section-7.3 + #[cfg(feature = "digest")] + #[test] + fn ed25519ph_rf8032_test_vector_prehash() { + let sec_bytes = hex!("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"); + let pub_bytes = hex!("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"); + let msg_bytes = hex!("616263"); + let sig_bytes = hex!("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406"); + + let signing_key = SigningKey::from_bytes(&sec_bytes); + let expected_verifying_key = VerifyingKey::from_bytes(&pub_bytes).unwrap(); + assert_eq!(expected_verifying_key, signing_key.verifying_key()); + let sig1 = Signature::try_from(&sig_bytes[..]).unwrap(); + + let mut prehash_for_signing = Sha512::default(); + let mut prehash_for_verifying = Sha512::default(); + + prehash_for_signing.update(&msg_bytes[..]); + prehash_for_verifying.update(&msg_bytes[..]); + + let sig2: Signature = signing_key + .sign_prehashed(prehash_for_signing, None) + .unwrap(); + + assert!( + sig1 == sig2, + "Original signature from test vectors doesn't equal signature produced:\ + \noriginal:\n{:?}\nproduced:\n{:?}", + sig1, + sig2 + ); + assert!( + signing_key + .verify_prehashed(prehash_for_verifying.clone(), None, &sig2) + .is_ok(), + "Could not verify ed25519ph signature!" + ); + assert!( + expected_verifying_key + .verify_prehashed_strict(prehash_for_verifying, None, &sig2) + .is_ok(), + "Could not strict-verify ed25519ph signature!" + ); + } + + // + // The remaining items in this mod are for the repudiation tests + // + + // Taken from curve25519_dalek::constants::EIGHT_TORSION[4] + const EIGHT_TORSION_4: [u8; 32] = [ + 236, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, + ]; + + // Computes the prehashed or non-prehashed challenge, depending on whether context is given + fn compute_challenge( + message: &[u8], + pub_key: &EdwardsPoint, + signature_r: &EdwardsPoint, + context: Option<&[u8]>, + ) -> Scalar { + let mut h = Sha512::default(); + if let Some(c) = context { + h.update(b"SigEd25519 no Ed25519 collisions"); + h.update([1]); + h.update([c.len() as u8]); + h.update(c); + } + h.update(signature_r.compress().as_bytes()); + h.update(&pub_key.compress().as_bytes()[..]); + h.update(message); + Scalar::from_hash(h) + } + + fn serialize_signature(r: &EdwardsPoint, s: &Scalar) -> Vec { + [&r.compress().as_bytes()[..], &s.as_bytes()[..]].concat() + } + + const WEAK_PUBKEY: CompressedEdwardsY = CompressedEdwardsY(EIGHT_TORSION_4); + + // Pick a random Scalar + fn non_null_scalar() -> Scalar { + let mut rng = rand::rngs::OsRng; + let mut s_candidate = Scalar::random(&mut rng); + while s_candidate == Scalar::ZERO { + s_candidate = Scalar::random(&mut rng); + } + s_candidate + } + + fn pick_r(s: Scalar) -> EdwardsPoint { + let r0 = s * ED25519_BASEPOINT_POINT; + // Pick a torsion point of order 2 + r0 + WEAK_PUBKEY.decompress().unwrap().neg() + } + + // Tests that verify_strict() rejects small-order pubkeys. We test this by explicitly + // constructing a pubkey-signature pair that verifies with respect to two distinct messages. + // This should be accepted by verify(), but rejected by verify_strict(). + #[test] + fn repudiation() { + let message1 = b"Send 100 USD to Alice"; + let message2 = b"Send 100000 USD to Alice"; + + let mut s: Scalar = non_null_scalar(); + let pubkey = WEAK_PUBKEY.decompress().unwrap(); + let mut r = pick_r(s); + + // Find an R such that + // H(R || A || M₁) · A == A == H(R || A || M₂) · A + // This happens with high probability when A is low order. + while !(pubkey.neg() + compute_challenge(message1, &pubkey, &r, None) * pubkey) + .is_identity() + || !(pubkey.neg() + compute_challenge(message2, &pubkey, &r, None) * pubkey) + .is_identity() + { + // We pick an s and let R = sB - A where B is the basepoint + s = non_null_scalar(); + r = pick_r(s); + } + + // At this point, both verification equations hold: + // sB = R + H(R || A || M₁) · A + // = R + H(R || A || M₂) · A + // Check that this is true + let signature = serialize_signature(&r, &s); + let vk = VerifyingKey::from_bytes(pubkey.compress().as_bytes()).unwrap(); + let sig = Signature::try_from(&signature[..]).unwrap(); + assert!(vk.verify(message1, &sig).is_ok()); + assert!(vk.verify(message2, &sig).is_ok()); + + // Check that this public key appears as weak + assert!(vk.is_weak()); + + // Now check that the sigs fail under verify_strict. This is because verify_strict rejects + // small order pubkeys. + assert!(vk.verify_strict(message1, &sig).is_err()); + assert!(vk.verify_strict(message2, &sig).is_err()); + } + + // Identical to repudiation() above, but testing verify_prehashed against + // verify_prehashed_strict. See comments above for a description of what's happening. + #[cfg(feature = "digest")] + #[test] + fn repudiation_prehash() { + let message1 = Sha512::new().chain_update(b"Send 100 USD to Alice"); + let message2 = Sha512::new().chain_update(b"Send 100000 USD to Alice"); + let message1_bytes = message1.clone().finalize(); + let message2_bytes = message2.clone().finalize(); + + let mut s: Scalar = non_null_scalar(); + let pubkey = WEAK_PUBKEY.decompress().unwrap(); + let mut r = pick_r(s); + let context_str = Some(&b"edtest"[..]); + + while !(pubkey.neg() + + compute_challenge(&message1_bytes, &pubkey, &r, context_str) * pubkey) + .is_identity() + || !(pubkey.neg() + + compute_challenge(&message2_bytes, &pubkey, &r, context_str) * pubkey) + .is_identity() + { + s = non_null_scalar(); + r = pick_r(s); + } + + // Check that verify_prehashed succeeds on both sigs + let signature = serialize_signature(&r, &s); + let vk = VerifyingKey::from_bytes(pubkey.compress().as_bytes()).unwrap(); + let sig = Signature::try_from(&signature[..]).unwrap(); + assert!(vk + .verify_prehashed(message1.clone(), context_str, &sig) + .is_ok()); + assert!(vk + .verify_prehashed(message2.clone(), context_str, &sig) + .is_ok()); + + // Check that verify_prehashed_strict fails on both sigs + assert!(vk + .verify_prehashed_strict(message1.clone(), context_str, &sig) + .is_err()); + assert!(vk + .verify_prehashed_strict(message2.clone(), context_str, &sig) + .is_err()); + } +} + +#[cfg(feature = "rand_core")] +mod integrations { + use super::*; + use rand::rngs::OsRng; + use std::collections::HashMap; + + #[test] + fn sign_verify() { + // TestSignVerify + + let good: &[u8] = "test message".as_bytes(); + let bad: &[u8] = "wrong message".as_bytes(); + + let mut csprng = OsRng; + + let signing_key: SigningKey = SigningKey::generate(&mut csprng); + let verifying_key = signing_key.verifying_key(); + let good_sig: Signature = signing_key.sign(good); + let bad_sig: Signature = signing_key.sign(bad); + + // Check that an honestly generated public key is not weak + assert!(!verifying_key.is_weak()); + + assert!( + signing_key.verify(good, &good_sig).is_ok(), + "Verification of a valid signature failed!" + ); + assert!( + verifying_key.verify_strict(good, &good_sig).is_ok(), + "Strict verification of a valid signature failed!" + ); + assert!( + signing_key.verify(good, &bad_sig).is_err(), + "Verification of a signature on a different message passed!" + ); + assert!( + verifying_key.verify_strict(good, &bad_sig).is_err(), + "Strict verification of a signature on a different message passed!" + ); + assert!( + signing_key.verify(bad, &good_sig).is_err(), + "Verification of a signature on a different message passed!" + ); + assert!( + verifying_key.verify_strict(bad, &good_sig).is_err(), + "Strict verification of a signature on a different message passed!" + ); + } + + #[cfg(feature = "digest")] + #[test] + fn ed25519ph_sign_verify() { + let good: &[u8] = b"test message"; + let bad: &[u8] = b"wrong message"; + + let mut csprng = OsRng; + + // ugh… there's no `impl Copy for Sha512`… i hope we can all agree these are the same hashes + let mut prehashed_good1: Sha512 = Sha512::default(); + prehashed_good1.update(good); + let mut prehashed_good2: Sha512 = Sha512::default(); + prehashed_good2.update(good); + let mut prehashed_good3: Sha512 = Sha512::default(); + prehashed_good3.update(good); + + let mut prehashed_bad1: Sha512 = Sha512::default(); + prehashed_bad1.update(bad); + let mut prehashed_bad2: Sha512 = Sha512::default(); + prehashed_bad2.update(bad); + + let context: &[u8] = b"testing testing 1 2 3"; + + let signing_key: SigningKey = SigningKey::generate(&mut csprng); + let verifying_key = signing_key.verifying_key(); + let good_sig: Signature = signing_key + .sign_prehashed(prehashed_good1, Some(context)) + .unwrap(); + let bad_sig: Signature = signing_key + .sign_prehashed(prehashed_bad1, Some(context)) + .unwrap(); + + assert!( + signing_key + .verify_prehashed(prehashed_good2.clone(), Some(context), &good_sig) + .is_ok(), + "Verification of a valid signature failed!" + ); + assert!( + verifying_key + .verify_prehashed_strict(prehashed_good2, Some(context), &good_sig) + .is_ok(), + "Strict verification of a valid signature failed!" + ); + assert!( + signing_key + .verify_prehashed(prehashed_good3.clone(), Some(context), &bad_sig) + .is_err(), + "Verification of a signature on a different message passed!" + ); + assert!( + verifying_key + .verify_prehashed_strict(prehashed_good3, Some(context), &bad_sig) + .is_err(), + "Strict verification of a signature on a different message passed!" + ); + assert!( + signing_key + .verify_prehashed(prehashed_bad2.clone(), Some(context), &good_sig) + .is_err(), + "Verification of a signature on a different message passed!" + ); + assert!( + verifying_key + .verify_prehashed_strict(prehashed_bad2, Some(context), &good_sig) + .is_err(), + "Strict verification of a signature on a different message passed!" + ); + } + + #[cfg(feature = "batch")] + #[test] + fn verify_batch_seven_signatures() { + let messages: [&[u8]; 7] = [ + b"Watch closely everyone, I'm going to show you how to kill a god.", + b"I'm not a cryptographer I just encrypt a lot.", + b"Still not a cryptographer.", + b"This is a test of the tsunami alert system. This is only a test.", + b"Fuck dumbin' it down, spit ice, skip jewellery: Molotov cocktails on me like accessories.", + b"Hey, I never cared about your bucks, so if I run up with a mask on, probably got a gas can too.", + b"And I'm not here to fill 'er up. Nope, we came to riot, here to incite, we don't want any of your stuff.", ]; + let mut csprng = OsRng; + let mut signing_keys: Vec = Vec::new(); + let mut signatures: Vec = Vec::new(); + + for msg in messages { + let signing_key: SigningKey = SigningKey::generate(&mut csprng); + signatures.push(signing_key.sign(msg)); + signing_keys.push(signing_key); + } + let verifying_keys: Vec = + signing_keys.iter().map(|key| key.verifying_key()).collect(); + + let result = verify_batch(&messages, &signatures, &verifying_keys); + + assert!(result.is_ok()); + } + + #[test] + fn public_key_hash_trait_check() { + let mut csprng = OsRng {}; + let secret: SigningKey = SigningKey::generate(&mut csprng); + let public_from_secret: VerifyingKey = (&secret).into(); + + let mut m = HashMap::new(); + m.insert(public_from_secret, "Example_Public_Key"); + + m.insert(public_from_secret, "Updated Value"); + + let (k, &v) = m.get_key_value(&public_from_secret).unwrap(); + assert_eq!(k, &public_from_secret); + assert_eq!(v, "Updated Value"); + assert_eq!(m.len(), 1usize); + + let second_secret: SigningKey = SigningKey::generate(&mut csprng); + let public_from_second_secret: VerifyingKey = (&second_secret).into(); + assert_ne!(public_from_secret, public_from_second_secret); + m.insert(public_from_second_secret, "Second public key"); + + let (k, &v) = m.get_key_value(&public_from_second_secret).unwrap(); + assert_eq!(k, &public_from_second_secret); + assert_eq!(v, "Second public key"); + assert_eq!(m.len(), 2usize); + } + + #[test] + fn montgomery_and_edwards_conversion() { + let mut rng = rand::rngs::OsRng; + let signing_key = SigningKey::generate(&mut rng); + let verifying_key = signing_key.verifying_key(); + + let ed = verifying_key.to_edwards(); + + // Check that to_edwards and From return same result: + assert_eq!(ed, curve25519_dalek::EdwardsPoint::from(verifying_key)); + + // The verifying key serialization is simply the compressed Edwards point + assert_eq!(verifying_key.to_bytes(), ed.compress().0); + + // Check that modulo sign, to_montgomery().to_edwards() returns the original point + let monty = verifying_key.to_montgomery(); + let via_monty0 = monty.to_edwards(0).unwrap(); + let via_monty1 = monty.to_edwards(1).unwrap(); + + assert!(via_monty0 != via_monty1); + assert!(ed == via_monty0 || ed == via_monty1); + } +} + +#[cfg(all(test, feature = "serde"))] +#[derive(Debug, serde::Serialize, serde::Deserialize)] +#[serde(crate = "serde")] +struct Demo { + signing_key: SigningKey, +} + +#[cfg(all(test, feature = "serde"))] +mod serialisation { + #![allow(clippy::zero_prefixed_literal)] + + use super::*; + + // The size for bincode to serialize the length of a byte array. + static BINCODE_INT_LENGTH: usize = 8; + + static PUBLIC_KEY_BYTES: [u8; PUBLIC_KEY_LENGTH] = [ + 130, 039, 155, 015, 062, 076, 188, 063, 124, 122, 026, 251, 233, 253, 225, 220, 014, 041, + 166, 120, 108, 035, 254, 077, 160, 083, 172, 058, 219, 042, 086, 120, + ]; + + static SECRET_KEY_BYTES: [u8; SECRET_KEY_LENGTH] = [ + 062, 070, 027, 163, 092, 182, 011, 003, 077, 234, 098, 004, 011, 127, 079, 228, 243, 187, + 150, 073, 201, 137, 076, 022, 085, 251, 152, 002, 241, 042, 072, 054, + ]; + + /// Signature with the above signing_key of a blank message. + static SIGNATURE_BYTES: [u8; SIGNATURE_LENGTH] = [ + 010, 126, 151, 143, 157, 064, 047, 001, 196, 140, 179, 058, 226, 152, 018, 102, 160, 123, + 080, 016, 210, 086, 196, 028, 053, 231, 012, 157, 169, 019, 158, 063, 045, 154, 238, 007, + 053, 185, 227, 229, 079, 108, 213, 080, 124, 252, 084, 167, 216, 085, 134, 144, 129, 149, + 041, 081, 063, 120, 126, 100, 092, 059, 050, 011, + ]; + + #[test] + fn serialize_deserialize_signature_bincode() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES); + let encoded_signature: Vec = bincode::serialize(&signature).unwrap(); + let decoded_signature: Signature = bincode::deserialize(&encoded_signature).unwrap(); + + assert_eq!(signature, decoded_signature); + } + + #[test] + fn serialize_deserialize_signature_json() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES); + let encoded_signature = serde_json::to_string(&signature).unwrap(); + let decoded_signature: Signature = serde_json::from_str(&encoded_signature).unwrap(); + + assert_eq!(signature, decoded_signature); + } + + #[test] + fn serialize_deserialize_verifying_key_bincode() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_verifying_key: Vec = bincode::serialize(&verifying_key).unwrap(); + let decoded_verifying_key: VerifyingKey = + bincode::deserialize(&encoded_verifying_key).unwrap(); + + assert_eq!( + &PUBLIC_KEY_BYTES[..], + &encoded_verifying_key[encoded_verifying_key.len() - PUBLIC_KEY_LENGTH..] + ); + assert_eq!(verifying_key, decoded_verifying_key); + } + + #[test] + fn serialize_deserialize_verifying_key_json() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + let encoded_verifying_key = serde_json::to_string(&verifying_key).unwrap(); + let decoded_verifying_key: VerifyingKey = + serde_json::from_str(&encoded_verifying_key).unwrap(); + + assert_eq!(verifying_key, decoded_verifying_key); + } + + #[test] + fn serialize_deserialize_verifying_key_json_too_long() { + // derived from `serialize_deserialize_verifying_key_json` test + // trailing zero elements makes key too long (34 bytes) + let encoded_verifying_key_too_long = "[130,39,155,15,62,76,188,63,124,122,26,251,233,253,225,220,14,41,166,120,108,35,254,77,160,83,172,58,219,42,86,120,0,0]"; + let de_err = serde_json::from_str::(encoded_verifying_key_too_long) + .unwrap_err() + .to_string(); + assert!( + de_err.contains("invalid length 34"), + "expected invalid length error, got: {de_err}", + ); + } + + #[test] + fn serialize_deserialize_verifying_key_json_too_short() { + // derived from `serialize_deserialize_verifying_key_json` test + let encoded_verifying_key_too_long = "[130,39,155,15]"; + let de_err = serde_json::from_str::(encoded_verifying_key_too_long) + .unwrap_err() + .to_string(); + assert!( + de_err.contains("invalid length 4"), + "expected invalid length error, got: {de_err}" + ); + } + + #[test] + fn serialize_deserialize_signing_key_bincode() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); + let encoded_signing_key: Vec = bincode::serialize(&signing_key).unwrap(); + let decoded_signing_key: SigningKey = bincode::deserialize(&encoded_signing_key).unwrap(); + + #[allow(clippy::needless_range_loop)] + for i in 0..SECRET_KEY_LENGTH { + assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]); + } + } + + #[test] + fn serialize_deserialize_signing_key_json() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); + let encoded_signing_key = serde_json::to_string(&signing_key).unwrap(); + let decoded_signing_key: SigningKey = serde_json::from_str(&encoded_signing_key).unwrap(); + + #[allow(clippy::needless_range_loop)] + for i in 0..SECRET_KEY_LENGTH { + assert_eq!(SECRET_KEY_BYTES[i], decoded_signing_key.to_bytes()[i]); + } + } + + #[test] + fn serialize_deserialize_signing_key_json_too_long() { + // derived from `serialize_deserialize_signing_key_json` test + // trailing zero elements makes key too long (34 bytes) + let encoded_signing_key_too_long = "[62,70,27,163,92,182,11,3,77,234,98,4,11,127,79,228,243,187,150,73,201,137,76,22,85,251,152,2,241,42,72,54,0,0]"; + let de_err = serde_json::from_str::(encoded_signing_key_too_long) + .unwrap_err() + .to_string(); + assert!( + de_err.contains("invalid length 34"), + "expected invalid length error, got: {de_err}", + ); + } + + #[test] + fn serialize_deserialize_signing_key_json_too_short() { + // derived from `serialize_deserialize_signing_key_json` test + let encoded_signing_key_too_long = "[62,70,27,163]"; + let de_err = serde_json::from_str::(encoded_signing_key_too_long) + .unwrap_err() + .to_string(); + assert!( + de_err.contains("invalid length 4"), + "expected invalid length error, got: {de_err}" + ); + } + + #[test] + fn serialize_deserialize_signing_key_toml() { + let demo = Demo { + signing_key: SigningKey::from_bytes(&SECRET_KEY_BYTES), + }; + + println!("\n\nWrite to toml"); + let demo_toml = toml::to_string(&demo).unwrap(); + println!("{}", demo_toml); + let demo_toml_rebuild: Result = toml::from_str(&demo_toml); + println!("{:?}", demo_toml_rebuild); + } + + #[test] + fn serialize_verifying_key_size() { + let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&PUBLIC_KEY_BYTES).unwrap(); + assert_eq!( + bincode::serialized_size(&verifying_key).unwrap() as usize, + BINCODE_INT_LENGTH + PUBLIC_KEY_LENGTH + ); + } + + #[test] + fn serialize_signature_size() { + let signature: Signature = Signature::from_bytes(&SIGNATURE_BYTES); + assert_eq!( + bincode::serialized_size(&signature).unwrap() as usize, + SIGNATURE_LENGTH + ); + } + + #[test] + fn serialize_signing_key_size() { + let signing_key = SigningKey::from_bytes(&SECRET_KEY_BYTES); + assert_eq!( + bincode::serialized_size(&signing_key).unwrap() as usize, + BINCODE_INT_LENGTH + SECRET_KEY_LENGTH + ); + } +} diff --git a/ed25519-dalek/tests/examples/pkcs8-v1.der b/ed25519-dalek/tests/examples/pkcs8-v1.der new file mode 100644 index 000000000..cb780b362 Binary files /dev/null and b/ed25519-dalek/tests/examples/pkcs8-v1.der differ diff --git a/ed25519-dalek/tests/examples/pkcs8-v2.der b/ed25519-dalek/tests/examples/pkcs8-v2.der new file mode 100644 index 000000000..3358e8a73 Binary files /dev/null and b/ed25519-dalek/tests/examples/pkcs8-v2.der differ diff --git a/ed25519-dalek/tests/examples/pubkey.der b/ed25519-dalek/tests/examples/pubkey.der new file mode 100644 index 000000000..d1002c4a4 Binary files /dev/null and b/ed25519-dalek/tests/examples/pubkey.der differ diff --git a/ed25519-dalek/tests/pkcs8.rs b/ed25519-dalek/tests/pkcs8.rs new file mode 100644 index 000000000..fecdba94e --- /dev/null +++ b/ed25519-dalek/tests/pkcs8.rs @@ -0,0 +1,71 @@ +//! PKCS#8 private key and SPKI public key tests. +//! +//! These are standard formats for storing public and private keys, defined in +//! RFC5958 (PKCS#8) and RFC5280 (SPKI). + +#![cfg(feature = "pkcs8")] + +use ed25519_dalek::pkcs8::{DecodePrivateKey, DecodePublicKey}; +use ed25519_dalek::{SigningKey, VerifyingKey}; +use hex_literal::hex; + +#[cfg(feature = "alloc")] +use ed25519_dalek::pkcs8::{EncodePrivateKey, EncodePublicKey}; + +/// Ed25519 PKCS#8 v1 private key encoded as ASN.1 DER. +const PKCS8_V1_DER: &[u8] = include_bytes!("examples/pkcs8-v1.der"); + +/// Ed25519 PKCS#8 v2 private key + public key encoded as ASN.1 DER. +const PKCS8_V2_DER: &[u8] = include_bytes!("examples/pkcs8-v2.der"); + +/// Ed25519 SubjectVerifyingKeyInfo encoded as ASN.1 DER. +const PUBLIC_KEY_DER: &[u8] = include_bytes!("examples/pubkey.der"); + +/// Secret key bytes. +/// +/// Extracted with: +/// $ openssl asn1parse -inform der -in tests/examples/pkcs8-v1.der +const SK_BYTES: [u8; 32] = hex!("D4EE72DBF913584AD5B6D8F1F769F8AD3AFE7C28CBF1D4FBE097A88F44755842"); + +/// Public key bytes. +const PK_BYTES: [u8; 32] = hex!("19BF44096984CDFE8541BAC167DC3B96C85086AA30B6B6CB0C5C38AD703166E1"); + +#[test] +fn decode_pkcs8_v1() { + let keypair = SigningKey::from_pkcs8_der(PKCS8_V1_DER).unwrap(); + assert_eq!(SK_BYTES, keypair.to_bytes()); + assert_eq!(PK_BYTES, keypair.verifying_key().to_bytes()); +} + +#[test] +fn decode_pkcs8_v2() { + let keypair = SigningKey::from_pkcs8_der(PKCS8_V2_DER).unwrap(); + assert_eq!(SK_BYTES, keypair.to_bytes()); + assert_eq!(PK_BYTES, keypair.verifying_key().to_bytes()); +} + +#[test] +fn decode_verifying_key() { + let verifying_key = VerifyingKey::from_public_key_der(PUBLIC_KEY_DER).unwrap(); + assert_eq!(PK_BYTES, verifying_key.to_bytes()); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_pkcs8() { + let keypair = SigningKey::from_bytes(&SK_BYTES); + let pkcs8_key = keypair.to_pkcs8_der().unwrap(); + + let keypair2 = SigningKey::from_pkcs8_der(pkcs8_key.as_bytes()).unwrap(); + assert_eq!(keypair.to_bytes(), keypair2.to_bytes()); +} + +#[test] +#[cfg(feature = "alloc")] +fn encode_verifying_key() { + let verifying_key = VerifyingKey::from_bytes(&PK_BYTES).unwrap(); + let verifying_key_der = verifying_key.to_public_key_der().unwrap(); + + let verifying_key2 = VerifyingKey::from_public_key_der(verifying_key_der.as_bytes()).unwrap(); + assert_eq!(verifying_key, verifying_key2); +} diff --git a/ed25519-dalek/tests/validation_criteria.rs b/ed25519-dalek/tests/validation_criteria.rs new file mode 100644 index 000000000..7c45a960b --- /dev/null +++ b/ed25519-dalek/tests/validation_criteria.rs @@ -0,0 +1,231 @@ +use ed25519::signature::Verifier; +use ed25519_dalek::{Signature, VerifyingKey}; + +use serde::{de::Error as SError, Deserialize, Deserializer}; +use std::{collections::BTreeSet as Set, fs::File}; + +/// The set of edge cases that [`VerifyingKey::verify()`] permits. +const VERIFY_ALLOWED_EDGECASES: &[Flag] = &[ + Flag::LowOrderA, + Flag::LowOrderR, + Flag::NonCanonicalA, + Flag::LowOrderComponentA, + Flag::LowOrderComponentR, + // `ReencodedK` is not actually permitted by `verify()`, but it looks that way in the tests + // because it sometimes occurs with a low-order A. 1/8 of the time, the resulting signature + // will be identical the one made with a normal k. find_validation_criteria shows that indeed + // this occurs 10/58 of the time + Flag::ReencodedK, +]; + +/// The set of edge cases that [`VerifyingKey::verify_strict()`] permits +const VERIFY_STRICT_ALLOWED_EDGECASES: &[Flag] = + &[Flag::LowOrderComponentA, Flag::LowOrderComponentR]; + +/// Each variant describes a specific edge case that can occur in an Ed25519 signature. Refer to +/// the test vector [README][] for more info. +/// +/// [README]: https://github.com/C2SP/CCTV/blob/5ea85644bd035c555900a2f707f7e4c31ea65ced/ed25519vectors/README.md +#[derive(Deserialize, Debug, Copy, Clone, PartialOrd, Ord, Eq, PartialEq)] +enum Flag { + #[serde(rename = "low_order")] + LowOrder, + #[serde(rename = "low_order_A")] + LowOrderA, + #[serde(rename = "low_order_R")] + LowOrderR, + #[serde(rename = "non_canonical_A")] + NonCanonicalA, + #[serde(rename = "non_canonical_R")] + NonCanonicalR, + #[serde(rename = "low_order_component_A")] + LowOrderComponentA, + #[serde(rename = "low_order_component_R")] + LowOrderComponentR, + #[serde(rename = "low_order_residue")] + LowOrderResidue, + #[serde(rename = "reencoded_k")] + ReencodedK, +} + +/// This is an intermediate representation between JSON and TestVector +#[derive(Deserialize)] +struct IntermediateTestVector { + number: usize, + #[serde(deserialize_with = "bytes_from_hex", rename = "key")] + pubkey: Vec, + #[serde(deserialize_with = "bytes_from_hex")] + sig: Vec, + msg: String, + flags: Option>, +} + +/// The test vector struct from [CCTV][]. `sig` may or may not be a valid signature of `msg` with +/// respect to `pubkey`, depending on the verification function's validation criteria. `flags` +/// describes all the edge cases which this test vector falls into. +/// +/// [CCTV]: https://github.com/C2SP/CCTV/tree/5ea85644bd035c555900a2f707f7e4c31ea65ced/ed25519vectors +struct TestVector { + number: usize, + pubkey: VerifyingKey, + sig: Signature, + msg: Vec, + flags: Set, +} + +impl From for TestVector { + fn from(tv: IntermediateTestVector) -> Self { + let number = tv.number; + let pubkey = { + let mut buf = [0u8; 32]; + buf.copy_from_slice(&tv.pubkey); + VerifyingKey::from_bytes(&buf).unwrap() + }; + let sig = { + let mut buf = [0u8; 64]; + buf.copy_from_slice(&tv.sig); + Signature::from_bytes(&buf) + }; + let msg = tv.msg.as_bytes().to_vec(); + + // Unwrap the Option> + let flags = tv.flags.unwrap_or_default(); + + Self { + number, + pubkey, + sig, + msg, + flags, + } + } +} + +// Tells serde how to deserialize bytes from hex +fn bytes_from_hex<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let mut hex_str = String::deserialize(deserializer)?; + // Prepend a 0 if it's not even length + if hex_str.len() % 2 == 1 { + hex_str.insert(0, '0'); + } + hex::decode(hex_str).map_err(|e| SError::custom(format!("{:?}", e))) +} + +fn get_test_vectors() -> impl Iterator { + let f = File::open("VALIDATIONVECTORS").expect( + "This test is only available when the code has been cloned from the git repository, since + the VALIDATIONVECTORS file is large and is therefore not included within the distributed \ + crate.", + ); + + serde_json::from_reader::<_, Vec>(f) + .unwrap() + .into_iter() + .map(TestVector::from) +} + +/// Tests that the verify() and verify_strict() functions succeed only on test cases whose flags +/// (i.e., edge cases it falls into) are a subset of VERIFY_ALLOWED_EDGECASES and +/// VERIFY_STRICT_ALLOWED_EDGECASES, respectively +#[test] +fn check_validation_criteria() { + let verify_allowed_edgecases = Set::from_iter(VERIFY_ALLOWED_EDGECASES.to_vec()); + let verify_strict_allowed_edgecases = Set::from_iter(VERIFY_STRICT_ALLOWED_EDGECASES.to_vec()); + + for TestVector { + number, + pubkey, + msg, + sig, + flags, + } in get_test_vectors() + { + // If all the verify-permitted flags here are ones we permit, then verify() should succeed. + // Otherwise, it should not. + let success = pubkey.verify(&msg, &sig).is_ok(); + if flags.is_subset(&verify_allowed_edgecases) { + assert!(success, "verify() expected success in testcase #{number}",); + } else { + assert!(!success, "verify() expected failure in testcase #{number}",); + } + + // If all the verify_strict-permitted flags here are ones we permit, then verify_strict() + // should succeed. Otherwise, it should not. + let success = pubkey.verify_strict(&msg, &sig).is_ok(); + if flags.is_subset(&verify_strict_allowed_edgecases) { + assert!( + success, + "verify_strict() expected success in testcase #{number}", + ); + } else { + assert!( + !success, + "verify_strict() expected failure in testcase #{number}", + ); + } + } +} + +/// Prints the flags that are consistently permitted by verify() and verify_strict() +#[test] +fn find_validation_criteria() { + let mut verify_allowed_edgecases = Set::new(); + let mut verify_strict_allowed_edgecases = Set::new(); + + // Counts the number of times a signature with a re-encoded k and a low-order A verified. This + // happens with 1/8 probability, assuming the usual verification equation(s). + let mut num_lucky_reencoded_k = 0; + let mut num_reencoded_k = 0; + + for TestVector { + number: _, + pubkey, + msg, + sig, + flags, + } in get_test_vectors() + { + // If verify() was a success, add all the associated flags to verify-permitted set + let success = pubkey.verify(&msg, &sig).is_ok(); + + // If this is ReencodedK && LowOrderA, log some statistics + if flags.contains(&Flag::ReencodedK) && flags.contains(&Flag::LowOrderA) { + num_reencoded_k += 1; + num_lucky_reencoded_k += success as u8; + } + + if success { + for flag in &flags { + // Don't count re-encoded k when A is low-order. This is because the + // re-encoded k might be a multiple of 8 by accident + if *flag == Flag::ReencodedK && flags.contains(&Flag::LowOrderA) { + continue; + } else { + verify_allowed_edgecases.insert(*flag); + } + } + } + + // If verify_strict() was a success, add all the associated flags to + // verify_strict-permitted set + let success = pubkey.verify_strict(&msg, &sig).is_ok(); + if success { + for flag in &flags { + verify_strict_allowed_edgecases.insert(*flag); + } + } + } + + println!("VERIFY_ALLOWED_EDGECASES: {:?}", verify_allowed_edgecases); + println!( + "VERIFY_STRICT_ALLOWED_EDGECASES: {:?}", + verify_strict_allowed_edgecases + ); + println!( + "re-encoded k && low-order A yielded a valid signature {}/{} of the time", + num_lucky_reencoded_k, num_reencoded_k + ); +} diff --git a/ed25519-dalek/tests/x25519.rs b/ed25519-dalek/tests/x25519.rs new file mode 100644 index 000000000..11e72a804 --- /dev/null +++ b/ed25519-dalek/tests/x25519.rs @@ -0,0 +1,80 @@ +//! Tests for converting Ed25519 keys into X25519 (Montgomery form) keys. + +use curve25519_dalek::scalar::{clamp_integer, Scalar}; +use ed25519_dalek::SigningKey; +use hex_literal::hex; +use sha2::{Digest, Sha512}; +use x25519_dalek::{PublicKey as XPublicKey, StaticSecret as XStaticSecret}; + +/// Tests that X25519 Diffie-Hellman works when using keys converted from Ed25519. +// TODO: generate test vectors using another implementation of Ed25519->X25519 +#[test] +fn ed25519_to_x25519_dh() { + // Keys from RFC8032 test vectors (from section 7.1) + let ed_secret_key_a = hex!("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"); + let ed_secret_key_b = hex!("4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb"); + + let ed_signing_key_a = SigningKey::from_bytes(&ed_secret_key_a); + let ed_signing_key_b = SigningKey::from_bytes(&ed_secret_key_b); + + // Create an x25519 static secret from the ed25519 signing key + let scalar_bytes_a = ed_signing_key_a.to_scalar_bytes(); + let scalar_bytes_b = ed_signing_key_b.to_scalar_bytes(); + let x_static_secret_a = XStaticSecret::from(scalar_bytes_a); + let x_static_secret_b = XStaticSecret::from(scalar_bytes_b); + + // Compute the secret scalars too + let scalar_a = ed_signing_key_a.to_scalar(); + let scalar_b = ed_signing_key_b.to_scalar(); + + // Compare the scalar bytes to the first 32 bytes of SHA-512(secret_key). We have to clamp and + // reduce the SHA-512 output because that's what the spec does before using the scalars for + // anything. + assert_eq!(scalar_bytes_a, &Sha512::digest(ed_secret_key_a)[..32]); + assert_eq!(scalar_bytes_b, &Sha512::digest(ed_secret_key_b)[..32]); + + // Compare the scalar with the clamped and reduced scalar bytes + assert_eq!( + scalar_a, + Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes_a)) + ); + assert_eq!( + scalar_b, + Scalar::from_bytes_mod_order(clamp_integer(scalar_bytes_b)) + ); + + let x_public_key_a = XPublicKey::from(&x_static_secret_a); + let x_public_key_b = XPublicKey::from(&x_static_secret_b); + assert_eq!( + x_public_key_a.to_bytes(), + hex!("d85e07ec22b0ad881537c2f44d662d1a143cf830c57aca4305d85c7a90f6b62e") + ); + assert_eq!( + x_public_key_b.to_bytes(), + hex!("25c704c594b88afc00a76b69d1ed2b984d7e22550f3ed0802d04fbcd07d38d47") + ); + + // Test the claim made in the comments of SigningKey::to_scalar_bytes, i.e., that the resulting + // scalar is a valid private key for the x25519 pubkey represented by + // `sk.verifying_key().to_montgomery()` + assert_eq!( + ed_signing_key_a.verifying_key().to_montgomery().as_bytes(), + x_public_key_a.as_bytes() + ); + assert_eq!( + ed_signing_key_b.verifying_key().to_montgomery().as_bytes(), + x_public_key_b.as_bytes() + ); + + // Check that Diffie-Hellman works + let expected_shared_secret = + hex!("5166f24a6918368e2af831a4affadd97af0ac326bdf143596c045967cc00230e"); + assert_eq!( + x_static_secret_a.diffie_hellman(&x_public_key_b).to_bytes(), + expected_shared_secret, + ); + assert_eq!( + x_static_secret_b.diffie_hellman(&x_public_key_a).to_bytes(), + expected_shared_secret, + ); +} diff --git a/src/backend/mod.rs b/src/backend/mod.rs deleted file mode 100644 index 606aa3d7b..000000000 --- a/src/backend/mod.rs +++ /dev/null @@ -1,66 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! Pluggable implementations for different architectures. -//! -//! The backend code is split into two parts: a serial backend, -//! and a vector backend. -//! -//! The [`serial`] backend contains 32- and 64-bit implementations of -//! field arithmetic and scalar arithmetic, as well as implementations -//! of point operations using the mixed-model strategy (passing -//! between different curve models depending on the operation). -//! -//! The [`vector`] backend contains implementations of vectorized -//! field arithmetic, used to implement point operations using a novel -//! implementation strategy derived from parallel formulas of Hisil, -//! Wong, Carter, and Dawson. -//! -//! Because the two strategies give rise to different curve models, -//! it's not possible to reuse exactly the same scalar multiplication -//! code (or to write it generically), so both serial and vector -//! backends contain matching implementations of scalar multiplication -//! algorithms. These are intended to be selected by a `#[cfg]`-based -//! type alias. -//! -//! The [`vector`] backend is selected by the `simd_backend` cargo -//! feature; it uses the [`serial`] backend for non-vectorized operations. - -#[cfg(not(any( - feature = "u32_backend", - feature = "u64_backend", - feature = "fiat_u32_backend", - feature = "fiat_u64_backend", - feature = "simd_backend", - feature = "u32e_backend", -)))] -compile_error!( - "no curve25519-dalek backend cargo feature enabled! \ - please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend, simd_backend, u32e_backend" -); - -pub mod serial; - -#[cfg(any( - all( - feature = "simd_backend", - any(target_feature = "avx2", target_feature = "avx512ifma") - ), - all(feature = "nightly", rustdoc) -))] -#[cfg_attr( - feature = "nightly", - doc(cfg(any(all( - feature = "simd_backend", - any(target_feature = "avx2", target_feature = "avx512ifma") - )))) -)] -pub mod vector; diff --git a/src/backend/serial/mod.rs b/src/backend/serial/mod.rs deleted file mode 100644 index f935baa94..000000000 --- a/src/backend/serial/mod.rs +++ /dev/null @@ -1,58 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! Serial implementations of field, scalar, point arithmetic. -//! -//! When the vector backend is disabled, the crate uses the -//! mixed-model strategy for implementing point operations and scalar -//! multiplication; see the [`curve_models`](self::curve_models) and -//! [`scalar_mul`](self::scalar_mul) documentation for more -//! information. -//! -//! When the vector backend is enabled, the field and scalar -//! implementations are still used for non-vectorized operations. -//! -//! Note: at this time the `u32` and `u64` backends cannot be built -//! together. - -#[cfg(not(any( - feature = "u32_backend", - feature = "u64_backend", - feature = "fiat_u32_backend", - feature = "fiat_u64_backend", - feature = "u32e_backend", -)))] -compile_error!( - "no curve25519-dalek backend cargo feature enabled! \ - please enable one of: u32_backend, u64_backend, fiat_u32_backend, fiat_u64_backend, u32e_backend" -); - -#[cfg(feature = "u32_backend")] -pub mod u32; - -#[cfg(feature = "u32e_backend")] -pub mod u32e; -#[cfg(feature = "u64_backend")] -pub mod u64; - -#[cfg(feature = "fiat_u32_backend")] -pub mod fiat_u32; - -#[cfg(feature = "fiat_u64_backend")] -pub mod fiat_u64; - -pub mod curve_models; - -#[cfg(not(all( - feature = "simd_backend", - any(target_feature = "avx2", target_feature = "avx512ifma") -)))] -pub mod scalar_mul; diff --git a/src/backend/serial/scalar_mul/vartime_double_base.rs b/src/backend/serial/scalar_mul/vartime_double_base.rs deleted file mode 100644 index 03517f933..000000000 --- a/src/backend/serial/scalar_mul/vartime_double_base.rs +++ /dev/null @@ -1,62 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence -#![allow(non_snake_case)] - -use constants; -use traits::Identity; -use scalar::Scalar; -use edwards::EdwardsPoint; -use backend::serial::curve_models::{ProjectiveNielsPoint, ProjectivePoint}; -use window::NafLookupTable5; - -/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. -pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { - let a_naf = a.non_adjacent_form(5); - let b_naf = b.non_adjacent_form(8); - - // Find starting index - let mut i: usize = 255; - for j in (0..256).rev() { - i = j; - if a_naf[i] != 0 || b_naf[i] != 0 { - break; - } - } - - let table_A = NafLookupTable5::::from(A); - let table_B = &constants::AFFINE_ODD_MULTIPLES_OF_BASEPOINT; - - let mut r = ProjectivePoint::identity(); - loop { - let mut t = r.double(); - - if a_naf[i] > 0 { - t = &t.to_extended() + &table_A.select(a_naf[i] as usize); - } else if a_naf[i] < 0 { - t = &t.to_extended() - &table_A.select(-a_naf[i] as usize); - } - - if b_naf[i] > 0 { - t = &t.to_extended() + &table_B.select(b_naf[i] as usize); - } else if b_naf[i] < 0 { - t = &t.to_extended() - &table_B.select(-b_naf[i] as usize); - } - - r = t.to_projective(); - - if i == 0 { - break; - } - i -= 1; - } - - r.to_extended() -} diff --git a/src/backend/serial/u32/constants.rs b/src/backend/serial/u32/constants.rs deleted file mode 100644 index cf2bae9d1..000000000 --- a/src/backend/serial/u32/constants.rs +++ /dev/null @@ -1,4790 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! This module contains various constants (such as curve parameters -//! and useful field elements like `sqrt(-1)`), as well as -//! lookup tables of pre-computed points. - -use backend::serial::curve_models::AffineNielsPoint; -use super::field::FieldElement2625; -use super::scalar::Scalar29; -use edwards::{EdwardsBasepointTable, EdwardsPoint}; -use window::{LookupTable, NafLookupTable8}; - -/// The value of minus one, equal to `-&FieldElement::one()` -pub(crate) const MINUS_ONE: FieldElement2625 = FieldElement2625([ - 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431 -]); - -/// Edwards `d` value, equal to `-121665/121666 mod p`. -pub(crate) const EDWARDS_D: FieldElement2625 = FieldElement2625([ - 56195235, 13857412, 51736253, 6949390, 114729, 24766616, 60832955, 30306712, 48412415, 21499315, -]); - -/// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. -pub(crate) const EDWARDS_D2: FieldElement2625 = FieldElement2625([ - 45281625, 27714825, 36363642, 13898781, 229458, 15978800, 54557047, 27058993, 29715967, 9444199, -]); - -/// One minus edwards `d` value squared, equal to `(1 - (-121665/121666) mod p) pow 2` -pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement2625 = FieldElement2625([ - 6275446, 16937061, 44170319, 29780721, 11667076, 7397348, 39186143, 1766194, 42675006, 672202 -]); - -/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` -pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement2625 = FieldElement2625([ - 15551776, 22456977, 53683765, 23429360, 55212328, 10178283, 40474537, 4729243, 61826754, 23438029 -]); - -/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. -pub(crate) const SQRT_AD_MINUS_ONE: FieldElement2625 = FieldElement2625([ - 24849947, 33400850, 43495378, 6347714, 46036536, 32887293, 41837720, 18186727, 66238516, - 14525638, -]); - -/// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. -pub(crate) const INVSQRT_A_MINUS_D: FieldElement2625 = FieldElement2625([ - 6111466, 4156064, 39310137, 12243467, 41204824, 120896, 20826367, 26493656, 6093567, 31568420, -]); - -/// Precomputed value of one of the square roots of -1 (mod p) -pub(crate) const SQRT_M1: FieldElement2625 = FieldElement2625([ - 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, 31548777, 326685, 11406482, -]); - -/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) -#[cfg(not(feature = "betrusted"))] -pub(crate) const APLUS2_OVER_FOUR: FieldElement2625 = - FieldElement2625([121666, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - -/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation -/// for Curve25519 in its Montgomery form. (This is used internally within the -/// Elligator map.) -pub(crate) const MONTGOMERY_A: FieldElement2625 = - FieldElement2625([486662, 0, 0, 0, 0, 0, 0, 0, 0, 0]); - -/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the -/// Elligator map.) -pub(crate) const MONTGOMERY_A_NEG: FieldElement2625 = FieldElement2625([ - 66622183, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, -]); - -/// `L` is the order of base point, i.e. 2^252 + -/// 27742317777372353535851937790883648493 -pub(crate) const L: Scalar29 = Scalar29([ - 0x1cf5d3ed, 0x009318d2, 0x1de73596, 0x1df3bd45, 0x0000014d, 0x00000000, 0x00000000, 0x00000000, - 0x00100000, -]); - -/// `L` * `LFACTOR` = -1 (mod 2^29) -pub(crate) const LFACTOR: u32 = 0x12547e1b; - -/// `R` = R % L where R = 2^261 -pub(crate) const R: Scalar29 = Scalar29([ - 0x114df9ed, 0x1a617303, 0x0f7c098c, 0x16793167, 0x1ffd656e, 0x1fffffff, 0x1fffffff, 0x1fffffff, - 0x000fffff, -]); - -/// `RR` = (R^2) % L where R = 2^261 -pub(crate) const RR: Scalar29 = Scalar29([ - 0x0b5f9d12, 0x1e141b17, 0x158d7f3d, 0x143f3757, 0x1972d781, 0x042feb7c, 0x1ceec73d, 0x1e184d1e, - 0x0005046d, -]); - -/// The Ed25519 basepoint, as an `EdwardsPoint`. -/// -/// This is called `_POINT` to distinguish it from -/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar -/// multiplication (it's much faster). -pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { - X: FieldElement2625([ - 52811034, 25909283, 16144682, 17082669, 27570973, 30858332, 40966398, 8378388, 20764389, - 8758491, - ]), - Y: FieldElement2625([ - 40265304, 26843545, 13421772, 20132659, 26843545, 6710886, 53687091, 13421772, 40265318, - 26843545, - ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ - 28827043, 27438313, 39759291, 244362, 8635006, 11264893, 19351346, 13413597, 16611511, - 27139452, - ]), -}; - -/// The 8-torsion subgroup \\(\mathcal E [8]\\). -/// -/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of -/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\) -/// generating \\(\mathcal E[8]\\). -/// -/// Thus \\(\mathcal E[4]\\) is the points indexed by `0,2,4,6`, and -/// \\(\mathcal E[2]\\) is the points indexed by `0,4`. -/// The Ed25519 basepoint has y = 4/5. This is called `_POINT` to -/// distinguish it from `_TABLE`, which should be used for scalar -/// multiplication (it's much faster). -pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; - -/// Inner item used to hide limb constants from cargo doc output. -#[doc(hidden)] -pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ - EdwardsPoint { - X: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - Y: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - }, - EdwardsPoint { - X: FieldElement2625([ - 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, - 8345318, - ]), - Y: FieldElement2625([ - 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, - 31985330, - ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ - 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, - 3541542, 28543251, - ]), - }, - EdwardsPoint { - X: FieldElement2625([ - 32595773, 7943725, 57730914, 30054016, 54719391, 272472, 25146209, 2005654, 66782178, - 22147949, - ]), - Y: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - }, - EdwardsPoint { - X: FieldElement2625([ - 21352778, 5345713, 4660180, 25206575, 24143089, 14568123, 30185756, 21306662, 33579924, - 8345318, - ]), - Y: FieldElement2625([ - 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, - 47743011, 1569101, - ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ - 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, - 5011180, - ]), - }, - EdwardsPoint { - X: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - Y: FieldElement2625([ - 67108844, 33554431, 67108863, 33554431, 67108863, 33554431, 67108863, 33554431, - 67108863, 33554431, - ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - }, - EdwardsPoint { - X: FieldElement2625([ - 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, - 33528939, 25209113, - ]), - Y: FieldElement2625([ - 60155942, 32288931, 6862340, 26496934, 63071167, 28106709, 31680898, 18229030, - 47743011, 1569101, - ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ - 41846657, 21581751, 11716001, 27684820, 48915701, 16297738, 20670665, 24995334, - 3541542, 28543251, - ]), - }, - EdwardsPoint { - X: FieldElement2625([ - 34513072, 25610706, 9377949, 3500415, 12389472, 33281959, 41962654, 31548777, 326685, - 11406482, - ]), - Y: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - }, - EdwardsPoint { - X: FieldElement2625([ - 45756067, 28208718, 62448683, 8347856, 42965774, 18986308, 36923107, 12247769, - 33528939, 25209113, - ]), - Y: FieldElement2625([ - 6952903, 1265500, 60246523, 7057497, 4037696, 5447722, 35427965, 15325401, 19365852, - 31985330, - ]), - Z: FieldElement2625([1, 0, 0, 0, 0, 0, 0, 0, 0, 0]), - T: FieldElement2625([ - 25262188, 11972680, 55392862, 5869611, 18193162, 17256693, 46438198, 8559097, 63567321, - 5011180, - ]), - }, -]; - -/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). -pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; - -/// Inner constant, used to avoid filling the docs with precomputed points. -#[doc(hidden)] -pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = - EdwardsBasepointTable([ - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, - 61029707, 35602036, - ]), - y_minus_x: FieldElement2625([ - 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, - 19500929, 18085054, - ]), - xy2d: FieldElement2625([ - 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, - 42594502, 29115885, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54292951, 54132516, 45527619, 11784319, 41753206, 30803714, 55390960, 29739860, - 66750418, 23343128, - ]), - y_minus_x: FieldElement2625([ - 45405608, 6903824, 27185491, 6451973, 37531140, 24000426, 51492312, 11189267, - 40279186, 28235350, - ]), - xy2d: FieldElement2625([ - 26966623, 11152617, 32442495, 15396054, 14353839, 20802097, 63980037, 24013313, - 51636816, 29387734, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, - 28944398, 32004408, - ]), - y_minus_x: FieldElement2625([ - 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, - 7689661, 11199574, - ]), - xy2d: FieldElement2625([ - 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, - 49359771, 23634074, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 50071967, 13921891, 78054670, 27521000, 27105051, 17470053, 105291517, - 15006021, 70393432, 27277891, - ]), - y_minus_x: FieldElement2625([ - 23599295, 25248385, 55915199, 25867015, 13236773, 10506355, 7464579, 9656445, - 13059162, 10374397, - ]), - xy2d: FieldElement2625([ - 7798537, 16710257, 3033922, 2874086, 28997861, 2835604, 32406664, 29715387, - 66467155, 33453106, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, - 118779423, 44373810, - ]), - y_minus_x: FieldElement2625([ - 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, - 54440373, 5581305, - ]), - xy2d: FieldElement2625([ - 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, - 43430843, 17738489, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 51736881, 20691677, 32573249, 4720197, 107781206, 39429941, 115029100, - 18329611, 124398787, 21468653, - ]), - y_minus_x: FieldElement2625([ - 58559652, 109982, 15149363, 2178705, 22900618, 4543417, 3044240, 17864545, - 1762327, 14866737, - ]), - xy2d: FieldElement2625([ - 48909169, 17603008, 56635573, 1707277, 49922944, 3916100, 38872452, 3959420, - 27914454, 4383652, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, - 43156424, 18378665, - ]), - y_minus_x: FieldElement2625([ - 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, - 30598449, 7715701, - ]), - xy2d: FieldElement2625([ - 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, - 29794553, 32145132, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 14499452, 64379265, 33917749, 62854211, 95603724, 14271266, 97399599, 10876453, - 33954766, 35936157, - ]), - y_minus_x: FieldElement2625([ - 59913433, 30899068, 52378708, 462250, 39384538, 3941371, 60872247, 3696004, - 34808032, 15351954, - ]), - xy2d: FieldElement2625([ - 27431194, 8222322, 16448760, 29646437, 48401861, 11938354, 34147463, 30583916, - 29551812, 10109425, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 53451805, 20399000, 102933977, 45331528, 88556249, 40073815, 64730579, - 31926875, 77201646, 28790260, - ]), - y_minus_x: FieldElement2625([ - 27939166, 14210322, 4677035, 16277044, 44144402, 21156292, 34600109, 12005537, - 49298737, 12803509, - ]), - xy2d: FieldElement2625([ - 17228999, 17892808, 65875336, 300139, 65883994, 21839654, 30364212, 24516238, - 18016356, 4397660, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 56150002, 25864224, 4776340, 18600194, 27850027, 17952220, 40489757, 14544524, - 49631360, 34537070, - ]), - y_minus_x: FieldElement2625([ - 29253598, 15796703, 64244882, 23645547, 10057022, 3163536, 7332899, 29434304, - 46061167, 9934962, - ]), - xy2d: FieldElement2625([ - 5793284, 16271923, 42977250, 23438027, 29188559, 1206517, 52360934, 4559894, - 36984942, 22656481, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 39464893, 55615857, 83391519, 22517938, 28414020, 52096600, 24191032, 38096129, - 53770554, 39054999, - ]), - y_minus_x: FieldElement2625([ - 12650548, 32057319, 9052870, 11355358, 49428827, 25154267, 49678271, 12264342, - 10874051, 13524335, - ]), - xy2d: FieldElement2625([ - 25556948, 30508442, 714650, 2510400, 23394682, 23139102, 33119037, 5080568, - 44580805, 5376627, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 108129445, 29543378, 50095164, 30016803, 60382070, 35475328, 44787558, - 57661420, 71644630, 35123438, - ]), - y_minus_x: FieldElement2625([ - 64853442, 14606629, 45416424, 25514613, 28430648, 8775819, 36614302, 3044289, - 31848280, 12543772, - ]), - xy2d: FieldElement2625([ - 45080285, 2943892, 35251351, 6777305, 13784462, 29262229, 39731668, 31491700, - 7718481, 14474653, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 69494160, 36008644, 44477543, 33601034, 62670928, 51428448, 67765827, 26317766, - 91425031, 28300864, - ]), - y_minus_x: FieldElement2625([ - 13741529, 10911568, 33875447, 24950694, 46931033, 32521134, 33040650, 20129900, - 46379407, 8321685, - ]), - xy2d: FieldElement2625([ - 21060490, 31341688, 15712756, 29218333, 1639039, 10656336, 23845965, 21679594, - 57124405, 608371, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 53436113, 18466845, 56219170, 25997372, 61071954, 11305546, 68232832, 60328286, - 94338261, 33578318, - ]), - y_minus_x: FieldElement2625([ - 43864724, 33260226, 55364135, 14712570, 37643165, 31524814, 12797023, 27114124, - 65475458, 16678953, - ]), - xy2d: FieldElement2625([ - 37608244, 4770661, 51054477, 14001337, 7830047, 9564805, 65600720, 28759386, - 49939598, 4904952, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 91168402, 48171434, 86146020, 18514523, 86874956, 18648002, 72278074, 16191879, - 69237100, 29227598, - ]), - y_minus_x: FieldElement2625([ - 50127693, 4124965, 58568254, 22900634, 30336521, 19449185, 37302527, 916032, - 60226322, 30567899, - ]), - xy2d: FieldElement2625([ - 44477957, 12419371, 59974635, 26081060, 50629959, 16739174, 285431, 2763829, - 15736322, 4143876, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 69488197, 11839344, 62998462, 27565766, 78383161, 34349388, 67321664, 18959768, - 23527083, 17096164, - ]), - y_minus_x: FieldElement2625([ - 33431108, 22423954, 49269897, 17927531, 8909498, 8376530, 34483524, 4087880, - 51919953, 19138217, - ]), - xy2d: FieldElement2625([ - 1767664, 7197987, 53903638, 31531796, 54017513, 448825, 5799055, 4357868, - 62334673, 17231393, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 6721947, 47388255, 43585475, 32003117, 93463156, 21691110, 90474010, 29604699, - 74499753, 36314231, - ]), - y_minus_x: FieldElement2625([ - 4409022, 2052381, 23373853, 10530217, 7676779, 20668478, 21302352, 29290375, - 1244379, 20634787, - ]), - xy2d: FieldElement2625([ - 62687625, 7169618, 4982368, 30596842, 30256824, 30776892, 14086412, 9208236, - 15886429, 16489664, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 69104920, 43930080, 81455230, 46865633, 60234728, 17116020, 120524529, - 33952799, 36502408, 32841498, - ]), - y_minus_x: FieldElement2625([ - 41801399, 9795879, 64331450, 14878808, 33577029, 14780362, 13348553, 12076947, - 36272402, 5113181, - ]), - xy2d: FieldElement2625([ - 49338080, 11797795, 31950843, 13929123, 41220562, 12288343, 36767763, 26218045, - 13847710, 5387222, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 48526682, 30138214, 84933706, 64767897, 89853205, 56666252, 75871923, 37172217, - 47508201, 43925422, - ]), - y_minus_x: FieldElement2625([ - 20246567, 19185054, 22358228, 33010720, 18507282, 23140436, 14554436, 24808340, - 32232923, 16763880, - ]), - xy2d: FieldElement2625([ - 9648486, 10094563, 26416693, 14745928, 36734546, 27081810, 11094160, 15689506, - 3140038, 17044340, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 50948773, 39027126, 31895587, 38299426, 75932378, 43920116, 39884063, 43003044, - 38334409, 33920726, - ]), - y_minus_x: FieldElement2625([ - 19153450, 11523972, 56012374, 27051289, 42461232, 5420646, 28344573, 8041113, - 719605, 11671788, - ]), - xy2d: FieldElement2625([ - 8678006, 2694440, 60300850, 2517371, 4964326, 11152271, 51675948, 18287915, - 27000812, 23358879, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 119059805, 40688742, 75748150, 30739554, 59873175, 43976173, 67672928, - 38890528, 73859840, 19033405, - ]), - y_minus_x: FieldElement2625([ - 11836410, 29574944, 26297893, 16080799, 23455045, 15735944, 1695823, 24735310, - 8169719, 16220347, - ]), - xy2d: FieldElement2625([ - 48993007, 8653646, 17578566, 27461813, 59083086, 17541668, 55964556, 30926767, - 61118155, 19388398, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 43800347, 22586119, 82322091, 23473217, 36255258, 22504427, 27884328, 36401716, - 69764724, 35292826, - ]), - y_minus_x: FieldElement2625([ - 39571412, 19301410, 41772562, 25551651, 57738101, 8129820, 21651608, 30315096, - 48021414, 22549153, - ]), - xy2d: FieldElement2625([ - 1533110, 3437855, 23735889, 459276, 29970501, 11335377, 26030092, 5821408, - 10478196, 8544890, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 32173083, 50979553, 24896205, 37475929, 22579055, 63698010, 19270447, 45771905, - 84897880, 63712868, - ]), - y_minus_x: FieldElement2625([ - 36555903, 31326030, 51530034, 23407230, 13243888, 517024, 15479401, 29701199, - 30460519, 1052596, - ]), - xy2d: FieldElement2625([ - 55493970, 13323617, 32618793, 8175907, 51878691, 12596686, 27491595, 28942073, - 3179267, 24075541, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 99055914, 52742212, 62468279, 18214510, 51982886, 27514722, 52352086, 17142691, - 19072639, 24043372, - ]), - y_minus_x: FieldElement2625([ - 11685058, 11822410, 3158003, 19601838, 33402193, 29389366, 5977895, 28339415, - 473098, 5040608, - ]), - xy2d: FieldElement2625([ - 46817982, 8198641, 39698732, 11602122, 1290375, 30754672, 28326861, 1721092, - 47550222, 30422825, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 74990396, 10687936, 74687587, 7738377, 48157852, 31000479, 88929649, 8076148, - 39240368, 11538388, - ]), - y_minus_x: FieldElement2625([ - 47173198, 3899860, 18283497, 26752864, 51380203, 22305220, 8754524, 7446702, - 61432810, 5797015, - ]), - xy2d: FieldElement2625([ - 55813245, 29760862, 51326753, 25589858, 12708868, 25098233, 2014098, 24503858, - 64739691, 27677090, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 111745333, 55540121, 106535706, 34700805, 86065554, 50194990, 68301593, - 29840232, 82232482, 44365936, - ]), - y_minus_x: FieldElement2625([ - 14352079, 30134717, 48166819, 10822654, 32750596, 4699007, 67038501, 15776355, - 38222085, 21579878, - ]), - xy2d: FieldElement2625([ - 38867681, 25481956, 62129901, 28239114, 29416930, 1847569, 46454691, 17069576, - 4714546, 23953777, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 15200313, 41923004, 86787964, 15970073, 35236190, 35513882, 24611598, 29010600, - 55362987, 45894651, - ]), - y_minus_x: FieldElement2625([ - 12876937, 23074376, 33134380, 6590940, 60801088, 14872439, 9613953, 8241152, - 15370987, 9608631, - ]), - xy2d: FieldElement2625([ - 62965568, 21540023, 8446280, 33162829, 4407737, 13629032, 59383996, 15866073, - 38898243, 24740332, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 26660609, 51431209, 75502596, 33912478, 59707572, 34547419, 43204630, 34413128, - 87680086, 41974987, - ]), - y_minus_x: FieldElement2625([ - 14620696, 13067227, 51661590, 8264466, 14106269, 15080814, 33531827, 12516406, - 45534429, 21077682, - ]), - xy2d: FieldElement2625([ - 236881, 10476226, 57258, 18877408, 6472997, 2466984, 17258519, 7256740, - 8791136, 15069930, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 68385255, 24182513, 90058498, 17231624, 43615824, 61406677, 81820737, 38428660, - 36445723, 31223040, - ]), - y_minus_x: FieldElement2625([ - 5855666, 4990204, 53397016, 7294283, 59304582, 1924646, 65685689, 25642053, - 34039526, 9234252, - ]), - xy2d: FieldElement2625([ - 20590503, 24535444, 31529743, 26201766, 64402029, 10650547, 31559055, 21944845, - 18979185, 13396066, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 24474268, 38522535, 22267081, 37961786, 91172745, 25229251, 48291976, 13594781, - 33514650, 40576390, - ]), - y_minus_x: FieldElement2625([ - 55541958, 26988926, 45743778, 15928891, 40950559, 4315420, 41160136, 29637754, - 45628383, 12868081, - ]), - xy2d: FieldElement2625([ - 38473832, 13504660, 19988037, 31421671, 21078224, 6443208, 45662757, 2244499, - 54653067, 25465048, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 36513317, 13793478, 61256044, 33873567, 41385691, 60844964, 100195408, 8957936, - 51875216, 39094952, - ]), - y_minus_x: FieldElement2625([ - 55478669, 22050529, 58989363, 25911358, 2620055, 1022908, 43398120, 31985447, - 50980335, 18591624, - ]), - xy2d: FieldElement2625([ - 23152952, 775386, 27395463, 14006635, 57407746, 4649511, 1689819, 892185, - 55595587, 18348483, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 76878974, 43141169, 93604957, 37878551, 68665374, 30004407, 94562682, 38317558, - 47929249, 39421565, - ]), - y_minus_x: FieldElement2625([ - 34343820, 1927589, 31726409, 28801137, 23962433, 17534932, 27846558, 5931263, - 37359161, 17445976, - ]), - xy2d: FieldElement2625([ - 27461885, 30576896, 22380809, 1815854, 44075111, 30522493, 7283489, 18406359, - 47582163, 7734628, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 59098581, 57518046, 55988459, 39750469, 29344157, 20123547, 74694158, 30377805, - 85658360, 48856500, - ]), - y_minus_x: FieldElement2625([ - 34450527, 27383209, 59436070, 22502750, 6258877, 13504381, 10458790, 27135971, - 58236621, 8424745, - ]), - xy2d: FieldElement2625([ - 24687186, 8613276, 36441818, 30320886, 1863891, 31723888, 19206233, 7134917, - 55824382, 32725512, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 11334880, 24336410, 75134156, 46261950, 84632755, 23078360, 77352601, 18868970, - 62042829, 50053268, - ]), - y_minus_x: FieldElement2625([ - 8911542, 6887158, 57524604, 26595841, 11145640, 24010752, 17303924, 19430194, - 6536640, 10543906, - ]), - xy2d: FieldElement2625([ - 38162480, 15479762, 49642029, 568875, 65611181, 11223453, 64439674, 16928857, - 39873154, 8876770, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 41365946, 54541999, 118567760, 32707823, 101191041, 32758142, 33627041, - 15824473, 66504438, 24514614, - ]), - y_minus_x: FieldElement2625([ - 10330056, 70051, 7957388, 24551765, 9764901, 15609756, 27698697, 28664395, - 1657393, 3084098, - ]), - xy2d: FieldElement2625([ - 10477963, 26084172, 12119565, 20303627, 29016246, 28188843, 31280318, 14396151, - 36875289, 15272408, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54820536, 36723894, 28813182, 16658753, 92225296, 27923965, 109043770, - 54472724, 42094105, 35504935, - ]), - y_minus_x: FieldElement2625([ - 40928506, 9489186, 11053416, 18808271, 36055143, 5825629, 58724558, 24786899, - 15341278, 8373727, - ]), - xy2d: FieldElement2625([ - 28685821, 7759505, 52730348, 21551571, 35137043, 4079241, 298136, 23321830, - 64230656, 15190419, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 34175950, 47360767, 52771378, 51314432, 110213106, 10940926, 75778582, - 36296824, 108184414, 60233859, - ]), - y_minus_x: FieldElement2625([ - 65528476, 21825014, 41129205, 22109408, 49696989, 22641577, 9291593, 17306653, - 54954121, 6048604, - ]), - xy2d: FieldElement2625([ - 36803549, 14843443, 1539301, 11864366, 20201677, 1900163, 13934231, 5128323, - 11213262, 9168384, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 40828313, 44562278, 19408959, 32613674, 115624762, 29225850, 62020803, - 22449281, 20470156, 50710163, - ]), - y_minus_x: FieldElement2625([ - 43972811, 9282191, 14855179, 18164354, 59746048, 19145871, 44324911, 14461607, - 14042978, 5230683, - ]), - xy2d: FieldElement2625([ - 29969548, 30812838, 50396996, 25001989, 9175485, 31085458, 21556950, 3506042, - 61174973, 21104723, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 63964099, 42299092, 19704002, 38135710, 46678177, 6830682, 45824694, 42525944, - 38569674, 48880994, - ]), - y_minus_x: FieldElement2625([ - 47644235, 10110287, 49846336, 30050539, 43608476, 1355668, 51585814, 15300987, - 46594746, 9168259, - ]), - xy2d: FieldElement2625([ - 61755510, 4488612, 43305616, 16314346, 7780487, 17915493, 38160505, 9601604, - 33087103, 24543045, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 47665675, 18041531, 46311396, 21109108, 104393280, 43783891, 39664534, - 52108332, 61111992, 49219103, - ]), - y_minus_x: FieldElement2625([ - 23294591, 16921819, 44458082, 25083453, 27844203, 11461195, 13099750, 31094076, - 18151675, 13417686, - ]), - xy2d: FieldElement2625([ - 42385932, 29377914, 35958184, 5988918, 40250079, 6685064, 1661597, 21002991, - 15271675, 18101767, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 78541887, 20325766, 75348494, 28274914, 65123427, 32828713, 48410099, 35721975, - 60187562, 20114249, - ]), - y_minus_x: FieldElement2625([ - 35672693, 15575145, 30436815, 12192228, 44645511, 9395378, 57191156, 24915434, - 12215109, 12028277, - ]), - xy2d: FieldElement2625([ - 14098381, 6555944, 23007258, 5757252, 51681032, 20603929, 30123439, 4617780, - 50208775, 32898803, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 63082644, 51868028, 79002030, 47273095, 52299401, 35401816, 51288864, 43708440, - 91082124, 20869957, - ]), - y_minus_x: FieldElement2625([ - 40577025, 29858441, 65199965, 2534300, 35238307, 17004076, 18341389, 22134481, - 32013173, 23450893, - ]), - xy2d: FieldElement2625([ - 41629544, 10876442, 55337778, 18929291, 54739296, 1838103, 21911214, 6354752, - 4425632, 32716610, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 56675456, 18941465, 89338721, 30463384, 53917697, 34331160, 116802352, - 55088400, 71833867, 47599401, - ]), - y_minus_x: FieldElement2625([ - 19268631, 26250011, 1555348, 8692754, 45634805, 23643767, 6347389, 32142648, - 47586572, 17444675, - ]), - xy2d: FieldElement2625([ - 42244775, 12986007, 56209986, 27995847, 55796492, 33405905, 19541417, 8180106, - 9282262, 10282508, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 108012627, 37982977, 58447667, 20360168, 71207265, 52943606, 15522533, 8372215, - 72651459, 22851748, - ]), - y_minus_x: FieldElement2625([ - 56546323, 14895632, 26814552, 16880582, 49628109, 31065071, 64326972, 6993760, - 49014979, 10114654, - ]), - xy2d: FieldElement2625([ - 47001790, 32625013, 31422703, 10427861, 59998115, 6150668, 38017109, 22025285, - 25953724, 33448274, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 62874448, 59069571, 57989737, 36600431, 69210472, 54501569, 86498882, 39648727, - 63793584, 46385556, - ]), - y_minus_x: FieldElement2625([ - 51110167, 7578151, 5310217, 14408357, 33560244, 33329692, 31575953, 6326196, - 7381791, 31132593, - ]), - xy2d: FieldElement2625([ - 46206085, 3296810, 24736065, 17226043, 18374253, 7318640, 6295303, 8082724, - 51746375, 12339663, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 27724736, 35845589, 73197064, 19369633, 68901590, 39412065, 80957277, 15768921, - 92200031, 14856293, - ]), - y_minus_x: FieldElement2625([ - 48242193, 8331042, 24373479, 8541013, 66406866, 24284974, 12927299, 20858939, - 44926390, 24541532, - ]), - xy2d: FieldElement2625([ - 55685435, 28132841, 11632844, 3405020, 30536730, 21880393, 39848098, 13866389, - 30146206, 9142070, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 71032974, 18246915, 120400605, 23499470, 79400683, 32886065, 39406089, 9326383, - 58871006, 37725725, - ]), - y_minus_x: FieldElement2625([ - 51186905, 16037936, 6713787, 16606682, 45496729, 2790943, 26396185, 3731949, - 345228, 28091483, - ]), - xy2d: FieldElement2625([ - 45781307, 13448258, 25284571, 1143661, 20614966, 24705045, 2031538, 21163201, - 50855680, 19972348, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 98125037, 16832002, 93480255, 52657630, 62081513, 14854136, 17477601, 37397089, - 28012649, 50703444, - ]), - y_minus_x: FieldElement2625([ - 62033029, 9368965, 58546785, 28953529, 51858910, 6970559, 57918991, 16292056, - 58241707, 3507939, - ]), - xy2d: FieldElement2625([ - 29439664, 3537914, 23333589, 6997794, 49553303, 22536363, 51899661, 18503164, - 57943934, 6580395, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54922984, 59429075, 83547131, 10826159, 58412047, 27318820, 84969307, 24280585, - 65013061, 42858998, - ]), - y_minus_x: FieldElement2625([ - 20714545, 29217521, 29088194, 7406487, 11426967, 28458727, 14792666, 18945815, - 5289420, 33077305, - ]), - xy2d: FieldElement2625([ - 50443312, 22903641, 60948518, 20248671, 9192019, 31751970, 17271489, 12349094, - 26939669, 29802138, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54218947, 9373457, 98704712, 16374214, 21471720, 13221525, 39825369, 54760304, - 63410056, 33672318, - ]), - y_minus_x: FieldElement2625([ - 22263325, 26994382, 3984569, 22379786, 51994855, 32987646, 28311252, 5358056, - 43789084, 541963, - ]), - xy2d: FieldElement2625([ - 16259200, 3261970, 2309254, 18019958, 50223152, 28972515, 24134069, 16848603, - 53771797, 20002236, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 76487005, 20414245, 111371745, 20809166, 95307144, 59864765, 64709178, - 32837080, 67799289, 48430675, - ]), - y_minus_x: FieldElement2625([ - 24977353, 33240048, 58884894, 20089345, 28432342, 32378079, 54040059, 21257083, - 44727879, 6618998, - ]), - xy2d: FieldElement2625([ - 65570671, 11685645, 12944378, 13682314, 42719353, 19141238, 8044828, 19737104, - 32239828, 27901670, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 48505798, 38317421, 66182613, 42439735, 105805247, 30367115, 76890510, - 23204372, 32779358, 5095274, - ]), - y_minus_x: FieldElement2625([ - 34100715, 28339925, 34843976, 29869215, 9460460, 24227009, 42507207, 14506723, - 21639561, 30924196, - ]), - xy2d: FieldElement2625([ - 50707921, 20442216, 25239337, 15531969, 3987758, 29055114, 65819361, 26690896, - 17874573, 558605, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 53508716, 10240080, 76280747, 16131052, 46239610, 43154131, 100608350, - 38634582, 69194755, 38674192, - ]), - y_minus_x: FieldElement2625([ - 44903700, 31034903, 50727262, 414690, 42089314, 2170429, 30634760, 25190818, - 35108870, 27794547, - ]), - xy2d: FieldElement2625([ - 60263160, 15791201, 8550074, 32241778, 29928808, 21462176, 27534429, 26362287, - 44757485, 12961481, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 42616785, 57538092, 10368192, 11582341, 110820435, 31309143, 83642793, 8206995, - 104023076, 28394792, - ]), - y_minus_x: FieldElement2625([ - 55987368, 30172197, 2307365, 6362031, 66973409, 8868176, 50273234, 7031274, - 7589640, 8945490, - ]), - xy2d: FieldElement2625([ - 34956097, 8917966, 6661220, 21876816, 65916803, 17761038, 7251488, 22372252, - 24099108, 19098262, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 72128384, 25646961, 71352990, 18840075, 107284455, 40007595, 47990681, - 20265406, 127985831, 56828126, - ]), - y_minus_x: FieldElement2625([ - 10853575, 10721687, 26480089, 5861829, 44113045, 1972174, 65242217, 22996533, - 63745412, 27113307, - ]), - xy2d: FieldElement2625([ - 50106456, 5906789, 221599, 26991285, 7828207, 20305514, 24362660, 31546264, - 53242455, 7421391, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 75248772, 27007934, 99366509, 27663885, 97484582, 1886180, 113042620, 48995682, - 95935221, 29431402, - ]), - y_minus_x: FieldElement2625([ - 6267067, 9695052, 7709135, 16950835, 34239795, 31668296, 14795159, 25714308, - 13746020, 31812384, - ]), - xy2d: FieldElement2625([ - 28584883, 7787108, 60375922, 18503702, 22846040, 25983196, 63926927, 33190907, - 4771361, 25134474, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 92058101, 6376278, 39642383, 25379823, 48462709, 23623825, 100652432, 54967168, - 70678489, 44897024, - ]), - y_minus_x: FieldElement2625([ - 26514970, 4740088, 27912651, 3697550, 19331575, 22082093, 6809885, 4608608, - 7325975, 18753361, - ]), - xy2d: FieldElement2625([ - 55490446, 19000001, 42787651, 7655127, 65739590, 5214311, 39708324, 10258389, - 49462170, 25367739, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 11431185, 49377439, 93679108, 47883555, 85138853, 38350513, 35662684, 49135095, - 76389221, 29580744, - ]), - y_minus_x: FieldElement2625([ - 66948081, 23228174, 44253547, 29249434, 46247496, 19933429, 34297962, 22372809, - 51563772, 4387440, - ]), - xy2d: FieldElement2625([ - 46309467, 12194511, 3937617, 27748540, 39954043, 9340369, 42594872, 8548136, - 20617071, 26072431, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 66170039, 29623845, 58394552, 49679149, 91711988, 27329038, 53333511, 55233041, - 91454545, 10325459, - ]), - y_minus_x: FieldElement2625([ - 47253587, 31985546, 44906155, 8714033, 14007766, 6928528, 16318175, 32543743, - 4766742, 3552007, - ]), - xy2d: FieldElement2625([ - 45357481, 16823515, 1351762, 32751011, 63099193, 3950934, 3217514, 14481909, - 10988822, 29559670, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 15564288, 19242862, 70210106, 39238579, 97555643, 25503075, 79785990, 27049088, - 58813011, 46850436, - ]), - y_minus_x: FieldElement2625([ - 57666574, 6624295, 36809900, 21640754, 62437882, 31497052, 31521203, 9614054, - 37108040, 12074673, - ]), - xy2d: FieldElement2625([ - 4771172, 33419193, 14290748, 20464580, 27992297, 14998318, 65694928, 31997715, - 29832612, 17163397, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 7064865, 59567690, 115055764, 62041325, 48217593, 30641695, 92934105, 38847728, - 39986203, 46656021, - ]), - y_minus_x: FieldElement2625([ - 64810282, 2439669, 59642254, 1719964, 39841323, 17225986, 32512468, 28236839, - 36752793, 29363474, - ]), - xy2d: FieldElement2625([ - 37102324, 10162315, 33928688, 3981722, 50626726, 20484387, 14413973, 9515896, - 19568978, 9628812, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 33053784, 33753789, 83003454, 35137490, 94489106, 28973996, 49269969, 61002024, - 60817076, 36992171, - ]), - y_minus_x: FieldElement2625([ - 48129987, 3884492, 19469877, 12726490, 15913552, 13614290, 44147131, 70103, - 7463304, 4176122, - ]), - xy2d: FieldElement2625([ - 39984863, 10659916, 11482427, 17484051, 12771466, 26919315, 34389459, 28231680, - 24216881, 5944158, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 76002989, 41005405, 64444714, 57343111, 106137209, 21165315, 19345745, - 48235228, 78741856, 5847884, - ]), - y_minus_x: FieldElement2625([ - 26942781, 31239115, 9129563, 28647825, 26024104, 11769399, 55590027, 6367193, - 57381634, 4782139, - ]), - xy2d: FieldElement2625([ - 19916442, 28726022, 44198159, 22140040, 25606323, 27581991, 33253852, 8220911, - 6358847, 31680575, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 67910273, 31472729, 16569427, 44619599, 29875703, 33651059, 75017251, 29073951, - 53570360, 34941586, - ]), - y_minus_x: FieldElement2625([ - 19646058, 5720633, 55692158, 12814208, 11607948, 12749789, 14147075, 15156355, - 45242033, 11835259, - ]), - xy2d: FieldElement2625([ - 19299512, 1155910, 28703737, 14890794, 2925026, 7269399, 26121523, 15467869, - 40548314, 5052482, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 64091413, 43612637, 69089700, 37518674, 22160965, 12322533, 60677741, 20936246, - 12228556, 26550755, - ]), - y_minus_x: FieldElement2625([ - 32944382, 14922211, 44263970, 5188527, 21913450, 24834489, 4001464, 13238564, - 60994061, 8653814, - ]), - xy2d: FieldElement2625([ - 22865569, 28901697, 27603667, 21009037, 14348957, 8234005, 24808405, 5719875, - 28483275, 2841751, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 117796741, 32441125, 66781144, 21446575, 21886281, 51556090, 65220896, - 33238773, 87040921, 20815228, - ]), - y_minus_x: FieldElement2625([ - 55452759, 10087520, 58243976, 28018288, 47830290, 30498519, 3999227, 13239134, - 62331395, 19644223, - ]), - xy2d: FieldElement2625([ - 1382174, 21859713, 17266789, 9194690, 53784508, 9720080, 20403944, 11284705, - 53095046, 3093229, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 83759766, 56070931, 66044684, 35125060, 58779117, 40907184, 66806439, 16271224, - 43059443, 26862581, - ]), - y_minus_x: FieldElement2625([ - 45197768, 27626490, 62497547, 27994275, 35364760, 22769138, 24123613, 15193618, - 45456747, 16815042, - ]), - xy2d: FieldElement2625([ - 57172930, 29264984, 41829040, 4372841, 2087473, 10399484, 31870908, 14690798, - 17361620, 11864968, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 55801216, 39764803, 80315437, 39360751, 105200035, 19587230, 54777658, - 26067830, 41530403, 50868174, - ]), - y_minus_x: FieldElement2625([ - 14668443, 21284197, 26039038, 15305210, 25515617, 4542480, 10453892, 6577524, - 9145645, 27110552, - ]), - xy2d: FieldElement2625([ - 5974855, 3053895, 57675815, 23169240, 35243739, 3225008, 59136222, 3936127, - 61456591, 30504127, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 97734231, 28825031, 41552902, 20761565, 46624288, 41249530, 17097187, 50805368, - 106217947, 35358062, - ]), - y_minus_x: FieldElement2625([ - 63555773, 9865098, 61880298, 4272700, 61435032, 16864731, 14911343, 12196514, - 45703375, 7047411, - ]), - xy2d: FieldElement2625([ - 20093258, 9920966, 55970670, 28210574, 13161586, 12044805, 34252013, 4124600, - 34765036, 23296865, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 46320021, 14084653, 53577151, 41396578, 19119037, 19731827, 71861240, 24839791, - 45429205, 35842469, - ]), - y_minus_x: FieldElement2625([ - 40289628, 30270716, 29965058, 3039786, 52635099, 2540456, 29457502, 14625692, - 42289247, 12570231, - ]), - xy2d: FieldElement2625([ - 66045306, 22002608, 16920317, 12494842, 1278292, 27685323, 45948920, 30055751, - 55134159, 4724942, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 85069815, 21778897, 62967895, 23851901, 58232301, 32143814, 54201480, 24894499, - 104641427, 35458286, - ]), - y_minus_x: FieldElement2625([ - 23134274, 19275300, 56426866, 31942495, 20684484, 15770816, 54119114, 3190295, - 26955097, 14109738, - ]), - xy2d: FieldElement2625([ - 15308788, 5320727, 36995055, 19235554, 22902007, 7767164, 29425325, 22276870, - 31960941, 11934971, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 39713134, 41990227, 71218507, 12222638, 109589860, 14818667, 87747037, - 38429459, 77600255, 34934149, - ]), - y_minus_x: FieldElement2625([ - 53949449, 9197840, 3875503, 24618324, 65725151, 27674630, 33518458, 16176658, - 21432314, 12180697, - ]), - xy2d: FieldElement2625([ - 55321537, 11500837, 13787581, 19721842, 44678184, 10140204, 1465425, 12689540, - 56807545, 19681548, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 72522936, 18168390, 46101199, 43198001, 79943833, 34740580, 64485947, 32212200, - 26128230, 39587344, - ]), - y_minus_x: FieldElement2625([ - 40771450, 19788269, 32496024, 19900513, 17847800, 20885276, 3604024, 8316894, - 41233830, 23117073, - ]), - xy2d: FieldElement2625([ - 3296484, 6223048, 24680646, 21307972, 44056843, 5903204, 58246567, 28915267, - 12376616, 3188849, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 29190450, 18895386, 27549112, 32370916, 70628929, 22857130, 32049514, 26245319, - 50999629, 57256556, - ]), - y_minus_x: FieldElement2625([ - 52364359, 24245275, 735817, 32955454, 46701176, 28496527, 25246077, 17758763, - 18640740, 32593455, - ]), - xy2d: FieldElement2625([ - 60180029, 17123636, 10361373, 5642961, 4910474, 12345252, 35470478, 33060001, - 10530746, 1053335, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 104951742, 52922057, 120679510, 54991489, 47651803, 56453479, 102755357, - 30605445, 24018830, 48581076, - ]), - y_minus_x: FieldElement2625([ - 44516310, 30409154, 64819587, 5953842, 53668675, 9425630, 25310643, 13003497, - 64794073, 18408815, - ]), - xy2d: FieldElement2625([ - 39688860, 32951110, 59064879, 31885314, 41016598, 13987818, 39811242, 187898, - 43942445, 31022696, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 45364447, 19743956, 68953703, 38575859, 123783328, 17642957, 76825530, - 49821353, 62038646, 34280530, - ]), - y_minus_x: FieldElement2625([ - 29370903, 27500434, 7334070, 18212173, 9385286, 2247707, 53446902, 28714970, - 30007387, 17731091, - ]), - xy2d: FieldElement2625([ - 66172485, 16086690, 23751945, 33011114, 65941325, 28365395, 9137108, 730663, - 9835848, 4555336, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 43732410, 34964877, 44855110, 54209249, 97976497, 49381408, 17693929, 34099128, - 55123565, 45977077, - ]), - y_minus_x: FieldElement2625([ - 31117226, 21338698, 53606025, 6561946, 57231997, 20796761, 61990178, 29457725, - 29120152, 13924425, - ]), - xy2d: FieldElement2625([ - 49707966, 19321222, 19675798, 30819676, 56101901, 27695611, 57724924, 22236731, - 7240930, 33317044, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 35747087, 22207651, 119210280, 27698212, 111764387, 54956091, 68331198, - 37943914, 70402500, 51557120, - ]), - y_minus_x: FieldElement2625([ - 50424044, 19110186, 11038543, 11054958, 53307689, 30215898, 42789283, 7733546, - 12796905, 27218610, - ]), - xy2d: FieldElement2625([ - 58349431, 22736595, 41689999, 10783768, 36493307, 23807620, 38855524, 3647835, - 3222231, 22393970, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 85714958, 35247531, 108769341, 51938590, 71221215, 43599452, 23603892, - 31506198, 59558087, 36039416, - ]), - y_minus_x: FieldElement2625([ - 9255298, 30423235, 54952701, 32550175, 13098012, 24339566, 16377219, 31451620, - 47306788, 30519729, - ]), - xy2d: FieldElement2625([ - 44379556, 7496159, 61366665, 11329248, 19991973, 30206930, 35390715, 9936965, - 37011176, 22935634, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 88987435, 28553134, 71447199, 47198328, 64071998, 13160959, 86817760, 5415496, - 59748361, 29445138, - ]), - y_minus_x: FieldElement2625([ - 27736842, 10103576, 12500508, 8502413, 63695848, 23920873, 10436917, 32004156, - 43449720, 25422331, - ]), - xy2d: FieldElement2625([ - 19492550, 21450067, 37426887, 32701801, 63900692, 12403436, 30066266, 8367329, - 13243957, 8709688, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 79123950, 36355692, 95306994, 10151020, 91926984, 28811298, 55914672, 27908697, - 72259831, 40828617, - ]), - y_minus_x: FieldElement2625([ - 2831347, 21062286, 1478974, 6122054, 23825128, 20820846, 31097298, 6083058, - 31021603, 23760822, - ]), - xy2d: FieldElement2625([ - 64578913, 31324785, 445612, 10720828, 53259337, 22048494, 43601132, 16354464, - 15067285, 19406725, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 74949787, 47592304, 100852864, 49488446, 66380650, 29911725, 88512851, - 34612017, 47729401, 21151211, - ]), - y_minus_x: FieldElement2625([ - 915865, 17085158, 15608284, 24765302, 42751837, 6060029, 49737545, 8410996, - 59888403, 16527024, - ]), - xy2d: FieldElement2625([ - 32922597, 32997445, 20336073, 17369864, 10903704, 28169945, 16957573, 52992, - 23834301, 6588044, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 32752011, 44787382, 70490858, 24839565, 22652987, 22810329, 17159698, 50243539, - 46794283, 32248439, - ]), - y_minus_x: FieldElement2625([ - 62419196, 9166775, 41398568, 22707125, 11576751, 12733943, 7924251, 30802151, - 1976122, 26305405, - ]), - xy2d: FieldElement2625([ - 21251203, 16309901, 64125849, 26771309, 30810596, 12967303, 156041, 30183180, - 12331344, 25317235, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 75760459, 29077399, 118132091, 28557436, 80111370, 36505236, 96163290, - 28447461, 77116999, 28886530, - ]), - y_minus_x: FieldElement2625([ - 31486061, 15114593, 52847614, 12951353, 14369431, 26166587, 16347320, 19892343, - 8684154, 23021480, - ]), - xy2d: FieldElement2625([ - 19443825, 11385320, 24468943, 23895364, 43189605, 2187568, 40845657, 27467510, - 31316347, 14219878, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 38514355, 1193784, 99354083, 11392484, 31092169, 49277233, 94254877, 40546840, - 29126554, 42761822, - ]), - y_minus_x: FieldElement2625([ - 32382916, 1110093, 18477781, 11028262, 39697101, 26006320, 62128346, 10843781, - 59151264, 19118701, - ]), - xy2d: FieldElement2625([ - 2814918, 7836403, 27519878, 25686276, 46214848, 22000742, 45614304, 8550129, - 28346258, 1994730, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 47530546, 41639976, 53108344, 29605809, 69894701, 17323124, 47591912, 40729325, - 22628101, 41669612, - ]), - y_minus_x: FieldElement2625([ - 36703732, 955510, 55975026, 18476362, 34661776, 20276352, 41457285, 3317159, - 57165847, 930271, - ]), - xy2d: FieldElement2625([ - 51805164, 26720662, 28856489, 1357446, 23421993, 1057177, 24091212, 32165462, - 44343487, 22903716, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 44357614, 28250434, 54201256, 54339997, 51297351, 25757378, 52269845, 50554643, - 65241844, 41953401, - ]), - y_minus_x: FieldElement2625([ - 35139535, 2106402, 62372504, 1362500, 12813763, 16200670, 22981545, 27263159, - 18009407, 17781660, - ]), - xy2d: FieldElement2625([ - 49887941, 24009210, 39324209, 14166834, 29815394, 7444469, 29551787, 29827013, - 19288548, 1325865, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 82209002, 51273111, 110293748, 32549332, 107767535, 49063838, 79485593, - 30075285, 100274970, 25511681, - ]), - y_minus_x: FieldElement2625([ - 20909212, 13023121, 57899112, 16251777, 61330449, 25459517, 12412150, 10018715, - 2213263, 19676059, - ]), - xy2d: FieldElement2625([ - 32529814, 22479743, 30361438, 16864679, 57972923, 1513225, 22922121, 6382134, - 61341936, 8371347, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77032307, 44825931, 79725657, 37099153, 104219359, 31832804, 12891686, - 25361300, 40665920, 44040575, - ]), - y_minus_x: FieldElement2625([ - 44511638, 26541766, 8587002, 25296571, 4084308, 20584370, 361725, 2610596, - 43187334, 22099236, - ]), - xy2d: FieldElement2625([ - 5408392, 32417741, 62139741, 10561667, 24145918, 14240566, 31319731, 29318891, - 19985174, 30118346, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 53114388, 50171252, 81658109, 36895530, 99264821, 13648975, 49531796, 8849296, - 67173894, 41925115, - ]), - y_minus_x: FieldElement2625([ - 58787919, 21504805, 31204562, 5839400, 46481576, 32497154, 47665921, 6922163, - 12743482, 23753914, - ]), - xy2d: FieldElement2625([ - 64747493, 12678784, 28815050, 4759974, 43215817, 4884716, 23783145, 11038569, - 18800704, 255233, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 61839168, 31780545, 13957885, 41545147, 23132994, 34283205, 80502710, 42621388, - 86367551, 52355070, - ]), - y_minus_x: FieldElement2625([ - 64172210, 22726896, 56676774, 14516792, 63468078, 4372540, 35173943, 2209389, - 65584811, 2055793, - ]), - xy2d: FieldElement2625([ - 580882, 16705327, 5468415, 30871414, 36182444, 18858431, 59905517, 24560042, - 37087844, 7394434, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 90947654, 35377159, 118479284, 48797157, 75426955, 29821327, 45436683, - 30062226, 62287122, 48354352, - ]), - y_minus_x: FieldElement2625([ - 13345610, 9759151, 3371034, 17416641, 16353038, 8577942, 31129804, 13496856, - 58052846, 7402517, - ]), - xy2d: FieldElement2625([ - 2286874, 29118501, 47066405, 31546095, 53412636, 5038121, 11006906, 17794080, - 8205060, 1607563, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 81522931, 25552299, 70440693, 63900646, 89358013, 27960243, 85473524, 30647473, - 30019586, 24525154, - ]), - y_minus_x: FieldElement2625([ - 39420813, 1585952, 56333811, 931068, 37988643, 22552112, 52698034, 12029092, - 9944378, 8024, - ]), - xy2d: FieldElement2625([ - 4368715, 29844802, 29874199, 18531449, 46878477, 22143727, 50994269, 32555346, - 58966475, 5640029, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77408455, 13746482, 11661824, 16234854, 74739102, 5998373, 76918751, 16859867, - 82328661, 19226648, - ]), - y_minus_x: FieldElement2625([ - 27425505, 27835351, 3055005, 10660664, 23458024, 595578, 51710259, 32381236, - 48766680, 9742716, - ]), - xy2d: FieldElement2625([ - 6744077, 2427284, 26042789, 2720740, 66260958, 1118973, 32324614, 7406442, - 12420155, 1994844, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 81121366, 62084143, 115833273, 23975961, 107732385, 29617991, 121184249, - 22644627, 91428792, 27108098, - ]), - y_minus_x: FieldElement2625([ - 16412671, 29047065, 10772640, 15929391, 50040076, 28895810, 10555944, 23070383, - 37006495, 28815383, - ]), - xy2d: FieldElement2625([ - 22397363, 25786748, 57815702, 20761563, 17166286, 23799296, 39775798, 6199365, - 21880021, 21303672, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 62825538, 5368522, 35991846, 41717820, 103894664, 36763558, 83666014, 42445160, - 75949308, 38512191, - ]), - y_minus_x: FieldElement2625([ - 51661137, 709326, 60189418, 22684253, 37330941, 6522331, 45388683, 12130071, - 52312361, 5005756, - ]), - xy2d: FieldElement2625([ - 64994094, 19246303, 23019041, 15765735, 41839181, 6002751, 10183197, 20315106, - 50713577, 31378319, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 115191953, 35186435, 80575154, 59113763, 110577275, 16573535, 35094956, - 30497327, 22208661, 35554900, - ]), - y_minus_x: FieldElement2625([ - 3065054, 32141671, 41510189, 33192999, 49425798, 27851016, 58944651, 11248526, - 63417650, 26140247, - ]), - xy2d: FieldElement2625([ - 10379208, 27508878, 8877318, 1473647, 37817580, 21046851, 16690914, 2553332, - 63976176, 16400288, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 82825513, 34808697, 115745037, 41000704, 58659945, 6344163, 45011593, 26268851, - 26894936, 42686498, - ]), - y_minus_x: FieldElement2625([ - 24158868, 12938817, 11085297, 25376834, 39045385, 29097348, 36532400, 64451, - 60291780, 30861549, - ]), - xy2d: FieldElement2625([ - 13488534, 7794716, 22236231, 5989356, 25426474, 20976224, 2350709, 30135921, - 62420857, 2364225, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 83443897, 9132433, 92749446, 40233319, 68834491, 42072368, 55301839, 21856974, - 15445874, 25756331, - ]), - y_minus_x: FieldElement2625([ - 29004188, 25687351, 28661401, 32914020, 54314860, 25611345, 31863254, 29418892, - 66830813, 17795152, - ]), - xy2d: FieldElement2625([ - 60986784, 18687766, 38493958, 14569918, 56250865, 29962602, 10343411, 26578142, - 37280576, 22738620, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 94190495, 37018415, 14099041, 29036828, 68725166, 27348827, 96651499, 15372178, - 84402661, 34515140, - ]), - y_minus_x: FieldElement2625([ - 20263915, 11434237, 61343429, 11236809, 13505955, 22697330, 50997518, 6493121, - 47724353, 7639713, - ]), - xy2d: FieldElement2625([ - 64278047, 18715199, 25403037, 25339236, 58791851, 17380732, 18006286, 17510682, - 29994676, 17746311, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 76878673, 38757082, 110060329, 19923038, 106166724, 21992806, 42495722, - 53248081, 35924287, 34263895, - ]), - y_minus_x: FieldElement2625([ - 12286395, 13076066, 45333675, 32377809, 42105665, 4057651, 35090736, 24663557, - 16102006, 13205847, - ]), - xy2d: FieldElement2625([ - 13733362, 5599946, 10557076, 3195751, 61550873, 8536969, 41568694, 8525971, - 10151379, 10394400, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 71133505, 17416880, 89545125, 12276533, 58009849, 64422764, 86807091, 11743038, - 100915394, 42488844, - ]), - y_minus_x: FieldElement2625([ - 51229064, 29029191, 58528116, 30620370, 14634844, 32856154, 57659786, 3137093, - 55571978, 11721157, - ]), - xy2d: FieldElement2625([ - 17555920, 28540494, 8268605, 2331751, 44370049, 9761012, 9319229, 8835153, - 57903375, 32274386, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 66647436, 25724417, 87722981, 16688287, 59594098, 28747312, 89409167, 34059860, - 73217325, 27371016, - ]), - y_minus_x: FieldElement2625([ - 62038564, 12367916, 36445330, 3234472, 32617080, 25131790, 29880582, 20071101, - 40210373, 25686972, - ]), - xy2d: FieldElement2625([ - 35133562, 5726538, 26934134, 10237677, 63935147, 32949378, 24199303, 3795095, - 7592688, 18562353, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 21594413, 18590204, 84575271, 63031641, 32537082, 36294330, 73516586, 12018832, - 38852812, 37852843, - ]), - y_minus_x: FieldElement2625([ - 46458361, 21592935, 39872588, 570497, 3767144, 31836892, 13891941, 31985238, - 13717173, 10805743, - ]), - xy2d: FieldElement2625([ - 52432215, 17910135, 15287173, 11927123, 24177847, 25378864, 66312432, 14860608, - 40169934, 27690595, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 80071405, 38866230, 57048095, 45212711, 85964149, 25600230, 80395126, 54300159, - 62727806, 9882021, - ]), - y_minus_x: FieldElement2625([ - 18512060, 11319350, 46985740, 15090308, 18818594, 5271736, 44380960, 3666878, - 43141434, 30255002, - ]), - xy2d: FieldElement2625([ - 60319844, 30408388, 16192428, 13241070, 15898607, 19348318, 57023983, 26893321, - 64705764, 5276064, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 97278672, 28236783, 93415069, 55358004, 94923826, 40623698, 74261714, 37239413, - 68558087, 13082860, - ]), - y_minus_x: FieldElement2625([ - 10342807, 3098505, 2119311, 193222, 25702612, 12233820, 23697382, 15056736, - 46092426, 25352431, - ]), - xy2d: FieldElement2625([ - 33958735, 3261607, 22745853, 7948688, 19370557, 18376767, 40936887, 6482813, - 56808784, 22494330, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 32869439, 61700319, 25609741, 49233102, 56421094, 51637792, 26112419, 36075440, - 44444575, 40459246, - ]), - y_minus_x: FieldElement2625([ - 29506904, 4457497, 3377935, 23757988, 36598817, 12935079, 1561737, 3841096, - 38105225, 26896789, - ]), - xy2d: FieldElement2625([ - 10340844, 26924055, 48452231, 31276001, 12621150, 20215377, 30878496, 21730062, - 41524312, 5181965, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 25940096, 20896407, 17324187, 56801490, 58437394, 15029093, 91505116, 17103509, - 64786011, 21165857, - ]), - y_minus_x: FieldElement2625([ - 45343161, 9916822, 65808455, 4079497, 66080518, 11909558, 1782390, 12641087, - 20603771, 26992690, - ]), - xy2d: FieldElement2625([ - 48226577, 21881051, 24849421, 11501709, 13161720, 28785558, 1925522, 11914390, - 4662781, 7820689, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 79349895, 33128449, 75241554, 42948365, 32846759, 31954812, 29749455, 45727356, - 83245615, 48818451, - ]), - y_minus_x: FieldElement2625([ - 56758909, 18873868, 58896884, 2330219, 49446315, 19008651, 10658212, 6671822, - 19012087, 3772772, - ]), - xy2d: FieldElement2625([ - 3753511, 30133366, 10617073, 2028709, 14841030, 26832768, 28718731, 17791548, - 20527770, 12988982, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 52286341, 27757162, 63400876, 12689772, 66209881, 22639565, 110034681, - 56543919, 70408527, 54683910, - ]), - y_minus_x: FieldElement2625([ - 50331161, 18301130, 57466446, 4978982, 3308785, 8755439, 6943197, 6461331, - 41525717, 8991217, - ]), - xy2d: FieldElement2625([ - 49882601, 1816361, 65435576, 27467992, 31783887, 25378441, 34160718, 7417949, - 36866577, 1507264, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 29692644, 40384323, 56610063, 37889327, 88054838, 21647935, 38221255, 41763822, - 14606361, 22907359, - ]), - y_minus_x: FieldElement2625([ - 63627275, 8707080, 32188102, 5672294, 22096700, 1711240, 34088169, 9761486, - 4170404, 31469107, - ]), - xy2d: FieldElement2625([ - 55521375, 14855944, 62981086, 32022574, 40459774, 15084045, 22186522, 16002000, - 52832027, 25153633, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 62297389, 47315460, 35404986, 31070512, 63796392, 41423478, 59995291, 23934339, - 80349708, 44520301, - ]), - y_minus_x: FieldElement2625([ - 59366301, 25297669, 52340529, 19898171, 43876480, 12387165, 4498947, 14147411, - 29514390, 4302863, - ]), - xy2d: FieldElement2625([ - 53695440, 21146572, 20757301, 19752600, 14785142, 8976368, 62047588, 31410058, - 17846987, 19582505, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 64864393, 32799703, 62511833, 32488122, 60861691, 35009730, 112569999, - 24339641, 61886162, 46204698, - ]), - y_minus_x: FieldElement2625([ - 57202067, 17484121, 21134159, 12198166, 40044289, 708125, 387813, 13770293, - 47974538, 10958662, - ]), - xy2d: FieldElement2625([ - 22470984, 12369526, 23446014, 28113323, 45588061, 23855708, 55336367, 21979976, - 42025033, 4271861, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 109048144, 57055220, 47199530, 48916026, 61124505, 35713623, 67184238, - 62830334, 101691505, 42024103, - ]), - y_minus_x: FieldElement2625([ - 15854951, 4148314, 58214974, 7259001, 11666551, 13824734, 36577666, 2697371, - 24154791, 24093489, - ]), - xy2d: FieldElement2625([ - 15446137, 17747788, 29759746, 14019369, 30811221, 23944241, 35526855, 12840103, - 24913809, 9815020, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 62399559, 27940162, 35267365, 21265538, 52665326, 44353845, 125114051, - 46993199, 85843991, 43020669, - ]), - y_minus_x: FieldElement2625([ - 11933045, 9281483, 5081055, 28370608, 64480701, 28648802, 59381042, 22658328, - 44380208, 16199063, - ]), - xy2d: FieldElement2625([ - 14576810, 379472, 40322331, 25237195, 37682355, 22741457, 67006097, 1876698, - 30801119, 2164795, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 15995067, 36754305, 13672554, 13712240, 47730029, 62461217, 121136116, - 51612593, 53616055, 34822483, - ]), - y_minus_x: FieldElement2625([ - 56818250, 29895392, 63822271, 10948817, 23037027, 3794475, 63638526, 20954210, - 50053494, 3565903, - ]), - xy2d: FieldElement2625([ - 29210069, 24135095, 61189071, 28601646, 10834810, 20226706, 50596761, 22733718, - 39946641, 19523900, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 121055819, 49063018, 83772567, 25398281, 38758921, 42573554, 37925442, - 29785008, 69352974, 19552452, - ]), - y_minus_x: FieldElement2625([ - 61955989, 29753495, 57802388, 27482848, 16243068, 14684434, 41435776, 17373631, - 13491505, 4641841, - ]), - xy2d: FieldElement2625([ - 10813398, 643330, 47920349, 32825515, 30292061, 16954354, 27548446, 25833190, - 14476988, 20787001, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77400943, 9984944, 73590300, 41834336, 59857349, 40587174, 27282936, 31910173, - 106304917, 12651322, - ]), - y_minus_x: FieldElement2625([ - 35923332, 32741048, 22271203, 11835308, 10201545, 15351028, 17099662, 3988035, - 21721536, 30405492, - ]), - xy2d: FieldElement2625([ - 10202177, 27008593, 35735631, 23979793, 34958221, 25434748, 54202543, 3852693, - 13216206, 14842320, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 51293205, 22953365, 60569911, 26295436, 60124204, 26972653, 35608016, 47320255, - 106783330, 43454614, - ]), - y_minus_x: FieldElement2625([ - 14465486, 19721101, 34974879, 18815558, 39665676, 12990491, 33046193, 15796406, - 60056998, 25514317, - ]), - xy2d: FieldElement2625([ - 30924398, 25274812, 6359015, 20738097, 16508376, 9071735, 41620263, 15413634, - 9524356, 26535554, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 12274182, 20378885, 99736504, 65323537, 73845487, 13267304, 72346523, 28444948, - 82772379, 37590215, - ]), - y_minus_x: FieldElement2625([ - 64157555, 8903984, 17349946, 601635, 50676049, 28941875, 53376124, 17665097, - 44850385, 4659090, - ]), - xy2d: FieldElement2625([ - 50192582, 28601458, 36715152, 18395610, 20774811, 15897498, 5736189, 15026997, - 64930608, 20098846, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 58249865, 31335375, 28571665, 56953346, 66634395, 23448733, 63307367, 33832526, - 23440561, 33264224, - ]), - y_minus_x: FieldElement2625([ - 10226222, 27625730, 15139955, 120818, 52241171, 5218602, 32937275, 11551483, - 50536904, 26111567, - ]), - xy2d: FieldElement2625([ - 17932739, 21117156, 43069306, 10749059, 11316803, 7535897, 22503767, 5561594, - 63462240, 3898660, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 74858752, 32584864, 50769132, 33537967, 42090752, 15122142, 65535333, 40706961, - 88940025, 34799664, - ]), - y_minus_x: FieldElement2625([ - 26958440, 18896406, 4314585, 8346991, 61431100, 11960071, 34519569, 32934396, - 36706772, 16838219, - ]), - xy2d: FieldElement2625([ - 54942968, 9166946, 33491384, 13673479, 29787085, 13096535, 6280834, 14587357, - 44770839, 13987524, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 109867800, 7778773, 88224864, 49127028, 62275597, 28196653, 62807965, 28429792, - 59639082, 30696363, - ]), - y_minus_x: FieldElement2625([ - 9681908, 26817309, 35157219, 13591837, 60225043, 386949, 31622781, 6439245, - 52527852, 4091396, - ]), - xy2d: FieldElement2625([ - 58682418, 1470726, 38999185, 31957441, 3978626, 28430809, 47486180, 12092162, - 29077877, 18812444, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 72378032, 26694705, 120987516, 25533715, 25932562, 35317984, 61502753, - 28048550, 47091016, 2357888, - ]), - y_minus_x: FieldElement2625([ - 32264008, 18146780, 61721128, 32394338, 65017541, 29607531, 23104803, 20684524, - 5727337, 189038, - ]), - xy2d: FieldElement2625([ - 14609104, 24599962, 61108297, 16931650, 52531476, 25810533, 40363694, 10942114, - 41219933, 18669734, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 87622345, 39112362, 51504250, 41383962, 93522806, 31535027, 45729895, 41026212, - 13913676, 28416557, - ]), - y_minus_x: FieldElement2625([ - 41534488, 11967825, 29233242, 12948236, 60354399, 4713226, 58167894, 14059179, - 12878652, 8511905, - ]), - xy2d: FieldElement2625([ - 41452044, 3393630, 64153449, 26478905, 64858154, 9366907, 36885446, 6812973, - 5568676, 30426776, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 78738868, 12144453, 69225203, 47160468, 94487748, 49231348, 49700110, 20050058, - 119822531, 8070816, - ]), - y_minus_x: FieldElement2625([ - 27117677, 23547054, 35826092, 27984343, 1127281, 12772488, 37262958, 10483305, - 55556115, 32525717, - ]), - xy2d: FieldElement2625([ - 10637467, 27866368, 5674780, 1072708, 40765276, 26572129, 65424888, 9177852, - 39615702, 15431202, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 87633990, 44446997, 121475255, 12779441, 104724694, 16150073, 105977209, - 14943140, 52052074, 25618500, - ]), - y_minus_x: FieldElement2625([ - 37084402, 5626925, 66557297, 23573344, 753597, 11981191, 25244767, 30314666, - 63752313, 9594023, - ]), - xy2d: FieldElement2625([ - 43356201, 2636869, 61944954, 23450613, 585133, 7877383, 11345683, 27062142, - 13352334, 22577348, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 65177046, 28146973, 70413512, 54223994, 84124668, 62231772, 104433876, - 25801948, 53893326, 33235227, - ]), - y_minus_x: FieldElement2625([ - 20239939, 6607058, 6203985, 3483793, 48721888, 32775202, 46385121, 15077869, - 44358105, 14523816, - ]), - xy2d: FieldElement2625([ - 27406023, 27512775, 27423595, 29057038, 4996213, 10002360, 38266833, 29008937, - 36936121, 28748764, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 78483087, 12660714, 17861383, 21013599, 78044431, 34653658, 53222787, 24462691, - 106490683, 44912934, - ]), - y_minus_x: FieldElement2625([ - 54378055, 10311866, 1510375, 10778093, 64989409, 24408729, 32676002, 11149336, - 40985213, 4985767, - ]), - xy2d: FieldElement2625([ - 48012542, 341146, 60911379, 33315398, 15756972, 24757770, 66125820, 13794113, - 47694557, 17933176, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 73598907, 45494717, 25495922, 59382504, 75777235, 24803115, 70476466, 40524436, - 65417798, 58104073, - ]), - y_minus_x: FieldElement2625([ - 1656478, 13457317, 15370807, 6364910, 13605745, 8362338, 47934242, 28078708, - 50312267, 28522993, - ]), - xy2d: FieldElement2625([ - 44835530, 20030007, 67044178, 29220208, 48503227, 22632463, 46537798, 26546453, - 67009010, 23317098, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 84856310, 43593691, 86477162, 29503840, 46478228, 51067577, 99101545, 17696455, - 104957364, 28042459, - ]), - y_minus_x: FieldElement2625([ - 31932008, 28568291, 47496481, 16366579, 22023614, 88450, 11371999, 29810185, - 4882241, 22927527, - ]), - xy2d: FieldElement2625([ - 29796488, 37186, 19818052, 10115756, 55279832, 3352735, 18551198, 3272828, - 61917932, 29392022, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 12501267, 4044383, 58495907, 53716478, 101787674, 38691029, 47878485, 30024734, - 330069, 29895023, - ]), - y_minus_x: FieldElement2625([ - 6384877, 2899513, 17807477, 7663917, 64749976, 12363164, 25366522, 24980540, - 66837568, 12071498, - ]), - xy2d: FieldElement2625([ - 58743349, 29511910, 25133447, 29037077, 60897836, 2265926, 34339246, 1936674, - 61949167, 3829362, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 28425947, 27718999, 66531773, 28857233, 120000172, 40425360, 75030413, - 26986644, 26333139, 47822096, - ]), - y_minus_x: FieldElement2625([ - 56041645, 11871230, 27385719, 22994888, 62522949, 22365119, 10004785, 24844944, - 45347639, 8930323, - ]), - xy2d: FieldElement2625([ - 45911060, 17158396, 25654215, 31829035, 12282011, 11008919, 1541940, 4757911, - 40617363, 17145491, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 80646107, 25794941, 113612887, 44516357, 61186043, 20336366, 53952279, - 39771685, 118274028, 47369420, - ]), - y_minus_x: FieldElement2625([ - 49686272, 15157789, 18705543, 29619, 24409717, 33293956, 27361680, 9257833, - 65152338, 31777517, - ]), - xy2d: FieldElement2625([ - 42063564, 23362465, 15366584, 15166509, 54003778, 8423555, 37937324, 12361134, - 48422886, 4578289, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 91688613, 3711569, 68451186, 22374305, 107212592, 47679386, 44564334, 14074918, - 21964432, 41789689, - ]), - y_minus_x: FieldElement2625([ - 60580251, 31142934, 9442965, 27628844, 12025639, 32067012, 64127349, 31885225, - 13006805, 2355433, - ]), - xy2d: FieldElement2625([ - 50803946, 19949172, 60476436, 28412082, 16974358, 22643349, 27202043, 1719366, - 1141648, 20758196, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54244901, 53888877, 58790596, 56090772, 60298717, 28710537, 13475065, 30420460, - 32674894, 47269477, - ]), - y_minus_x: FieldElement2625([ - 11423316, 28086373, 32344215, 8962751, 24989809, 9241752, 53843611, 16086211, - 38367983, 17912338, - ]), - xy2d: FieldElement2625([ - 65699196, 12530727, 60740138, 10847386, 19531186, 19422272, 55399715, 7791793, - 39862921, 4383346, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 38137947, 38825878, 65842854, 23817442, 121762491, 50287029, 62246456, - 62202414, 27193555, 39799623, - ]), - y_minus_x: FieldElement2625([ - 51914908, 5362277, 65324971, 2695833, 4960227, 12840725, 23061898, 3260492, - 22510453, 8577507, - ]), - xy2d: FieldElement2625([ - 54476394, 11257345, 34415870, 13548176, 66387860, 10879010, 31168030, 13952092, - 37537372, 29918525, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 70986166, 23981692, 99525555, 38959755, 56104456, 19897796, 70868632, 45489751, - 72720723, 41718449, - ]), - y_minus_x: FieldElement2625([ - 50833043, 14667796, 15906460, 12155291, 44997715, 24514713, 32003001, 24722143, - 5773084, 25132323, - ]), - xy2d: FieldElement2625([ - 43320746, 25300131, 1950874, 8937633, 18686727, 16459170, 66203139, 12376319, - 31632953, 190926, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 109624102, 17415545, 58684872, 13378745, 81271271, 6901327, 58820115, 38062995, - 41767308, 29926903, - ]), - y_minus_x: FieldElement2625([ - 8884438, 27670423, 6023973, 10104341, 60227295, 28612898, 18722940, 18768427, - 65436375, 827624, - ]), - xy2d: FieldElement2625([ - 34388281, 17265135, 34605316, 7101209, 13354605, 2659080, 65308289, 19446395, - 42230385, 1541285, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 70010192, 32436744, 70989239, 57049475, 116596786, 29941649, 45306746, - 29986950, 87565708, 31669398, - ]), - y_minus_x: FieldElement2625([ - 27019610, 12299467, 53450576, 31951197, 54247203, 28692960, 47568713, 28538373, - 29439640, 15138866, - ]), - xy2d: FieldElement2625([ - 21536104, 26928012, 34661045, 22864223, 44700786, 5175813, 61688824, 17193268, - 7779327, 109896, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 97388589, 48203181, 59063992, 39979989, 80748484, 32810922, 28698389, 45734550, - 23177718, 33000357, - ]), - y_minus_x: FieldElement2625([ - 26572828, 3405927, 35407164, 12890904, 47843196, 5335865, 60615096, 2378491, - 4439158, 20275085, - ]), - xy2d: FieldElement2625([ - 44392139, 3489069, 57883598, 33221678, 18875721, 32414337, 14819433, 20822905, - 49391106, 28092994, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 62052362, 50120982, 83062524, 37322183, 56672364, 49181491, 66287909, 35731656, - 75658945, 18440266, - ]), - y_minus_x: FieldElement2625([ - 48635543, 16596774, 66727204, 15663610, 22860960, 15585581, 39264755, 29971692, - 43848403, 25125843, - ]), - xy2d: FieldElement2625([ - 34628313, 15707274, 58902952, 27902350, 29464557, 2713815, 44383727, 15860481, - 45206294, 1494192, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 47546754, 53021470, 41524990, 24254879, 80236705, 34314140, 21923481, 16529112, - 75851568, 46521448, - ]), - y_minus_x: FieldElement2625([ - 38643965, 1553204, 32536856, 23080703, 42417258, 33148257, 58194238, 30620535, - 37205105, 15553882, - ]), - xy2d: FieldElement2625([ - 21877890, 3230008, 9881174, 10539357, 62311749, 2841331, 11543572, 14513274, - 19375923, 20906471, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 75941133, 52613378, 80362373, 38692006, 72146734, 37633208, 24880817, 60886148, - 69971515, 9455042, - ]), - y_minus_x: FieldElement2625([ - 29306751, 5123106, 20245049, 19404543, 9592565, 8447059, 65031740, 30564351, - 15511448, 4789663, - ]), - xy2d: FieldElement2625([ - 46429108, 7004546, 8824831, 24119455, 63063159, 29803695, 61354101, 108892, - 23513200, 16652362, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 100961536, 37699212, 62632834, 26975308, 77878902, 26398889, 60458447, - 54172563, 115898528, 43767290, - ]), - y_minus_x: FieldElement2625([ - 2756062, 8598110, 7383731, 26694540, 22312758, 32449420, 21179800, 2600940, - 57120566, 21047965, - ]), - xy2d: FieldElement2625([ - 42463153, 13317461, 36659605, 17900503, 21365573, 22684775, 11344423, 864440, - 64609187, 16844368, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 107784906, 6148327, 49924452, 19080277, 85891792, 33278434, 44547329, 33765731, - 69828620, 38495428, - ]), - y_minus_x: FieldElement2625([ - 65784982, 3911312, 60160120, 14759764, 37081714, 7851206, 21690126, 8518463, - 26699843, 5276295, - ]), - xy2d: FieldElement2625([ - 53958991, 27125364, 9396248, 365013, 24703301, 23065493, 1321585, 149635, - 51656090, 7159368, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77096625, 30149672, 84616825, 43059961, 76840398, 31388917, 89464872, 41866607, - 89586081, 25151046, - ]), - y_minus_x: FieldElement2625([ - 18155857, 17049442, 19744715, 9006923, 15154154, 23015456, 24256459, 28689437, - 44560690, 9334108, - ]), - xy2d: FieldElement2625([ - 2986088, 28642539, 10776627, 30080588, 10620589, 26471229, 45695018, 14253544, - 44521715, 536905, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 71486582, 41670267, 91675941, 15495313, 78733938, 46619030, 74499414, 44144056, - 77946923, 51688439, - ]), - y_minus_x: FieldElement2625([ - 47766460, 867879, 9277171, 30335973, 52677291, 31567988, 19295825, 17757482, - 6378259, 699185, - ]), - xy2d: FieldElement2625([ - 7895007, 4057113, 60027092, 20476675, 49222032, 33231305, 66392824, 15693154, - 62063800, 20180469, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 59371282, 27685029, 119651408, 26147511, 78494517, 46756047, 31730677, - 22591592, 63190227, 23885106, - ]), - y_minus_x: FieldElement2625([ - 10188286, 17783598, 59772502, 13427542, 22223443, 14896287, 30743455, 7116568, - 45322357, 5427592, - ]), - xy2d: FieldElement2625([ - 696102, 13206899, 27047647, 22922350, 15285304, 23701253, 10798489, 28975712, - 19236242, 12477404, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 55879406, 44798227, 50054593, 25513566, 66320635, 58940896, 63211193, 44734935, - 43939347, 41288075, - ]), - y_minus_x: FieldElement2625([ - 17800790, 19518253, 40108434, 21787760, 23887826, 3149671, 23466177, 23016261, - 10322026, 15313801, - ]), - xy2d: FieldElement2625([ - 26246234, 11968874, 32263343, 28085704, 6830754, 20231401, 51314159, 33452449, - 42659621, 10890803, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 35743198, 43825794, 54448238, 27287163, 83799070, 54046319, 119235514, - 50039361, 92289660, 28219547, - ]), - y_minus_x: FieldElement2625([ - 66522290, 10376443, 34522450, 22268075, 19801892, 10997610, 2276632, 9482883, - 316878, 13820577, - ]), - xy2d: FieldElement2625([ - 57226037, 29044064, 64993357, 16457135, 56008783, 11674995, 30756178, 26039378, - 30696929, 29841583, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 100097781, 23951019, 12499365, 41465219, 56491606, 21622917, 59766047, - 57123466, 34759345, 7392472, - ]), - y_minus_x: FieldElement2625([ - 58253184, 15927860, 9866406, 29905021, 64711949, 16898650, 36699387, 24419436, - 25112946, 30627788, - ]), - xy2d: FieldElement2625([ - 64604801, 33117465, 25621773, 27875660, 15085041, 28074555, 42223985, 20028237, - 5537437, 19640113, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 55883261, 2320284, 57524584, 10149186, 100773065, 5808646, 119341477, 31824763, - 98343453, 39645030, - ]), - y_minus_x: FieldElement2625([ - 57475529, 116425, 26083934, 2897444, 60744427, 30866345, 609720, 15878753, - 60138459, 24519663, - ]), - xy2d: FieldElement2625([ - 39351007, 247743, 51914090, 24551880, 23288160, 23542496, 43239268, 6503645, - 20650474, 1804084, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 106627923, 49010854, 76081380, 42024039, 82749485, 37994278, 70230858, - 56779150, 94951478, 33352103, - ]), - y_minus_x: FieldElement2625([ - 51801891, 2839643, 22530074, 10026331, 4602058, 5048462, 28248656, 5031932, - 55733782, 12714368, - ]), - xy2d: FieldElement2625([ - 20807691, 26283607, 29286140, 11421711, 39232341, 19686201, 45881388, 1035545, - 47375635, 12796919, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 79185725, 52807577, 58323861, 21705509, 42096072, 49955115, 49517368, 20654993, - 70589528, 51926048, - ]), - y_minus_x: FieldElement2625([ - 34747315, 5457596, 28548107, 7833186, 7303070, 21600887, 42745799, 17632556, - 33734809, 2771024, - ]), - xy2d: FieldElement2625([ - 45719598, 421931, 26597266, 6860826, 22486084, 26817260, 49971378, 29344205, - 42556581, 15673396, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 46924223, 35892647, 19788684, 57487908, 63107597, 24813538, 46837679, 38287685, - 70836007, 20619983, - ]), - y_minus_x: FieldElement2625([ - 6120100, 814863, 55314462, 32931715, 6812204, 17806661, 2019593, 7975683, - 31123697, 22595451, - ]), - xy2d: FieldElement2625([ - 30069250, 22119100, 30434653, 2958439, 18399564, 32578143, 12296868, 9204260, - 50676426, 9648164, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 32705413, 32003455, 97814521, 41005496, 55303257, 43186244, 70414129, 38803035, - 108209395, 22176929, - ]), - y_minus_x: FieldElement2625([ - 17219846, 2375039, 35537917, 27978816, 47649184, 9219902, 294711, 15298639, - 2662509, 17257359, - ]), - xy2d: FieldElement2625([ - 65935918, 25995736, 62742093, 29266687, 45762450, 25120105, 32087528, 32331655, - 32247247, 19164571, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 14312609, 34775988, 17395389, 58408721, 62163121, 58424228, 106019982, - 23916613, 51081240, 20175586, - ]), - y_minus_x: FieldElement2625([ - 65680039, 23875441, 57873182, 6549686, 59725795, 33085767, 23046501, 9803137, - 17597934, 2346211, - ]), - xy2d: FieldElement2625([ - 18510781, 15337574, 26171504, 981392, 44867312, 7827555, 43617730, 22231079, - 3059832, 21771562, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77250443, 39637338, 84938156, 31606788, 76938955, 13613135, 41552228, 28009845, - 33606651, 37146527, - ]), - y_minus_x: FieldElement2625([ - 33114149, 17665080, 40583177, 20211034, 33076704, 8716171, 1151462, 1521897, - 66126199, 26716628, - ]), - xy2d: FieldElement2625([ - 34169699, 29298616, 23947180, 33230254, 34035889, 21248794, 50471177, 3891703, - 26353178, 693168, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 97483084, 35150011, 117333688, 46741361, 71709207, 33961335, 76694157, - 33153763, 31375463, 47924397, - ]), - y_minus_x: FieldElement2625([ - 52738210, 25781902, 1510300, 6434173, 48324075, 27291703, 32732229, 20445593, - 17901440, 16011505, - ]), - xy2d: FieldElement2625([ - 18171223, 21619806, 54608461, 15197121, 56070717, 18324396, 47936623, 17508055, - 8764034, 12309598, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 73084753, 28311243, 47649501, 23872684, 55567586, 14015781, 110551971, - 34782749, 17544095, 22960650, - ]), - y_minus_x: FieldElement2625([ - 5811932, 31839139, 3442886, 31285122, 48741515, 25194890, 49064820, 18144304, - 61543482, 12348899, - ]), - xy2d: FieldElement2625([ - 35709185, 11407554, 25755363, 6891399, 63851926, 14872273, 42259511, 8141294, - 56476330, 32968952, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 121542424, 34248456, 62032718, 46854775, 81124121, 19103037, 124519055, - 22225380, 30944592, 1130208, - ]), - y_minus_x: FieldElement2625([ - 8247747, 26843490, 40546482, 25845122, 52706924, 18905521, 4652151, 2488540, - 23550156, 33283200, - ]), - xy2d: FieldElement2625([ - 17294297, 29765994, 7026747, 15626851, 22990044, 113481, 2267737, 27646286, - 66700045, 33416712, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 83199930, 17300505, 85708115, 40895109, 69246500, 32332774, 63744702, 48105367, - 70369388, 26388160, - ]), - y_minus_x: FieldElement2625([ - 62198760, 20221544, 18550886, 10864893, 50649539, 26262835, 44079994, 20349526, - 54360141, 2701325, - ]), - xy2d: FieldElement2625([ - 58534169, 16099414, 4629974, 17213908, 46322650, 27548999, 57090500, 9276970, - 11329923, 1862132, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 14763057, 17650824, 103299457, 3689865, 70620756, 43867957, 45157775, 45773662, - 58070900, 32614131, - ]), - y_minus_x: FieldElement2625([ - 8894987, 30108338, 6150752, 3013931, 301220, 15693451, 35127648, 30644714, - 51670695, 11595569, - ]), - xy2d: FieldElement2625([ - 15214943, 3537601, 40870142, 19495559, 4418656, 18323671, 13947275, 10730794, - 53619402, 29190761, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 64570539, 41237224, 99867876, 33817540, 104232996, 25598978, 111885603, - 23365795, 68085971, 34254425, - ]), - y_minus_x: FieldElement2625([ - 54642373, 4195083, 57897332, 550903, 51543527, 12917919, 19118110, 33114591, - 36574330, 19216518, - ]), - xy2d: FieldElement2625([ - 31788442, 19046775, 4799988, 7372237, 8808585, 18806489, 9408236, 23502657, - 12493931, 28145115, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 41428258, 5260743, 47873055, 27269961, 63412921, 16566086, 94327144, 36161552, - 29375954, 6024730, - ]), - y_minus_x: FieldElement2625([ - 842132, 30759739, 62345482, 24831616, 26332017, 21148791, 11831879, 6985184, - 57168503, 2854095, - ]), - xy2d: FieldElement2625([ - 62261602, 25585100, 2516241, 27706719, 9695690, 26333246, 16512644, 960770, - 12121869, 16648078, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 51890193, 48221527, 53772634, 35568148, 97707150, 33090294, 35603941, 25672367, - 20237805, 36392843, - ]), - y_minus_x: FieldElement2625([ - 47820798, 4453151, 15298546, 17376044, 22115042, 17581828, 12544293, 20083975, - 1068880, 21054527, - ]), - xy2d: FieldElement2625([ - 57549981, 17035596, 33238497, 13506958, 30505848, 32439836, 58621956, 30924378, - 12521377, 4845654, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 106019188, 44298538, 64150483, 43754095, 74868174, 54020263, 70518210, - 32681031, 127735421, 20668560, - ]), - y_minus_x: FieldElement2625([ - 43547042, 6230155, 46726851, 10655313, 43068279, 21933259, 10477733, 32314216, - 63995636, 13974497, - ]), - xy2d: FieldElement2625([ - 12966261, 15550616, 35069916, 31939085, 21025979, 32924988, 5642324, 7188737, - 18895762, 12629579, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 14741860, 18607545, 89286071, 21833194, 68388604, 41613031, 11758139, 34343875, - 32195180, 37450109, - ]), - y_minus_x: FieldElement2625([ - 10758205, 15755439, 62598914, 9243697, 62229442, 6879878, 64904289, 29988312, - 58126794, 4429646, - ]), - xy2d: FieldElement2625([ - 64654951, 15725972, 46672522, 23143759, 61304955, 22514211, 59972993, 21911536, - 18047435, 18272689, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 41935825, 55801698, 29759954, 45331216, 111955344, 51288407, 78101976, - 54258026, 49488161, 57700395, - ]), - y_minus_x: FieldElement2625([ - 21987233, 700364, 42603816, 14972007, 59334599, 27836036, 32155025, 2581431, - 37149879, 8773374, - ]), - xy2d: FieldElement2625([ - 41540495, 454462, 53896929, 16126714, 25240068, 8594567, 20656846, 12017935, - 59234475, 19634276, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 73137027, 39817509, 103205921, 55807152, 66289943, 36016203, 102376553, - 61640820, 65387074, 30777706, - ]), - y_minus_x: FieldElement2625([ - 54829870, 16624276, 987579, 27631834, 32908202, 1248608, 7719845, 29387734, - 28408819, 6816612, - ]), - xy2d: FieldElement2625([ - 56750770, 25316602, 19549650, 21385210, 22082622, 16147817, 20613181, 13982702, - 56769294, 5067942, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 36602859, 29732664, 79183544, 13582411, 47230892, 35998382, 47389577, 12746131, - 72440074, 57002919, - ]), - y_minus_x: FieldElement2625([ - 30528792, 3601899, 65151774, 4619784, 39747042, 18118043, 24180792, 20984038, - 27679907, 31905504, - ]), - xy2d: FieldElement2625([ - 9402385, 19597367, 32834042, 10838634, 40528714, 20317236, 26653273, 24868867, - 22611443, 20839026, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 89299435, 34672460, 22736440, 48684895, 103757035, 27563109, 86298488, - 62459921, 71963721, 40176570, - ]), - y_minus_x: FieldElement2625([ - 58798126, 30600981, 58846284, 30166382, 56707132, 33282502, 13424425, 29987205, - 26404408, 13001963, - ]), - xy2d: FieldElement2625([ - 35867026, 18138731, 64114613, 8939345, 11562230, 20713762, 41044498, 21932711, - 51703708, 11020692, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 68974887, 59159374, 59210213, 23253421, 12483314, 47031979, 70284499, 21130268, - 28761761, 34961166, - ]), - y_minus_x: FieldElement2625([ - 66660290, 31776765, 13018550, 3194501, 57528444, 22392694, 24760584, 29207344, - 25577410, 20175752, - ]), - xy2d: FieldElement2625([ - 42818486, 4759344, 66418211, 31701615, 2066746, 10693769, 37513074, 9884935, - 57739938, 4745409, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 57967561, 39604145, 47577802, 29213020, 102956929, 43498706, 51646855, - 55797011, 78040786, 21622500, - ]), - y_minus_x: FieldElement2625([ - 50547351, 14112679, 59096219, 4817317, 59068400, 22139825, 44255434, 10856640, - 46638094, 13434653, - ]), - xy2d: FieldElement2625([ - 22759470, 23480998, 50342599, 31683009, 13637441, 23386341, 1765143, 20900106, - 28445306, 28189722, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 29875044, 46048045, 69904399, 63322533, 68819482, 48735613, 56913146, 24765756, - 9074233, 34721612, - ]), - y_minus_x: FieldElement2625([ - 40903181, 11014232, 57266213, 30918946, 40200743, 7532293, 48391976, 24018933, - 3843902, 9367684, - ]), - xy2d: FieldElement2625([ - 56139269, 27150720, 9591133, 9582310, 11349256, 108879, 16235123, 8601684, - 66969667, 4242894, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 89201818, 53917740, 65066069, 21585919, 99295616, 55591475, 60534521, 36025091, - 106800361, 16625499, - ]), - y_minus_x: FieldElement2625([ - 56051142, 3042015, 13770083, 24296510, 584235, 33009577, 59338006, 2602724, - 39757248, 14247412, - ]), - xy2d: FieldElement2625([ - 6314156, 23289540, 34336361, 15957556, 56951134, 168749, 58490057, 14290060, - 27108877, 32373552, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 58522248, 26383465, 80350645, 44514587, 34117848, 19759835, 100656839, - 22495542, 107069276, 34536304, - ]), - y_minus_x: FieldElement2625([ - 22833421, 9293594, 34459416, 19935764, 57971897, 14756818, 44180005, 19583651, - 56629059, 17356469, - ]), - xy2d: FieldElement2625([ - 59340277, 3326785, 38997067, 10783823, 19178761, 14905060, 22680049, 13906969, - 51175174, 3797898, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 88830182, 29341685, 54902740, 42864613, 63226624, 19901321, 90849087, 30845199, - 87600846, 59066711, - ]), - y_minus_x: FieldElement2625([ - 9209251, 18419377, 53852306, 27386633, 66377847, 15289672, 25947805, 15286587, - 30997318, 26851369, - ]), - xy2d: FieldElement2625([ - 7392013, 16618386, 23946583, 25514540, 53843699, 32020573, 52911418, 31232855, - 17649997, 33304352, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 57807757, 52915036, 97718388, 30504888, 41933794, 32270679, 51867297, 24028707, - 64875610, 41216577, - ]), - y_minus_x: FieldElement2625([ - 49550191, 1763593, 33994528, 15908609, 37067994, 21380136, 7335079, 25082233, - 63934189, 3440182, - ]), - xy2d: FieldElement2625([ - 47219164, 27577423, 42997570, 23865561, 10799742, 16982475, 40449, 29122597, - 4862399, 1133, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 34252636, 25680474, 61686474, 48415381, 50789832, 41510573, 74366924, 33866292, - 36513872, 26175010, - ]), - y_minus_x: FieldElement2625([ - 63335436, 31988495, 28985339, 7499440, 24445838, 9325937, 29727763, 16527196, - 18278453, 15405622, - ]), - xy2d: FieldElement2625([ - 62726958, 8508651, 47210498, 29880007, 61124410, 15149969, 53795266, 843522, - 45233802, 13626196, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 69390312, 20067376, 56193445, 30944521, 68988221, 49718638, 56324981, 37508223, - 80449702, 15928662, - ]), - y_minus_x: FieldElement2625([ - 31727126, 26374577, 48671360, 25270779, 2875792, 17164102, 41838969, 26539605, - 43656557, 5964752, - ]), - xy2d: FieldElement2625([ - 4100401, 27594980, 49929526, 6017713, 48403027, 12227140, 40424029, 11344143, - 2538215, 25983677, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 57675240, 6123112, 78268667, 31397823, 97125143, 48520672, 46633880, 35039852, - 66479607, 17595569, - ]), - y_minus_x: FieldElement2625([ - 40304287, 4260918, 11851389, 9658551, 35091757, 16367491, 46903439, 20363143, - 11659921, 22439314, - ]), - xy2d: FieldElement2625([ - 26180377, 10015009, 36264640, 24973138, 5418196, 9480663, 2231568, 23384352, - 33100371, 32248261, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 82229958, 28352560, 56718958, 48982252, 39598926, 17561924, 88779810, 38041106, - 61177053, 19088051, - ]), - y_minus_x: FieldElement2625([ - 16166467, 24070699, 56004733, 6023907, 35182066, 32189508, 2340059, 17299464, - 56373093, 23514607, - ]), - xy2d: FieldElement2625([ - 28042865, 29997343, 54982337, 12259705, 63391366, 26608532, 6766452, 24864833, - 18036435, 5803270, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 66291264, 40318343, 78912424, 35140016, 78067310, 30883266, 23855390, 4598332, - 60949433, 19436993, - ]), - y_minus_x: FieldElement2625([ - 36077558, 19298237, 17332028, 31170912, 31312681, 27587249, 696308, 50292, - 47013125, 11763583, - ]), - xy2d: FieldElement2625([ - 66514282, 31040148, 34874710, 12643979, 12650761, 14811489, 665117, 20940800, - 47335652, 22840869, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 97573435, 55845991, 62981386, 20819953, 86944190, 60003250, 109821551, - 35630203, 50088706, 34546902, - ]), - y_minus_x: FieldElement2625([ - 18357166, 26559999, 7766381, 16342475, 37783946, 411173, 14578841, 8080033, - 55534529, 22952821, - ]), - xy2d: FieldElement2625([ - 19598397, 10334610, 12555054, 2555664, 18821899, 23214652, 21873262, 16014234, - 26224780, 16452269, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 36884920, 5145195, 73053412, 49940397, 71085598, 35564328, 122839923, 25936244, - 46575034, 37253081, - ]), - y_minus_x: FieldElement2625([ - 14187449, 3448569, 56472628, 22743496, 44444983, 30120835, 7268409, 22663988, - 27394300, 12015369, - ]), - xy2d: FieldElement2625([ - 19695742, 16087646, 28032085, 12999827, 6817792, 11427614, 20244189, 32241655, - 53849736, 30151970, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 97968948, 12735207, 65220619, 28854697, 50133957, 35811371, 126051714, - 45852742, 58558339, 23160969, - ]), - y_minus_x: FieldElement2625([ - 61389038, 22309106, 65198214, 15569034, 26642876, 25966672, 61319509, 18435777, - 62132699, 12651792, - ]), - xy2d: FieldElement2625([ - 64260450, 9953420, 11531313, 28271553, 26895122, 20857343, 53990043, 17036529, - 9768697, 31021214, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 109498250, 35449081, 66821165, 28850346, 82457582, 25397901, 32767512, - 46319882, 72048958, 44232657, - ]), - y_minus_x: FieldElement2625([ - 18860224, 15980149, 48121624, 31991861, 40875851, 22482575, 59264981, 13944023, - 42736516, 16582018, - ]), - xy2d: FieldElement2625([ - 51604604, 4970267, 37215820, 4175592, 46115652, 31354675, 55404809, 15444559, - 56105103, 7989036, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 98599278, 39122492, 64696060, 35736814, 34772016, 38086117, 35030594, 39754637, - 47422750, 52308692, - ]), - y_minus_x: FieldElement2625([ - 49800177, 17674491, 35586086, 33551600, 34221481, 16375548, 8680158, 17182719, - 28550067, 26697300, - ]), - xy2d: FieldElement2625([ - 38981977, 27866340, 16837844, 31733974, 60258182, 12700015, 37068883, 4364037, - 1155602, 5988841, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 88999280, 20281524, 121593716, 12154347, 59276991, 48854927, 90257846, - 29083950, 91727270, 41837612, - ]), - y_minus_x: FieldElement2625([ - 33972757, 23041680, 9975415, 6841041, 35549071, 16356535, 3070187, 26528504, - 1466168, 10740210, - ]), - xy2d: FieldElement2625([ - 65599446, 18066246, 53605478, 22898515, 32799043, 909394, 53169961, 27774712, - 34944214, 18227391, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 71069668, 19286628, 39082773, 51190812, 47704004, 46701299, 82676190, 34505938, - 63848542, 32980496, - ]), - y_minus_x: FieldElement2625([ - 24740822, 5052253, 37014733, 8961360, 25877428, 6165135, 42740684, 14397371, - 59728495, 27410326, - ]), - xy2d: FieldElement2625([ - 38220480, 3510802, 39005586, 32395953, 55870735, 22922977, 51667400, 19101303, - 65483377, 27059617, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 67902144, 24323953, 75945165, 27318724, 39747955, 31184838, 100261706, - 62223612, 57202662, 32932579, - ]), - y_minus_x: FieldElement2625([ - 5666214, 525582, 20782575, 25516013, 42570364, 14657739, 16099374, 1468826, - 60937436, 18367850, - ]), - xy2d: FieldElement2625([ - 62249590, 29775088, 64191105, 26806412, 7778749, 11688288, 36704511, 23683193, - 65549940, 23690785, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 10896313, 25834728, 67933138, 34027032, 114757419, 36564017, 25248957, - 48337770, 36527387, 17796587, - ]), - y_minus_x: FieldElement2625([ - 10566929, 12612572, 35164652, 11118702, 54475488, 12362878, 21752402, 8822496, - 24003793, 14264025, - ]), - xy2d: FieldElement2625([ - 27713843, 26198459, 56100623, 9227529, 27050101, 2504721, 23886875, 20436907, - 13958494, 27821979, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 110736080, 38421656, 39861735, 37454952, 29838368, 25342141, 102328328, - 23512649, 74449384, 51698795, - ]), - y_minus_x: FieldElement2625([ - 4646495, 25543308, 44342840, 22021777, 23184552, 8566613, 31366726, 32173371, - 52042079, 23179239, - ]), - xy2d: FieldElement2625([ - 49838347, 12723031, 50115803, 14878793, 21619651, 27356856, 27584816, 3093888, - 58265170, 3849920, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 58043933, 35657603, 92670503, 51983125, 61869038, 43137389, 99585908, 24536476, - 72111157, 18004172, - ]), - y_minus_x: FieldElement2625([ - 55051311, 22376525, 21115584, 20189277, 8808711, 21523724, 16489529, 13378448, - 41263148, 12741425, - ]), - xy2d: FieldElement2625([ - 61162478, 10645102, 36197278, 15390283, 63821882, 26435754, 24306471, 15852464, - 28834118, 25908360, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 49773097, 24447374, 109686448, 42989383, 58636779, 32971069, 54018092, - 34010272, 87570721, 39045736, - ]), - y_minus_x: FieldElement2625([ - 13669229, 17458950, 54626889, 23351392, 52539093, 21661233, 42112877, 11293806, - 38520660, 24132599, - ]), - xy2d: FieldElement2625([ - 28497909, 6272777, 34085870, 14470569, 8906179, 32328802, 18504673, 19389266, - 29867744, 24758489, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 50901822, 47071627, 39309233, 19856633, 24009063, 60734973, 60741262, 53933471, - 22853427, 29542421, - ]), - y_minus_x: FieldElement2625([ - 24191359, 16712145, 53177067, 15217830, 14542237, 1646131, 18603514, 22516545, - 12876622, 31441985, - ]), - xy2d: FieldElement2625([ - 17902668, 4518229, 66697162, 30725184, 26878216, 5258055, 54248111, 608396, - 16031844, 3723494, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 105584936, 12763726, 46662418, 41131935, 33001347, 54091119, 17558840, - 59235974, 23896952, 29240187, - ]), - y_minus_x: FieldElement2625([ - 47103464, 21542479, 31520463, 605201, 2543521, 5991821, 64163800, 7229063, - 57189218, 24727572, - ]), - xy2d: FieldElement2625([ - 28816026, 298879, 38943848, 17633493, 19000927, 31888542, 54428030, 30605106, - 49057085, 31471516, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 16000882, 33209536, 70601955, 55661665, 37604267, 20394642, 79686603, 49595699, - 47393623, 7847706, - ]), - y_minus_x: FieldElement2625([ - 10151868, 10572098, 27312476, 7922682, 14825339, 4723128, 34252933, 27035413, - 57088296, 3852847, - ]), - xy2d: FieldElement2625([ - 55678375, 15697595, 45987307, 29133784, 5386313, 15063598, 16514493, 17622322, - 29330898, 18478208, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 41609110, 29175637, 51885955, 26653220, 83724594, 35606215, 70412565, 33569921, - 106668931, 45868821, - ]), - y_minus_x: FieldElement2625([ - 15683501, 27551389, 18109119, 23573784, 15337967, 27556609, 50391428, 15921865, - 16103996, 29823217, - ]), - xy2d: FieldElement2625([ - 43939021, 22773182, 13588191, 31925625, 63310306, 32479502, 47835256, 5402698, - 37293151, 23713330, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 90299521, 35939014, 34394523, 37016585, 104314072, 32025298, 55842007, 8911516, - 109011869, 36294143, - ]), - y_minus_x: FieldElement2625([ - 21374101, 30000182, 33584214, 9874410, 15377179, 11831242, 33578960, 6134906, - 4931255, 11987849, - ]), - xy2d: FieldElement2625([ - 67101132, 30575573, 50885377, 7277596, 105524, 33232381, 35628324, 13861387, - 37032554, 10117929, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 37607694, 22809559, 40945095, 13051538, 41483300, 38644074, 127892224, - 40258509, 79998882, 15728939, - ]), - y_minus_x: FieldElement2625([ - 45136504, 21783052, 66157804, 29135591, 14704839, 2695116, 903376, 23126293, - 12885166, 8311031, - ]), - xy2d: FieldElement2625([ - 49592363, 5352193, 10384213, 19742774, 7506450, 13453191, 26423267, 4384730, - 1888765, 28119028, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 108400371, 64001550, 120723127, 30371924, 98005322, 19632702, 101966083, - 20846561, 47644429, 30214188, - ]), - y_minus_x: FieldElement2625([ - 43500868, 30888657, 66582772, 4651135, 5765089, 4618330, 6092245, 14845197, - 17151279, 23700316, - ]), - xy2d: FieldElement2625([ - 42278406, 20820711, 51942885, 10367249, 37577956, 33289075, 22825804, 26467153, - 50242379, 16176524, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 43525570, 40119392, 87172552, 37352659, 129477549, 40913655, 69115045, - 23191005, 38362610, 56911354, - ]), - y_minus_x: FieldElement2625([ - 56482264, 29068029, 53788301, 28429114, 3432135, 27161203, 23632036, 31613822, - 32808309, 1099883, - ]), - xy2d: FieldElement2625([ - 15030958, 5768825, 39657628, 30667132, 60681485, 18193060, 51830967, 26745081, - 2051440, 18328567, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 63746522, 26315059, 74626753, 43379423, 90664713, 33849800, 72257261, 52954675, - 44422508, 50188091, - ]), - y_minus_x: FieldElement2625([ - 4577067, 16802144, 13249840, 18250104, 19958762, 19017158, 18559669, 22794883, - 8402477, 23690159, - ]), - xy2d: FieldElement2625([ - 38702534, 32502850, 40318708, 32646733, 49896449, 22523642, 9453450, 18574360, - 17983009, 9967138, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 41346351, 40079153, 93694351, 43523701, 24709297, 34774792, 65430873, 7806336, - 84616260, 37205991, - ]), - y_minus_x: FieldElement2625([ - 56688388, 29436320, 14584638, 15971087, 51340543, 8861009, 26556809, 27979875, - 48555541, 22197296, - ]), - xy2d: FieldElement2625([ - 2839082, 14284142, 4029895, 3472686, 14402957, 12689363, 40466743, 8459446, - 61503401, 25932490, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 62269556, 30018987, 76853824, 2871047, 92222842, 36741449, 109106914, 32705364, - 84366947, 25576692, - ]), - y_minus_x: FieldElement2625([ - 18164541, 22959256, 49953981, 32012014, 19237077, 23809137, 23357532, 18337424, - 26908269, 12150756, - ]), - xy2d: FieldElement2625([ - 36843994, 25906566, 5112248, 26517760, 65609056, 26580174, 43167, 28016731, - 34806789, 16215818, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 60209940, 43378825, 54804084, 29153342, 102820586, 27277595, 99683352, - 46087336, 59605791, 24879084, - ]), - y_minus_x: FieldElement2625([ - 39765323, 17038963, 39957339, 22831480, 946345, 16291093, 254968, 7168080, - 21676107, 31611404, - ]), - xy2d: FieldElement2625([ - 21260942, 25129680, 50276977, 21633609, 43430902, 3968120, 63456915, 27338965, - 63552672, 25641356, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 16544735, 46804798, 50304435, 49100673, 62525860, 46311689, 64646555, 24874095, - 48201831, 23891632, - ]), - y_minus_x: FieldElement2625([ - 64693606, 17976703, 18312302, 4964443, 51836334, 20900867, 26820650, 16690659, - 25459437, 28989823, - ]), - xy2d: FieldElement2625([ - 41964155, 11425019, 28423002, 22533875, 60963942, 17728207, 9142794, 31162830, - 60676445, 31909614, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 44004193, 39807907, 16964146, 29785560, 109103755, 54812425, 39651637, - 50764205, 73444554, 40804420, - ]), - y_minus_x: FieldElement2625([ - 36775618, 13979674, 7503222, 21186118, 55152142, 28932738, 36836594, 2682241, - 25993170, 21075909, - ]), - xy2d: FieldElement2625([ - 4364628, 5930691, 32304656, 23509878, 59054082, 15091130, 22857016, 22955477, - 31820367, 15075278, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 98987979, 24635738, 84367624, 33645057, 126175891, 28636721, 91271651, - 23903545, 116247489, 46387475, - ]), - y_minus_x: FieldElement2625([ - 19073683, 14851414, 42705695, 21694263, 7625277, 11091125, 47489674, 2074448, - 57694925, 14905376, - ]), - xy2d: FieldElement2625([ - 24483648, 21618865, 64589997, 22007013, 65555733, 15355505, 41826784, 9253128, - 27628530, 25998952, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 84706452, 41895034, 86464480, 34106618, 26198469, 30377849, 71702187, 24396849, - 120106852, 48851446, - ]), - y_minus_x: FieldElement2625([ - 510886, 14337390, 35323607, 16638631, 6328095, 2713355, 46891447, 21690211, - 8683220, 2921426, - ]), - xy2d: FieldElement2625([ - 18606791, 11874196, 27155355, 28272950, 43077121, 6265445, 41930624, 32275507, - 4674689, 13890525, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 13609605, 13069022, 106845367, 20498522, 91469449, 43147405, 82086020, - 43389536, 71498550, 33842827, - ]), - y_minus_x: FieldElement2625([ - 9922506, 33035038, 13613106, 5883594, 48350519, 33120168, 54804801, 8317627, - 23388070, 16052080, - ]), - xy2d: FieldElement2625([ - 12719997, 11937594, 35138804, 28525742, 26900119, 8561328, 46953177, 21921452, - 52354592, 22741539, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 83070703, 47704840, 93825794, 32888599, 111423399, 47157999, 78938436, - 41022275, 38286735, 34483706, - ]), - y_minus_x: FieldElement2625([ - 11038231, 21972036, 39798381, 26237869, 56610336, 17246600, 43629330, 24182562, - 45715720, 2465073, - ]), - xy2d: FieldElement2625([ - 20017144, 29231206, 27915241, 1529148, 12396362, 15675764, 13817261, 23896366, - 2463390, 28932292, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 50749967, 20890520, 122152544, 38550884, 65852441, 34628003, 76692421, - 12851106, 71112760, 46228148, - ]), - y_minus_x: FieldElement2625([ - 65377275, 18398561, 63845933, 16143081, 19294135, 13385325, 14741514, 24450706, - 7903885, 2348101, - ]), - xy2d: FieldElement2625([ - 24536016, 17039225, 12715591, 29692277, 1511292, 10047386, 63266518, 26425272, - 38731325, 10048126, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54486638, 27349611, 97827688, 2591311, 56491836, 12192839, 85982162, 59811773, - 34811106, 15221631, - ]), - y_minus_x: FieldElement2625([ - 40630742, 22450567, 11546243, 31701949, 9180879, 7656409, 45764914, 2095754, - 29769758, 6593415, - ]), - xy2d: FieldElement2625([ - 35114656, 30646970, 4176911, 3264766, 12538965, 32686321, 26312344, 27435754, - 30958053, 8292160, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 98538667, 53149747, 96282394, 15632447, 12174511, 64348770, 99917693, 37531617, - 93251999, 30405555, - ]), - y_minus_x: FieldElement2625([ - 22648882, 1402143, 44308880, 13746058, 7936347, 365344, 58440231, 31879998, - 63350620, 31249806, - ]), - xy2d: FieldElement2625([ - 51616947, 8012312, 64594134, 20851969, 43143017, 23300402, 65496150, 32018862, - 50444388, 8194477, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 27338047, 26047012, 59694639, 10140404, 48082437, 26964542, 94386054, 42409807, - 95681149, 36559595, - ]), - y_minus_x: FieldElement2625([ - 26287105, 4821776, 25476601, 29408529, 63344350, 17765447, 49100281, 1182478, - 41014043, 20474836, - ]), - xy2d: FieldElement2625([ - 59937691, 3178079, 23970071, 6201893, 49913287, 29065239, 45232588, 19571804, - 32208682, 32356184, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 50451143, 36372074, 56822501, 14811297, 73133531, 46903936, 39793359, 56611021, - 39436277, 22014573, - ]), - y_minus_x: FieldElement2625([ - 15941010, 24148500, 45741813, 8062054, 31876073, 33315803, 51830470, 32110002, - 15397330, 29424239, - ]), - xy2d: FieldElement2625([ - 8934485, 20068965, 43822466, 20131190, 34662773, 14047985, 31170398, 32113411, - 39603297, 15087183, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 115860466, 31397939, 24524912, 16876564, 82629290, 27193655, 118715321, - 11461894, 83897392, 27685489, - ]), - y_minus_x: FieldElement2625([ - 65161459, 16013772, 21750665, 3714552, 49707082, 17498998, 63338576, 23231111, - 31322513, 21938797, - ]), - xy2d: FieldElement2625([ - 21426636, 27904214, 53460576, 28206894, 38296674, 28633461, 48833472, 18933017, - 13040861, 21441484, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 78402740, 46032517, 107081326, 48638180, 104910306, 14748870, 14555558, - 20137329, 68722574, 38451366, - ]), - y_minus_x: FieldElement2625([ - 41213962, 15323293, 58619073, 25496531, 25967125, 20128972, 2825959, 28657387, - 43137087, 22287016, - ]), - xy2d: FieldElement2625([ - 51184079, 28324551, 49665331, 6410663, 3622847, 10243618, 20615400, 12405433, - 43355834, 25118015, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 127126414, 46110638, 114026375, 9025185, 50036385, 4333800, 71487300, 35986461, - 23097948, 32988414, - ]), - y_minus_x: FieldElement2625([ - 4565804, 17528778, 20084411, 25711615, 1724998, 189254, 24767264, 10103221, - 48596551, 2424777, - ]), - xy2d: FieldElement2625([ - 366633, 21577626, 8173089, 26664313, 30788633, 5745705, 59940186, 1344108, - 63466311, 12412658, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 110215918, 41244716, 82038279, 33386174, 102006892, 53695876, 91271559, - 51782359, 63967361, 44733816, - ]), - y_minus_x: FieldElement2625([ - 18289503, 18829478, 8056944, 16430056, 45379140, 7842513, 61107423, 32067534, - 48424218, 22110928, - ]), - xy2d: FieldElement2625([ - 476239, 6601091, 60956074, 23831056, 17503544, 28690532, 27672958, 13403813, - 11052904, 5219329, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 87787372, 25178693, 34436965, 42403554, 129207969, 48129182, 98295834, - 29580701, 9014761, 58529808, - ]), - y_minus_x: FieldElement2625([ - 53464795, 23204192, 51146355, 5075807, 65594203, 22019831, 34006363, 9160279, - 8473550, 30297594, - ]), - xy2d: FieldElement2625([ - 24900749, 14435722, 17209120, 18261891, 44516588, 9878982, 59419555, 17218610, - 42540382, 11788947, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 63990690, 22159237, 53306774, 48351872, 76761311, 26708527, 47071426, 43965164, - 42540393, 32095740, - ]), - y_minus_x: FieldElement2625([ - 51449703, 16736705, 44641714, 10215877, 58011687, 7563910, 11871841, 21049238, - 48595538, 8464117, - ]), - xy2d: FieldElement2625([ - 43708233, 8348506, 52522913, 32692717, 63158658, 27181012, 14325288, 8628612, - 33313881, 25183915, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 46921853, 28586496, 89476219, 38825978, 66011746, 28765593, 109412060, - 23317576, 58168128, 61290594, - ]), - y_minus_x: FieldElement2625([ - 60160060, 31759219, 34483180, 17533252, 32635413, 26180187, 15989196, 20716244, - 28358191, 29300528, - ]), - xy2d: FieldElement2625([ - 43547083, 30755372, 34757181, 31892468, 57961144, 10429266, 50471180, 4072015, - 61757200, 5596588, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 105981130, 30164382, 79421759, 39767609, 3117141, 49632997, 29266238, 36111653, - 68877164, 15373192, - ]), - y_minus_x: FieldElement2625([ - 59865506, 30307471, 62515396, 26001078, 66980936, 32642186, 66017961, 29049440, - 42448372, 3442909, - ]), - xy2d: FieldElement2625([ - 36898293, 5124042, 14181784, 8197961, 18964734, 21615339, 22597930, 7176455, - 48523386, 13365929, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 59231455, 32054473, 75433536, 38244510, 73370723, 34444877, 24538106, 24984246, - 57419264, 30522764, - ]), - y_minus_x: FieldElement2625([ - 25008885, 22782833, 62803832, 23916421, 16265035, 15721635, 683793, 21730648, - 15723478, 18390951, - ]), - xy2d: FieldElement2625([ - 57448220, 12374378, 40101865, 26528283, 59384749, 21239917, 11879681, 5400171, - 519526, 32318556, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 22258378, 50776631, 59239045, 14613015, 44588609, 30603508, 46754982, 40870398, - 16648396, 41160072, - ]), - y_minus_x: FieldElement2625([ - 59027556, 25089834, 58885552, 9719709, 19259459, 18206220, 23994941, 28272877, - 57640015, 4763277, - ]), - xy2d: FieldElement2625([ - 45409620, 9220968, 51378240, 1084136, 41632757, 30702041, 31088446, 25789909, - 55752334, 728111, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 26047201, 55357393, 127317403, 50587064, 91200930, 9158118, 62835319, 20998873, - 104852291, 28056158, - ]), - y_minus_x: FieldElement2625([ - 17510331, 33231575, 5854288, 8403524, 17133918, 30441820, 38997856, 12327944, - 10750447, 10014012, - ]), - xy2d: FieldElement2625([ - 56796096, 3936951, 9156313, 24656749, 16498691, 32559785, 39627812, 32887699, - 3424690, 7540221, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 97431206, 26590321, 78469868, 29411114, 74542167, 4989747, 127146306, 50791643, - 57864597, 48812477, - ]), - y_minus_x: FieldElement2625([ - 13054543, 30774935, 19155473, 469045, 54626067, 4566041, 5631406, 2711395, - 1062915, 28418087, - ]), - xy2d: FieldElement2625([ - 47868616, 22299832, 37599834, 26054466, 61273100, 13005410, 61042375, 12194496, - 32960380, 1459310, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 86960860, 40582355, 90778216, 43574797, 75695366, 26896524, 67503060, 27452546, - 85746866, 55933926, - ]), - y_minus_x: FieldElement2625([ - 31395515, 15098109, 26581030, 8030562, 50580950, 28547297, 9012485, 25970078, - 60465776, 28111795, - ]), - xy2d: FieldElement2625([ - 57916680, 31207054, 65111764, 4529533, 25766844, 607986, 67095642, 9677542, - 34813975, 27098423, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 64664330, 33404494, 96457765, 8186664, 68982624, 12489862, 103283149, 25714738, - 59256019, 58970434, - ]), - y_minus_x: FieldElement2625([ - 51872508, 18120922, 7766469, 746860, 26346930, 23332670, 39775412, 10754587, - 57677388, 5203575, - ]), - xy2d: FieldElement2625([ - 31834314, 14135496, 66338857, 5159117, 20917671, 16786336, 59640890, 26216907, - 31809242, 7347066, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 57502122, 21680191, 87523322, 46588417, 80825387, 21862550, 86906833, 21343176, - 82301739, 31466941, - ]), - y_minus_x: FieldElement2625([ - 54445282, 31372712, 1168161, 29749623, 26747876, 19416341, 10609329, 12694420, - 33473243, 20172328, - ]), - xy2d: FieldElement2625([ - 33184999, 11180355, 15832085, 22169002, 65475192, 225883, 15089336, 22530529, - 60973201, 14480052, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 98417562, 27934433, 98139703, 31657332, 82783410, 26971548, 72605071, 13685226, - 27595050, 42291707, - ]), - y_minus_x: FieldElement2625([ - 46790012, 18404192, 10933842, 17376410, 8335351, 26008410, 36100512, 20943827, - 26498113, 66511, - ]), - xy2d: FieldElement2625([ - 22644435, 24792703, 50437087, 4884561, 64003250, 19995065, 30540765, 29267685, - 53781076, 26039336, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 106199862, 9834843, 85726071, 30873119, 63706907, 53801357, 75314402, 13585436, - 117090263, 48669869, - ]), - y_minus_x: FieldElement2625([ - 23711543, 32881517, 31206560, 25191721, 6164646, 23844445, 33572981, 32128335, - 8236920, 16492939, - ]), - xy2d: FieldElement2625([ - 43198286, 20038905, 40809380, 29050590, 25005589, 25867162, 19574901, 10071562, - 6708380, 27332008, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 69210217, 28624377, 86811594, 35922006, 118790560, 34602105, 72409880, - 42883131, 29955600, 55430554, - ]), - y_minus_x: FieldElement2625([ - 3096359, 9271816, 45488000, 18032587, 52260867, 25961494, 41216721, 20918836, - 57191288, 6216607, - ]), - xy2d: FieldElement2625([ - 34493015, 338662, 41913253, 2510421, 37895298, 19734218, 24822829, 27407865, - 40341383, 7525078, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 44042196, 53123240, 83242349, 25658253, 130828162, 34333218, 66198527, - 30771936, 47722230, 45548532, - ]), - y_minus_x: FieldElement2625([ - 21691500, 19929806, 66467532, 19187410, 3285880, 30070836, 42044197, 9718257, - 59631427, 13381417, - ]), - xy2d: FieldElement2625([ - 18445390, 29352196, 14979845, 11622458, 65381754, 29971451, 23111647, 27179185, - 28535281, 15779576, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 30098034, 36644094, 124983340, 16662133, 45801924, 44862842, 53040409, - 12021729, 77064149, 17251075, - ]), - y_minus_x: FieldElement2625([ - 9734894, 18977602, 59635230, 24415696, 2060391, 11313496, 48682835, 9924398, - 20194861, 13380996, - ]), - xy2d: FieldElement2625([ - 40730762, 25589224, 44941042, 15789296, 49053522, 27385639, 65123949, 15707770, - 26342023, 10146099, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 41091971, 33334488, 88448054, 33513043, 86854119, 30675731, 37471583, 35781471, - 21612325, 33008704, - ]), - y_minus_x: FieldElement2625([ - 54031477, 1184227, 23562814, 27583990, 46757619, 27205717, 25764460, 12243797, - 46252298, 11649657, - ]), - xy2d: FieldElement2625([ - 57077370, 11262625, 27384172, 2271902, 26947504, 17556661, 39943, 6114064, - 33514190, 2333242, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 112784121, 54687041, 75228644, 40774344, 45278341, 58092729, 60429112, - 54438225, 91459440, 20104430, - ]), - y_minus_x: FieldElement2625([ - 62992557, 22282898, 43222677, 4843614, 37020525, 690622, 35572776, 23147595, - 8317859, 12352766, - ]), - xy2d: FieldElement2625([ - 18200138, 19078521, 34021104, 30857812, 43406342, 24451920, 43556767, 31266881, - 20712162, 6719373, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 26656189, 39629685, 59250307, 35440503, 105873684, 37816756, 78226393, - 29791221, 26224234, 30256974, - ]), - y_minus_x: FieldElement2625([ - 49939907, 18700334, 63713187, 17184554, 47154818, 14050419, 21728352, 9493610, - 18620611, 17125804, - ]), - xy2d: FieldElement2625([ - 53785524, 13325348, 11432106, 5964811, 18609221, 6062965, 61839393, 23828875, - 36407290, 17074774, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 43248307, 55875704, 94070219, 35195292, 34695751, 16816491, 79357372, 28313792, - 80844205, 35488493, - ]), - y_minus_x: FieldElement2625([ - 25089769, 6742589, 17081145, 20148166, 21909292, 17486451, 51972569, 29789085, - 45830866, 5473615, - ]), - xy2d: FieldElement2625([ - 31883658, 25593331, 1083431, 21982029, 22828470, 13290673, 59983779, 12469655, - 29111212, 28103418, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 91353792, 52058456, 107954750, 36345970, 52111264, 50221109, 91476329, - 39943270, 56813276, 34006814, - ]), - y_minus_x: FieldElement2625([ - 41468082, 30136590, 5217915, 16224624, 19987036, 29472163, 42872612, 27639183, - 15766061, 8407814, - ]), - xy2d: FieldElement2625([ - 46701865, 13990230, 15495425, 16395525, 5377168, 15166495, 58191841, 29165478, - 59040954, 2276717, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 30157899, 46478498, 116505677, 42800183, 87003891, 36922573, 43281276, - 38650650, 89849239, 26251014, - ]), - y_minus_x: FieldElement2625([ - 2041139, 19298082, 7783686, 13876377, 41161879, 20201972, 24051123, 13742383, - 51471265, 13295221, - ]), - xy2d: FieldElement2625([ - 33338218, 25048699, 12532112, 7977527, 9106186, 31839181, 49388668, 28941459, - 62657506, 18884987, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 47063564, 39008528, 52762315, 40001577, 28862070, 35438083, 64639597, 29412551, - 74879432, 43175028, - ]), - y_minus_x: FieldElement2625([ - 23208049, 7979712, 33071466, 8149229, 1758231, 22719437, 30945527, 31860109, - 33606523, 18786461, - ]), - xy2d: FieldElement2625([ - 1439939, 17283952, 66028874, 32760649, 4625401, 10647766, 62065063, 1220117, - 30494170, 22113633, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 62071265, 20526136, 64138304, 30492664, 82749837, 26852765, 40369837, 34480481, - 65424524, 20220784, - ]), - y_minus_x: FieldElement2625([ - 13908495, 30005160, 30919927, 27280607, 45587000, 7989038, 9021034, 9078865, - 3353509, 4033511, - ]), - xy2d: FieldElement2625([ - 37445433, 18440821, 32259990, 33209950, 24295848, 20642309, 23161162, 8839127, - 27485041, 7356032, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 76769853, 34259874, 79088928, 28184277, 65480320, 14661172, 60762722, 36179446, - 95539899, 50337029, - ]), - y_minus_x: FieldElement2625([ - 43269631, 25243016, 41163352, 7480957, 49427195, 25200248, 44562891, 14150564, - 15970762, 4099461, - ]), - xy2d: FieldElement2625([ - 29262576, 16756590, 26350592, 24760869, 8529670, 22346382, 13617292, 23617289, - 11465738, 8317062, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 41615764, 26591503, 99609063, 24135380, 44070139, 31252209, 82007500, 37402886, - 88078197, 28396915, - ]), - y_minus_x: FieldElement2625([ - 46724414, 19206718, 48772458, 13884721, 34069410, 2842113, 45498038, 29904543, - 11177094, 14989547, - ]), - xy2d: FieldElement2625([ - 42612143, 21838415, 16959895, 2278463, 12066309, 10137771, 13515641, 2581286, - 38621356, 9930239, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 49357223, 31456605, 83653163, 54099563, 118302919, 18605349, 18345766, - 53705111, 83400343, 28240393, - ]), - y_minus_x: FieldElement2625([ - 33879670, 2553287, 32678213, 9875984, 8534129, 6889387, 57432090, 6957616, - 4368891, 9788741, - ]), - xy2d: FieldElement2625([ - 16660737, 7281060, 56278106, 12911819, 20108584, 25452756, 45386327, 24941283, - 16250551, 22443329, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 47343357, 35944957, 117666696, 14161978, 69014150, 39969338, 71798447, - 10604806, 104027325, 4782745, - ]), - y_minus_x: FieldElement2625([ - 65754325, 14736940, 59741422, 20261545, 7710541, 19398842, 57127292, 4383044, - 22546403, 437323, - ]), - xy2d: FieldElement2625([ - 31665558, 21373968, 50922033, 1491338, 48740239, 3294681, 27343084, 2786261, - 36475274, 19457415, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 52641566, 32870716, 33734756, 41002983, 19294359, 14334329, 47418233, 35909750, - 47824192, 27440058, - ]), - y_minus_x: FieldElement2625([ - 15121312, 17758270, 6377019, 27523071, 56310752, 20596586, 18952176, 15496498, - 37728731, 11754227, - ]), - xy2d: FieldElement2625([ - 64471568, 20071356, 8488726, 19250536, 12728760, 31931939, 7141595, 11724556, - 22761615, 23420291, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 16918416, 11729663, 49025285, 36577418, 103201995, 53769203, 38367677, - 21327038, 32851221, 11717399, - ]), - y_minus_x: FieldElement2625([ - 11166615, 7338049, 60386341, 4531519, 37640192, 26252376, 31474878, 3483633, - 65915689, 29523600, - ]), - xy2d: FieldElement2625([ - 66923210, 9921304, 31456609, 20017994, 55095045, 13348922, 33142652, 6546660, - 47123585, 29606055, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 101757113, 44821142, 55911756, 25655328, 31703693, 37410335, 58571732, - 20721383, 36336829, 18068118, - ]), - y_minus_x: FieldElement2625([ - 49102387, 12709067, 3991746, 27075244, 45617340, 23004006, 35973516, 17504552, - 10928916, 3011958, - ]), - xy2d: FieldElement2625([ - 60151107, 17960094, 31696058, 334240, 29576716, 14796075, 36277808, 20749251, - 18008030, 10258577, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 44660220, 49210000, 74127342, 29144428, 36794597, 32352840, 65255398, 34921551, - 92236737, 6671742, - ]), - y_minus_x: FieldElement2625([ - 29701166, 19180498, 56230743, 9279287, 67091296, 13127209, 21382910, 11042292, - 25838796, 4642684, - ]), - xy2d: FieldElement2625([ - 46678630, 14955536, 42982517, 8124618, 61739576, 27563961, 30468146, 19653792, - 18423288, 4177476, - ]), - }, - ]), - ]); - -/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. -pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = - NafLookupTable8([ - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 93076338, 52752828, 29566454, 37215328, 54414518, 37569218, 94653489, 21800160, - 61029707, 35602036, - ]), - y_minus_x: FieldElement2625([ - 54563134, 934261, 64385954, 3049989, 66381436, 9406985, 12720692, 5043384, - 19500929, 18085054, - ]), - xy2d: FieldElement2625([ - 58370664, 4489569, 9688441, 18769238, 10184608, 21191052, 29287918, 11864899, - 42594502, 29115885, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 82745136, 23865874, 24204772, 25642034, 67725840, 16869169, 94896463, 52336674, - 28944398, 32004408, - ]), - y_minus_x: FieldElement2625([ - 16568933, 4717097, 55552716, 32452109, 15682895, 21747389, 16354576, 21778470, - 7689661, 11199574, - ]), - xy2d: FieldElement2625([ - 30464137, 27578307, 55329429, 17883566, 23220364, 15915852, 7512774, 10017326, - 49359771, 23634074, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77970208, 11473153, 27284546, 35535607, 37044514, 46132292, 99976748, 48069538, - 118779423, 44373810, - ]), - y_minus_x: FieldElement2625([ - 4708026, 6336745, 20377586, 9066809, 55836755, 6594695, 41455196, 12483687, - 54440373, 5581305, - ]), - xy2d: FieldElement2625([ - 19563141, 16186464, 37722007, 4097518, 10237984, 29206317, 28542349, 13850243, - 43430843, 17738489, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 72262591, 43463716, 68832610, 30776557, 97632468, 39071304, 86589715, 38784565, - 43156424, 18378665, - ]), - y_minus_x: FieldElement2625([ - 36839857, 30090922, 7665485, 10083793, 28475525, 1649722, 20654025, 16520125, - 30598449, 7715701, - ]), - xy2d: FieldElement2625([ - 28881826, 14381568, 9657904, 3680757, 46927229, 7843315, 35708204, 1370707, - 29794553, 32145132, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 44589852, 26862249, 14201701, 24808930, 43598457, 42399157, 85583074, 32192981, - 54046167, 47376308, - ]), - y_minus_x: FieldElement2625([ - 60653668, 25714560, 3374701, 28813570, 40010246, 22982724, 31655027, 26342105, - 18853321, 19333481, - ]), - xy2d: FieldElement2625([ - 4566811, 20590564, 38133974, 21313742, 59506191, 30723862, 58594505, 23123294, - 2207752, 30344648, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 41954014, 62923042, 96790006, 41423232, 60254202, 24130566, 121780363, 32891430, - 103106264, 17421994, - ]), - y_minus_x: FieldElement2625([ - 25576264, 30851218, 7349803, 21739588, 16472781, 9300885, 3844789, 15725684, - 171356, 6466918, - ]), - xy2d: FieldElement2625([ - 23103977, 13316479, 9739013, 17404951, 817874, 18515490, 8965338, 19466374, - 36393951, 16193876, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 100695917, 36735143, 64714733, 47558118, 50205389, 17283591, 84347261, 38283886, - 49034350, 9256799, - ]), - y_minus_x: FieldElement2625([ - 41926547, 29380300, 32336397, 5036987, 45872047, 11360616, 22616405, 9761698, - 47281666, 630304, - ]), - xy2d: FieldElement2625([ - 53388152, 2639452, 42871404, 26147950, 9494426, 27780403, 60554312, 17593437, - 64659607, 19263131, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 63957664, 28508356, 76391577, 40420576, 102310665, 32691407, 48168288, 15033783, - 92213982, 25659555, - ]), - y_minus_x: FieldElement2625([ - 42782475, 15950225, 35307649, 18961608, 55446126, 28463506, 1573891, 30928545, - 2198789, 17749813, - ]), - xy2d: FieldElement2625([ - 64009494, 10324966, 64867251, 7453182, 61661885, 30818928, 53296841, 17317989, - 34647629, 21263748, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 17735022, 27114469, 76149336, 40765111, 43325570, 26153544, 26948151, 45905235, - 38656900, 62179684, - ]), - y_minus_x: FieldElement2625([ - 2154119, 14782993, 28737794, 11906199, 36205504, 26488101, 19338132, 16910143, - 50209922, 29794297, - ]), - xy2d: FieldElement2625([ - 29935700, 6336041, 20999566, 30405369, 13628497, 24612108, 61639745, 22359641, - 56973806, 18684690, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 29792811, 31379227, 113441390, 20675662, 58452680, 54138549, 42892249, 32958636, - 31674345, 24275271, - ]), - y_minus_x: FieldElement2625([ - 7606599, 22131225, 17376912, 15235046, 32822971, 7512882, 30227203, 14344178, - 9952094, 8804749, - ]), - xy2d: FieldElement2625([ - 32575079, 3961822, 36404898, 17773250, 67073898, 1319543, 30641032, 7823672, - 63309858, 18878784, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77823924, 52933642, 26572931, 18690221, 109143683, 23989794, 79129572, 53326100, - 38888709, 55889506, - ]), - y_minus_x: FieldElement2625([ - 37146997, 554126, 63326061, 20925660, 49205290, 8620615, 53375504, 25938867, - 8752612, 31225894, - ]), - xy2d: FieldElement2625([ - 4529887, 12416158, 60388162, 30157900, 15427957, 27628808, 61150927, 12724463, - 23658330, 23690055, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 102043267, 54823614, 45810225, 19657305, 54297192, 7413280, 66851983, 39718512, - 25005048, 18002658, - ]), - y_minus_x: FieldElement2625([ - 5403481, 24654166, 61855580, 13522652, 14989680, 1879017, 43913069, 25724172, - 20315901, 421248, - ]), - xy2d: FieldElement2625([ - 34818947, 1705239, 25347020, 7938434, 51632025, 1720023, 54809726, 32655885, - 64907986, 5517607, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 88543525, 16557377, 80359887, 30047148, 91602876, 27723948, 62710290, 52707861, - 7715736, 61648232, - ]), - y_minus_x: FieldElement2625([ - 14461032, 6393639, 22681353, 14533514, 52493587, 3544717, 57780998, 24657863, - 59891807, 31628125, - ]), - xy2d: FieldElement2625([ - 60864886, 31199953, 18524951, 11247802, 43517645, 21165456, 26204394, 27268421, - 63221077, 29979135, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 97491378, 10077555, 94805128, 42472719, 30231379, 17961119, 76201413, 41182329, - 41405214, 31798052, - ]), - y_minus_x: FieldElement2625([ - 13670592, 720327, 7131696, 19360499, 66651570, 16947532, 3061924, 22871019, - 39814495, 20141336, - ]), - xy2d: FieldElement2625([ - 44847187, 28379568, 38472030, 23697331, 49441718, 3215393, 1669253, 30451034, - 62323912, 29368533, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 74923758, 35244493, 27222384, 30715870, 48444195, 28125622, 116052444, 32330148, - 92609232, 35372537, - ]), - y_minus_x: FieldElement2625([ - 39340596, 15199968, 52787715, 18781603, 18787729, 5464578, 11652644, 8722118, - 57056621, 5153960, - ]), - xy2d: FieldElement2625([ - 5733861, 14534448, 59480402, 15892910, 30737296, 188529, 491756, 17646733, - 33071791, 15771063, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 85239571, 21331573, 119690709, 30172286, 44350959, 55826224, 68258766, 16209406, - 20222151, 32139086, - ]), - y_minus_x: FieldElement2625([ - 52372801, 13847470, 52690845, 3802477, 48387139, 10595589, 13745896, 3112846, - 50361463, 2761905, - ]), - xy2d: FieldElement2625([ - 45982696, 12273933, 15897066, 704320, 31367969, 3120352, 11710867, 16405685, - 19410991, 10591627, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 82008850, 34439758, 89319886, 49124188, 34309215, 29866047, 80308709, 27738519, - 71739865, 46909287, - ]), - y_minus_x: FieldElement2625([ - 36631997, 23300851, 59535242, 27474493, 59924914, 29067704, 17551261, 13583017, - 37580567, 31071178, - ]), - xy2d: FieldElement2625([ - 22641770, 21277083, 10843473, 1582748, 37504588, 634914, 15612385, 18139122, - 59415250, 22563863, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 76721854, 52814714, 41722368, 35285867, 53022548, 38255176, 93163883, 27627617, - 87963092, 33729456, - ]), - y_minus_x: FieldElement2625([ - 61915349, 11733561, 59403492, 31381562, 29521830, 16845409, 54973419, 26057054, - 49464700, 796779, - ]), - xy2d: FieldElement2625([ - 3855018, 8248512, 12652406, 88331, 2948262, 971326, 15614761, 9441028, 29507685, - 8583792, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 76968870, 14808584, 76708906, 57649718, 23400175, 24077237, 63783137, 37471119, - 56750251, 30681804, - ]), - y_minus_x: FieldElement2625([ - 33709664, 3740344, 52888604, 25059045, 46197996, 22678812, 45207164, 6431243, - 21300862, 27646257, - ]), - xy2d: FieldElement2625([ - 49811511, 9216232, 25043921, 18738174, 29145960, 3024227, 65580502, 530149, - 66809973, 22275500, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 23499366, 24936714, 38355445, 35908587, 82540167, 39280880, 46809413, 41143783, - 72530804, 49676198, - ]), - y_minus_x: FieldElement2625([ - 45162189, 23851397, 9380591, 15192763, 36034862, 15525765, 5277811, 25040629, - 33286237, 31693326, - ]), - xy2d: FieldElement2625([ - 62424427, 13336013, 49368582, 1581264, 30884213, 15048226, 66823504, 4736577, - 53805192, 29608355, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 25190215, 26304748, 58928336, 42665707, 64280342, 38580230, 61299598, 20659504, - 30387592, 32519377, - ]), - y_minus_x: FieldElement2625([ - 14480213, 17057820, 2286692, 32980967, 14693157, 22197912, 49247898, 9909859, - 236428, 16857435, - ]), - xy2d: FieldElement2625([ - 7877514, 29872867, 45886243, 25902853, 41998762, 6241604, 35694938, 15657879, - 56797932, 8609105, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54245189, 32562161, 57887697, 19509733, 45323534, 37472546, 27606727, 59528498, - 74398957, 44973176, - ]), - y_minus_x: FieldElement2625([ - 28964163, 20950093, 44929966, 26145892, 34786807, 18058153, 18187179, 27016486, - 42438836, 14869174, - ]), - xy2d: FieldElement2625([ - 55703901, 1222455, 64329400, 24533246, 11330890, 9135834, 3589529, 19555234, - 53275553, 1207212, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 33323313, 35603165, 79328585, 6017848, 71286345, 23804207, 86644124, 44008367, - 55775078, 31816581, - ]), - y_minus_x: FieldElement2625([ - 64814718, 27217688, 29891310, 4504619, 8548709, 21986323, 62140656, 12555980, - 34377058, 21436823, - ]), - xy2d: FieldElement2625([ - 49069441, 9880212, 33350825, 24576421, 24446077, 15616561, 19302117, 9370836, - 55172180, 28526191, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 95404934, 26757208, 123864063, 4572839, 69249194, 43584425, 53559055, 41742046, - 41167331, 24643278, - ]), - y_minus_x: FieldElement2625([ - 35101859, 30958612, 66105296, 3168612, 22836264, 10055966, 22893634, 13045780, - 28576558, 30704591, - ]), - xy2d: FieldElement2625([ - 59987873, 21166324, 43296694, 15387892, 39447987, 19996270, 5059183, 19972934, - 30207804, 29631666, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 67444156, 16132892, 88330413, 37924284, 68147855, 57949418, 91481571, 24889160, - 62329722, 50712214, - ]), - y_minus_x: FieldElement2625([ - 56922508, 1347520, 23300731, 27393371, 42651667, 8512932, 27610931, 24436993, - 3998295, 3835244, - ]), - xy2d: FieldElement2625([ - 16327050, 22776956, 14746360, 22599650, 23700920, 11727222, 25900154, 21823218, - 34907363, 25105813, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 59807886, 12089757, 115624210, 41476837, 67589715, 26361580, 71355762, 44268661, - 67753061, 13128476, - ]), - y_minus_x: FieldElement2625([ - 7174885, 26592113, 59892333, 6465478, 4145835, 17673606, 38764952, 22293290, - 1360980, 25805937, - ]), - xy2d: FieldElement2625([ - 40179568, 6331649, 42386021, 20205884, 15635073, 6103612, 56391180, 6789942, - 7597240, 24095312, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54776568, 36935932, 18757261, 41429535, 67215081, 34700142, 86560976, 61204154, - 26496794, 19612129, - ]), - y_minus_x: FieldElement2625([ - 46701540, 24101444, 49515651, 25946994, 45338156, 9941093, 55509371, 31298943, - 1347425, 15381335, - ]), - xy2d: FieldElement2625([ - 53576449, 26135856, 17092785, 3684747, 57829121, 27109516, 2987881, 10987137, - 52269096, 15465522, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 80033010, 26264316, 72380996, 10039544, 94605936, 30615493, 60406855, 30400829, - 120765849, 45301372, - ]), - y_minus_x: FieldElement2625([ - 35668062, 24246990, 47788280, 25128298, 37456967, 19518969, 43459670, 10724644, - 7294162, 4471290, - ]), - xy2d: FieldElement2625([ - 33813988, 3549109, 101112, 21464449, 4858392, 3029943, 59999440, 21424738, - 34313875, 1512799, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 29494960, 28240930, 51093230, 28823678, 92791151, 54796794, 77571888, 37795542, - 75765856, 10649531, - ]), - y_minus_x: FieldElement2625([ - 63536751, 7572551, 62249759, 25202639, 32046232, 32318941, 29315141, 15424555, - 24706712, 28857648, - ]), - xy2d: FieldElement2625([ - 47618751, 5819839, 19528172, 20715950, 40655763, 20611047, 4960954, 6496879, - 2790858, 28045273, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 85174457, 55843901, 111946683, 31021158, 32797785, 48944265, 78338887, 31144772, - 82688001, 38470222, - ]), - y_minus_x: FieldElement2625([ - 49664705, 3638040, 57888693, 19234931, 40104182, 28143840, 28667142, 18386877, - 18584835, 3592929, - ]), - xy2d: FieldElement2625([ - 12065039, 18867394, 6430594, 17107159, 1727094, 13096957, 61520237, 27056604, - 27026997, 13543966, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 68512926, 37577278, 94695528, 14209106, 95849194, 30038709, 51818051, 20241476, - 68980056, 42251074, - ]), - y_minus_x: FieldElement2625([ - 17325298, 33376175, 65271265, 4931225, 31708266, 6292284, 23064744, 22072792, - 43945505, 9236924, - ]), - xy2d: FieldElement2625([ - 51955585, 20268063, 61151838, 26383348, 4766519, 20788033, 21173534, 27030753, - 9509140, 7790046, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 24124086, 38918775, 28620390, 10538620, 59433851, 19581010, 60862718, 43500219, - 77600721, 32213801, - ]), - y_minus_x: FieldElement2625([ - 7062127, 13930079, 2259902, 6463144, 32137099, 24748848, 41557343, 29331342, - 47345194, 13022814, - ]), - xy2d: FieldElement2625([ - 18921826, 392002, 55817981, 6420686, 8000611, 22415972, 14722962, 26246290, - 20604450, 8079345, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 67710253, 26257798, 51499391, 46550521, 30228769, 53940987, 76234206, 43362242, - 77953697, 21034392, - ]), - y_minus_x: FieldElement2625([ - 25817710, 8020883, 50134679, 21244805, 47057788, 8766556, 29308546, 22307963, - 49449920, 23874253, - ]), - xy2d: FieldElement2625([ - 11081015, 13522660, 12474691, 29260223, 48687631, 9341946, 16850694, 18637605, - 6199839, 14303642, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 64518173, 19894035, 117213833, 43031641, 79641718, 39533880, 66531934, 41205092, - 117735515, 13989682, - ]), - y_minus_x: FieldElement2625([ - 6921800, 4421166, 59739491, 30510778, 43106355, 30941531, 9363541, 3394240, - 50874187, 23872585, - ]), - xy2d: FieldElement2625([ - 54293979, 23466866, 47184247, 20627378, 8313211, 5865878, 5948507, 32290343, - 52583140, 23139870, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 111574723, 24134616, 49842442, 23485580, 34844037, 45228427, 67103167, 25858409, - 38508586, 35097070, - ]), - y_minus_x: FieldElement2625([ - 19879846, 15259900, 25020018, 14261729, 22075205, 25189303, 787540, 31325033, - 62422289, 16131171, - ]), - xy2d: FieldElement2625([ - 39487053, 27893575, 34654176, 25620816, 60209846, 23603919, 8931189, 12275052, - 38626469, 33438928, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 105416367, 9568747, 62672739, 49685015, 106242995, 4547918, 18403901, 38581738, - 60829966, 33150322, - ]), - y_minus_x: FieldElement2625([ - 7950033, 25841033, 47276506, 3884935, 62418883, 2342083, 50269031, 14194015, - 27013685, 3320257, - ]), - xy2d: FieldElement2625([ - 35270691, 18076829, 46994271, 4273335, 43595882, 31742297, 58328702, 4594760, - 49180851, 18144010, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 30194115, 50068680, 49746331, 27470090, 40428285, 23271051, 70252167, 16153483, - 123511881, 27809602, - ]), - y_minus_x: FieldElement2625([ - 27113466, 6865046, 4512771, 29327742, 29021084, 7405965, 33302911, 9322435, - 4307527, 32438240, - ]), - xy2d: FieldElement2625([ - 29337813, 24673346, 10359233, 30347534, 57709483, 9930840, 60607771, 24076133, - 20985293, 22480923, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 14579237, 33467236, 85745988, 15769997, 101228358, 21649866, 82685456, 59023858, - 86175344, 24337101, - ]), - y_minus_x: FieldElement2625([ - 4472119, 14702190, 10432042, 22460027, 708461, 18783996, 34234374, 30870323, - 63796457, 10370850, - ]), - xy2d: FieldElement2625([ - 36957127, 19555637, 16244231, 24367549, 58999881, 13440043, 35147632, 8718974, - 43101064, 18487380, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 21818223, 34477173, 23913863, 22441963, 129271975, 14842154, 43035020, 9485973, - 53819529, 22318987, - ]), - y_minus_x: FieldElement2625([ - 10874834, 4351765, 66252340, 17269436, 64427034, 30735311, 5883785, 28998531, - 44403022, 26064601, - ]), - xy2d: FieldElement2625([ - 64017630, 9755550, 37507935, 22752543, 4031638, 29903925, 47267417, 32706846, - 39147952, 21635901, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 81365001, 44927611, 97395185, 43985591, 66242539, 38517499, 52937891, 37374973, - 73352483, 38476849, - ]), - y_minus_x: FieldElement2625([ - 43460763, 24260930, 21493330, 30888969, 23329454, 24545577, 58286855, 12750266, - 22391140, 26198125, - ]), - xy2d: FieldElement2625([ - 20477567, 24078713, 1674568, 4102219, 25208396, 13972305, 30389482, 19572626, - 1485666, 17679765, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 100511110, 23887606, 116505658, 30877106, 45483774, 25222431, 67931340, 37154158, - 32618865, 18610785, - ]), - y_minus_x: FieldElement2625([ - 48647066, 166413, 55454758, 8889513, 21027475, 32728181, 43100067, 4690060, - 7520989, 16421303, - ]), - xy2d: FieldElement2625([ - 14868391, 20996450, 64836606, 1042490, 27060176, 10253541, 53431276, 19516737, - 41808946, 2239538, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 50228416, 29594943, 62030348, 10307368, 70970997, 20292574, 126292474, 51543890, - 67827181, 15848795, - ]), - y_minus_x: FieldElement2625([ - 5548701, 17911007, 33137864, 32764443, 31146554, 17931096, 64023370, 7290289, - 6361313, 32861205, - ]), - xy2d: FieldElement2625([ - 63374742, 30320053, 4091667, 30955480, 44819449, 2212055, 52638826, 22391938, - 38484599, 7051029, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 50485560, 7033600, 57711425, 10740562, 72347547, 42328739, 7593987, 46950560, - 85560721, 41970063, - ]), - y_minus_x: FieldElement2625([ - 40930651, 3776911, 39108529, 2508077, 19371703, 7626128, 4092943, 15778278, - 42044145, 24540103, - ]), - xy2d: FieldElement2625([ - 44128555, 8867576, 8645499, 22222278, 11497130, 4344907, 10788462, 23382703, - 3547104, 15368835, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 81786515, 51902785, 74560130, 22753403, 52379722, 41395524, 57994925, 6818020, - 57707296, 16352835, - ]), - y_minus_x: FieldElement2625([ - 21622574, 18581624, 36511951, 1212467, 36930308, 7910192, 20622927, 2438677, - 52628762, 29068327, - ]), - xy2d: FieldElement2625([ - 6797431, 2854059, 4269865, 8037366, 32016522, 15223213, 34765784, 15297582, - 3559197, 26425254, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 107761639, 61759660, 79235166, 8794359, 48418924, 60111631, 87862210, 33613219, - 68436482, 40229362, - ]), - y_minus_x: FieldElement2625([ - 52388944, 32880897, 37676257, 8253690, 32826330, 2707379, 25088512, 17182878, - 15053907, 11601568, - ]), - xy2d: FieldElement2625([ - 43894091, 25425955, 50962615, 28097648, 30129084, 13258436, 39364589, 8197601, - 58181660, 15003422, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 13470722, 47835674, 31012390, 30525035, 89789519, 50713267, 39648035, 13815677, - 94028755, 62582101, - ]), - y_minus_x: FieldElement2625([ - 54478677, 14782829, 56712503, 7094748, 41775828, 29409658, 9084386, 30179063, - 64014926, 32519086, - ]), - xy2d: FieldElement2625([ - 6314429, 20018828, 12535891, 19610611, 10074031, 28087963, 50489447, 26314252, - 24553876, 32746308, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 105768482, 46629424, 103418946, 65789027, 85765355, 28316167, 56299027, 22780838, - 122676432, 32376204, - ]), - y_minus_x: FieldElement2625([ - 5654403, 26425050, 39347935, 963424, 5032477, 19850195, 30011537, 11153401, - 63182039, 13343989, - ]), - xy2d: FieldElement2625([ - 1130444, 29814849, 40569426, 8144467, 24179188, 6267924, 63847147, 2912740, - 63870704, 29186744, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 49722534, 11073633, 52865263, 50829611, 33921405, 38614719, 32360242, 35465390, - 50107050, 45035301, - ]), - y_minus_x: FieldElement2625([ - 2003571, 2472803, 46902183, 1716406, 58609069, 15922982, 43766122, 27456369, - 33468339, 29346282, - ]), - xy2d: FieldElement2625([ - 18834217, 8245144, 29896065, 3490830, 62967493, 7220277, 146130, 18459164, - 57533060, 30070422, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 77805507, 38474121, 73459597, 18553340, 107508318, 52705654, 33655873, 27331956, - 44498407, 13768350, - ]), - y_minus_x: FieldElement2625([ - 23652128, 27647291, 43351590, 13262712, 65238054, 26296349, 11902126, 2949002, - 34445239, 25602117, - ]), - xy2d: FieldElement2625([ - 55906958, 19046111, 28501158, 28224561, 14495533, 14714956, 32929972, 2643566, - 17034893, 11645825, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 38181639, 29751709, 73650473, 17760526, 80753587, 17992258, 72670209, 41214427, - 87524152, 37630124, - ]), - y_minus_x: FieldElement2625([ - 6498441, 12053607, 10375600, 14764370, 24795955, 16159258, 57849421, 16071837, - 31008329, 3792564, - ]), - xy2d: FieldElement2625([ - 47930485, 9176956, 54248931, 8732776, 58000258, 10333519, 96092, 29273884, - 13051277, 20121493, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 54190492, 49837594, 61282066, 10734597, 67926686, 36967416, 115462142, 30339271, - 37200685, 30036936, - ]), - y_minus_x: FieldElement2625([ - 21193614, 19929501, 18841215, 29565554, 64002173, 11123558, 14111648, 6069945, - 30307604, 25935103, - ]), - xy2d: FieldElement2625([ - 58539773, 2098685, 38301131, 15844175, 41633654, 16934366, 15145895, 5543861, - 64050790, 6595361, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 34107945, 34731353, 51956038, 5614778, 79079051, 30288154, 47460410, 22186730, - 30689695, 19628976, - ]), - y_minus_x: FieldElement2625([ - 25043248, 19224237, 46048097, 32289319, 29339134, 12397721, 37385860, 12978240, - 57951631, 31419653, - ]), - xy2d: FieldElement2625([ - 46038439, 28501736, 62566522, 12609283, 35236982, 30457796, 64113609, 14800343, - 6412849, 6276813, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 124528774, 39505727, 83050803, 41361190, 116071796, 37845759, 61633481, 38385016, - 71255100, 31629488, - ]), - y_minus_x: FieldElement2625([ - 249426, 17196749, 35434953, 13884216, 11701636, 24553269, 51821986, 12900910, - 34844073, 16150118, - ]), - xy2d: FieldElement2625([ - 2520516, 14697628, 15319213, 22684490, 62866663, 29666431, 13872507, 7473319, - 12419515, 2958466, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 101517167, 22298305, 98222207, 59471046, 61547444, 50370568, 97111094, 42539051, - 14298448, 49873561, - ]), - y_minus_x: FieldElement2625([ - 19427905, 12004555, 9971383, 28189868, 32306269, 23648270, 34176633, 10760437, - 53354280, 5634974, - ]), - xy2d: FieldElement2625([ - 30044319, 23677863, 60273406, 14563839, 9734978, 19808149, 30899064, 30835691, - 22828539, 23633348, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 25513026, 37111929, 37113703, 29589233, 77394412, 34745965, 95889446, 61766763, - 92876242, 37566563, - ]), - y_minus_x: FieldElement2625([ - 42139852, 9176396, 16274786, 33467453, 52558621, 7190768, 1490604, 31312359, - 44767199, 18491072, - ]), - xy2d: FieldElement2625([ - 4272877, 21431483, 45594743, 13027605, 59232641, 24151956, 38390319, 12906718, - 45915869, 15503563, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 29874396, 35808736, 25494239, 37976524, 43036007, 37144111, 18198811, 35141252, - 53490316, 47742788, - ]), - y_minus_x: FieldElement2625([ - 59518553, 28520621, 59946871, 29462027, 3630300, 29398589, 60425462, 24588735, - 53129947, 28399367, - ]), - xy2d: FieldElement2625([ - 18192774, 12787801, 32021061, 9158184, 48389348, 16385092, 11799402, 9492011, - 43154220, 15950102, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 68768204, 54638026, 33464925, 53430209, 66037964, 35360373, 22565155, 39168685, - 46605438, 51897954, - ]), - y_minus_x: FieldElement2625([ - 57660336, 29715319, 64414626, 32753338, 16894121, 935644, 53848937, 22684138, - 10541713, 14174330, - ]), - xy2d: FieldElement2625([ - 22888141, 12700209, 40301697, 6435658, 56329485, 5524686, 56715961, 6520808, - 15754965, 9355803, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 79549820, 26746924, 54931884, 38547877, 49672847, 19708985, 52599424, 12757151, - 93328625, 39524327, - ]), - y_minus_x: FieldElement2625([ - 33888606, 13911610, 18921581, 1162763, 46616901, 13799218, 29525142, 21929286, - 59295464, 503508, - ]), - xy2d: FieldElement2625([ - 57865531, 22043577, 17998312, 3038439, 52838371, 9832208, 43311531, 660991, - 25265267, 18977724, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 64010269, 23727746, 42277281, 48089313, 102316973, 34946803, 127880577, 38411468, - 114816699, 43712746, - ]), - y_minus_x: FieldElement2625([ - 56859315, 32558245, 41017090, 22610758, 13704990, 23215119, 2475037, 32344984, - 12799418, 11135856, - ]), - xy2d: FieldElement2625([ - 1867214, 27167702, 19772099, 16925005, 15366693, 25797692, 10829276, 15372827, - 26582557, 31642714, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 57265197, 20059797, 107314987, 30587501, 60553812, 25602102, 29690666, 37127097, - 103070929, 51772159, - ]), - y_minus_x: FieldElement2625([ - 56432653, 6329655, 42770975, 4187982, 30677076, 9335071, 60103332, 14755050, - 9451294, 574767, - ]), - xy2d: FieldElement2625([ - 52859018, 2867107, 56258365, 15719081, 5959372, 8703738, 29137781, 21575537, - 20249840, 31808689, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 74749335, 47235127, 9995910, 52200224, 92069015, 8964515, 33248715, 21201554, - 57573145, 31605506, - ]), - y_minus_x: FieldElement2625([ - 56307055, 23891752, 3613811, 30787942, 49031222, 26667524, 26985478, 31973510, - 26785294, 29587427, - ]), - xy2d: FieldElement2625([ - 30891460, 5254655, 47414930, 12769216, 42912782, 11830405, 7411958, 1394027, - 18778535, 18209370, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 61227949, 26179350, 57501473, 13585864, 102855675, 40344975, 54134826, 59707765, - 74122694, 12256219, - ]), - y_minus_x: FieldElement2625([ - 5975515, 16302413, 24341148, 28270615, 18786096, 22405501, 28243950, 28328004, - 53412289, 4381960, - ]), - xy2d: FieldElement2625([ - 9394648, 8758552, 26189703, 16642536, 35993528, 5117040, 5977877, 13955594, - 19244020, 24493735, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 111388362, 51822507, 30193028, 3993472, 110736308, 44014764, 107346699, 48464072, - 92830877, 56442511, - ]), - y_minus_x: FieldElement2625([ - 7236795, 30433657, 63588571, 620817, 11118384, 24979014, 66780154, 19877679, - 16217590, 26311105, - ]), - xy2d: FieldElement2625([ - 42540794, 21657271, 16455973, 23630199, 3992015, 21894417, 44876052, 19291718, - 55429803, 30442389, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement2625([ - 69421833, 26972132, 58859271, 20240912, 119664007, 29643940, 93968457, 34515112, - 110902491, 44996669, - ]), - y_minus_x: FieldElement2625([ - 3428668, 27807272, 41139948, 24786894, 4167808, 21423270, 52199622, 8021269, - 53172251, 18070808, - ]), - xy2d: FieldElement2625([ - 30631113, 26363656, 21279866, 23275794, 18311406, 466071, 42527968, 7989982, - 29641567, 29446694, - ]), - }, - ]); diff --git a/src/backend/serial/u32e/field/debug.rs b/src/backend/serial/u32e/field/debug.rs deleted file mode 100644 index bde1e1479..000000000 --- a/src/backend/serial/u32e/field/debug.rs +++ /dev/null @@ -1,104 +0,0 @@ -use utralib::generated::*; -pub struct Uart { - // pub base: *mut u32, -} - -impl Uart { - fn put_digit(&mut self, d: u8) { - let nyb = d & 0xF; - if nyb < 10 { - self.putc(nyb + 0x30); - } else { - self.putc(nyb + 0x61 - 10); - } - } - pub fn put_hex(&mut self, c: u8) { - self.put_digit(c >> 4); - self.put_digit(c & 0xF); - } - pub fn newline(&mut self) { - self.putc(0xa); - self.putc(0xd); - } - pub fn print_hex_word(&mut self, word: u32) { - for &byte in word.to_be_bytes().iter() { - self.put_hex(byte); - } - } - - pub fn putc(&self, c: u8) { - let base = utra::uart::HW_UART_BASE as *mut u32; - let mut uart = CSR::new(base); - // Wait until TXFULL is `0` - while uart.r(utra::uart::TXFULL) != 0 {} - uart.wo(utra::uart::RXTX, c as u32) - } - - pub fn getc(&self) -> Option { - let base = utra::uart::HW_UART_BASE as *mut u32; - let mut uart = CSR::new(base); - match uart.rf(utra::uart::EV_PENDING_RX) { - 0 => None, - ack => { - let c = Some(uart.rf(utra::uart::RXTX_RXTX) as u8); - uart.wfo(utra::uart::EV_PENDING_RX, ack); - c - } - } - } - - pub fn tiny_write_str(&mut self, s: &str) { - for c in s.bytes() { - self.putc(c); - } - } - -} - -use core::fmt::{Error, Write}; -impl Write for Uart { - fn write_str(&mut self, s: &str) -> Result<(), Error> { - for c in s.bytes() { - self.putc(c); - } - Ok(()) - } -} - -#[macro_use] -pub mod debug_print_hardware { - #[macro_export] - macro_rules! print - { - ($($args:tt)+) => ({ - use core::fmt::Write; - let _ = write!(debug::Uart {}, $($args)+); - }); - } -} - -#[macro_use] -#[cfg(test)] -mod debug_print_hardware { - #[macro_export] - #[allow(unused_variables)] - macro_rules! print { - ($($args:tt)+) => ({ - std::print!($($args)+) - }); - } -} - -#[macro_export] -macro_rules! println -{ - () => ({ - $crate::print!("\r\n") - }); - ($fmt:expr) => ({ - $crate::print!(concat!($fmt, "\r\n")) - }); - ($fmt:expr, $($args:tt)+) => ({ - $crate::print!(concat!($fmt, "\r\n"), $($args)+) - }); -} diff --git a/src/backend/serial/u32e/mod.rs b/src/backend/serial/u32e/mod.rs deleted file mode 100644 index 401ce74b4..000000000 --- a/src/backend/serial/u32e/mod.rs +++ /dev/null @@ -1,22 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! The `u32` backend uses `u32`s and a `(u32, u32) -> u64` multiplier. -//! -//! This code is intended to be portable, but it requires that -//! multiplication of two \\(32\\)-bit values to a \\(64\\)-bit result -//! is constant-time on the target platform. - -pub mod field; - -pub mod scalar; - -pub mod constants; diff --git a/src/backend/serial/u64/constants.rs b/src/backend/serial/u64/constants.rs deleted file mode 100644 index 6cbc0b50c..000000000 --- a/src/backend/serial/u64/constants.rs +++ /dev/null @@ -1,7759 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! This module contains backend-specific constant values, such as the 64-bit limbs of curve constants. - -use backend::serial::curve_models::AffineNielsPoint; -use super::field::FieldElement51; -use super::scalar::Scalar52; -use edwards::{EdwardsBasepointTable, EdwardsPoint}; -use window::{LookupTable, NafLookupTable8}; - -/// The value of minus one, equal to `-&FieldElement::one()` -pub(crate) const MINUS_ONE: FieldElement51 = FieldElement51([ - 2251799813685228, - 2251799813685247, - 2251799813685247, - 2251799813685247, - 2251799813685247 -]); - -/// Edwards `d` value, equal to `-121665/121666 mod p`. -pub(crate) const EDWARDS_D: FieldElement51 = FieldElement51([ - 929955233495203, - 466365720129213, - 1662059464998953, - 2033849074728123, - 1442794654840575, -]); - -/// Edwards `2*d` value, equal to `2*(-121665/121666) mod p`. -pub(crate) const EDWARDS_D2: FieldElement51 = FieldElement51([ - 1859910466990425, - 932731440258426, - 1072319116312658, - 1815898335770999, - 633789495995903, -]); - -/// One minus edwards `d` value squared, equal to `(1 - (-121665/121666) mod p) pow 2` -pub(crate) const ONE_MINUS_EDWARDS_D_SQUARED: FieldElement51 = FieldElement51([ - 1136626929484150, - 1998550399581263, - 496427632559748, - 118527312129759, - 45110755273534 -]); - -/// Edwards `d` value minus one squared, equal to `(((-121665/121666) mod p) - 1) pow 2` -pub(crate) const EDWARDS_D_MINUS_ONE_SQUARED: FieldElement51 = FieldElement51([ - 1507062230895904, - 1572317787530805, - 683053064812840, - 317374165784489, - 1572899562415810 -]); - -/// `= sqrt(a*d - 1)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. -pub(crate) const SQRT_AD_MINUS_ONE: FieldElement51 = FieldElement51([ - 2241493124984347, - 425987919032274, - 2207028919301688, - 1220490630685848, - 974799131293748, -]); - -/// `= 1/sqrt(a-d)`, where `a = -1 (mod p)`, `d` are the Edwards curve parameters. -pub(crate) const INVSQRT_A_MINUS_D: FieldElement51 = FieldElement51([ - 278908739862762, - 821645201101625, - 8113234426968, - 1777959178193151, - 2118520810568447, -]); - -/// Precomputed value of one of the square roots of -1 (mod p) -pub(crate) const SQRT_M1: FieldElement51 = FieldElement51([ - 1718705420411056, - 234908883556509, - 2233514472574048, - 2117202627021982, - 765476049583133, -]); - -/// `APLUS2_OVER_FOUR` is (A+2)/4. (This is used internally within the Montgomery ladder.) -pub(crate) const APLUS2_OVER_FOUR: FieldElement51 = FieldElement51([121666, 0, 0, 0, 0]); - -/// `MONTGOMERY_A` is equal to 486662, which is a constant of the curve equation -/// for Curve25519 in its Montgomery form. (This is used internally within the -/// Elligator map.) -pub(crate) const MONTGOMERY_A: FieldElement51 = FieldElement51([486662, 0, 0, 0, 0]); - -/// `MONTGOMERY_A_NEG` is equal to -486662. (This is used internally within the -/// Elligator map.) -pub(crate) const MONTGOMERY_A_NEG: FieldElement51 = FieldElement51([ - 2251799813198567, - 2251799813685247, - 2251799813685247, - 2251799813685247, - 2251799813685247, -]); - -/// `L` is the order of base point, i.e. 2^252 + 27742317777372353535851937790883648493 -pub(crate) const L: Scalar52 = Scalar52([ - 0x0002631a5cf5d3ed, - 0x000dea2f79cd6581, - 0x000000000014def9, - 0x0000000000000000, - 0x0000100000000000, -]); - -/// `L` * `LFACTOR` = -1 (mod 2^52) -pub(crate) const LFACTOR: u64 = 0x51da312547e1b; - -/// `R` = R % L where R = 2^260 -pub(crate) const R: Scalar52 = Scalar52([ - 0x000f48bd6721e6ed, - 0x0003bab5ac67e45a, - 0x000fffffeb35e51b, - 0x000fffffffffffff, - 0x00000fffffffffff, -]); - -/// `RR` = (R^2) % L where R = 2^260 -pub(crate) const RR: Scalar52 = Scalar52([ - 0x0009d265e952d13b, - 0x000d63c715bea69f, - 0x0005be65cb687604, - 0x0003dceec73d217f, - 0x000009411b7c309a, -]); - -/// The Ed25519 basepoint, as an `EdwardsPoint`. -/// -/// This is called `_POINT` to distinguish it from -/// `ED25519_BASEPOINT_TABLE`, which should be used for scalar -/// multiplication (it's much faster). -pub const ED25519_BASEPOINT_POINT: EdwardsPoint = EdwardsPoint { - X: FieldElement51([ - 1738742601995546, - 1146398526822698, - 2070867633025821, - 562264141797630, - 587772402128613, - ]), - Y: FieldElement51([ - 1801439850948184, - 1351079888211148, - 450359962737049, - 900719925474099, - 1801439850948198, - ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ - 1841354044333475, - 16398895984059, - 755974180946558, - 900171276175154, - 1821297809914039, - ]), -}; - -/// The 8-torsion subgroup \\(\mathcal E [8]\\). -/// -/// In the case of Curve25519, it is cyclic; the \\(i\\)-th element of -/// the array is \\([i]P\\), where \\(P\\) is a point of order \\(8\\) -/// generating \\(\mathcal E[8]\\). -/// -/// Thus \\(\mathcal E[4]\\) is the points indexed by `0,2,4,6`, and -/// \\(\mathcal E[2]\\) is the points indexed by `0,4`. -pub const EIGHT_TORSION: [EdwardsPoint; 8] = EIGHT_TORSION_INNER_DOC_HIDDEN; - -/// Inner item used to hide limb constants from cargo doc output. -#[doc(hidden)] -pub const EIGHT_TORSION_INNER_DOC_HIDDEN: [EdwardsPoint; 8] = [ - EdwardsPoint { - X: FieldElement51([0, 0, 0, 0, 0]), - Y: FieldElement51([1, 0, 0, 0, 0]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([0, 0, 0, 0, 0]), - }, - EdwardsPoint { - X: FieldElement51([ - 358744748052810, - 1691584618240980, - 977650209285361, - 1429865912637724, - 560044844278676, - ]), - Y: FieldElement51([ - 84926274344903, - 473620666599931, - 365590438845504, - 1028470286882429, - 2146499180330972, - ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ - 1448326834587521, - 1857896831960481, - 1093722731865333, - 1677408490711241, - 1915505153018406, - ]), - }, - EdwardsPoint { - X: FieldElement51([ - 533094393274173, - 2016890930128738, - 18285341111199, - 134597186663265, - 1486323764102114, - ]), - Y: FieldElement51([0, 0, 0, 0, 0]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([0, 0, 0, 0, 0]), - }, - EdwardsPoint { - X: FieldElement51([ - 358744748052810, - 1691584618240980, - 977650209285361, - 1429865912637724, - 560044844278676, - ]), - Y: FieldElement51([ - 2166873539340326, - 1778179147085316, - 1886209374839743, - 1223329526802818, - 105300633354275, - ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ - 803472979097708, - 393902981724766, - 1158077081819914, - 574391322974006, - 336294660666841, - ]), - }, - EdwardsPoint { - X: FieldElement51([0, 0, 0, 0, 0]), - Y: FieldElement51([ - 2251799813685228, - 2251799813685247, - 2251799813685247, - 2251799813685247, - 2251799813685247, - ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([0, 0, 0, 0, 0]), - }, - EdwardsPoint { - X: FieldElement51([ - 1893055065632419, - 560215195444267, - 1274149604399886, - 821933901047523, - 1691754969406571, - ]), - Y: FieldElement51([ - 2166873539340326, - 1778179147085316, - 1886209374839743, - 1223329526802818, - 105300633354275, - ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ - 1448326834587521, - 1857896831960481, - 1093722731865333, - 1677408490711241, - 1915505153018406, - ]), - }, - EdwardsPoint { - X: FieldElement51([ - 1718705420411056, - 234908883556509, - 2233514472574048, - 2117202627021982, - 765476049583133, - ]), - Y: FieldElement51([0, 0, 0, 0, 0]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([0, 0, 0, 0, 0]), - }, - EdwardsPoint { - X: FieldElement51([ - 1893055065632419, - 560215195444267, - 1274149604399886, - 821933901047523, - 1691754969406571, - ]), - Y: FieldElement51([ - 84926274344903, - 473620666599931, - 365590438845504, - 1028470286882429, - 2146499180330972, - ]), - Z: FieldElement51([1, 0, 0, 0, 0]), - T: FieldElement51([ - 803472979097708, - 393902981724766, - 1158077081819914, - 574391322974006, - 336294660666841, - ]), - }, -]; - -/// Table containing precomputed multiples of the Ed25519 basepoint \\(B = (x, 4/5)\\). -pub const ED25519_BASEPOINT_TABLE: EdwardsBasepointTable = ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN; - -/// Inner constant, used to avoid filling the docs with precomputed points. -#[doc(hidden)] -pub const ED25519_BASEPOINT_TABLE_INNER_DOC_HIDDEN: EdwardsBasepointTable = - EdwardsBasepointTable([ - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3540182452943730, - 2497478415033846, - 2521227595762870, - 1462984067271729, - 2389212253076811, - ]), - y_minus_x: FieldElement51([ - 62697248952638, - 204681361388450, - 631292143396476, - 338455783676468, - 1213667448819585, - ]), - xy2d: FieldElement51([ - 301289933810280, - 1259582250014073, - 1422107436869536, - 796239922652654, - 1953934009299142, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3632771708514775, - 790832306631235, - 2067202295274102, - 1995808275510000, - 1566530869037010, - ]), - y_minus_x: FieldElement51([ - 463307831301544, - 432984605774163, - 1610641361907204, - 750899048855000, - 1894842303421586, - ]), - xy2d: FieldElement51([ - 748439484463711, - 1033211726465151, - 1396005112841647, - 1611506220286469, - 1972177495910992, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1601611775252272, - 1720807796594148, - 1132070835939856, - 3512254832574799, - 2147779492816910, - ]), - y_minus_x: FieldElement51([ - 316559037616741, - 2177824224946892, - 1459442586438991, - 1461528397712656, - 751590696113597, - ]), - xy2d: FieldElement51([ - 1850748884277385, - 1200145853858453, - 1068094770532492, - 672251375690438, - 1586055907191707, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 934282339813791, - 1846903124198670, - 1172395437954843, - 1007037127761661, - 1830588347719256, - ]), - y_minus_x: FieldElement51([ - 1694390458783935, - 1735906047636159, - 705069562067493, - 648033061693059, - 696214010414170, - ]), - xy2d: FieldElement51([ - 1121406372216585, - 192876649532226, - 190294192191717, - 1994165897297032, - 2245000007398739, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 769950342298400, - 2384754244604994, - 3095885746880802, - 3225892188161580, - 2977876099231263, - ]), - y_minus_x: FieldElement51([ - 425251763115706, - 608463272472562, - 442562545713235, - 837766094556764, - 374555092627893, - ]), - xy2d: FieldElement51([ - 1086255230780037, - 274979815921559, - 1960002765731872, - 929474102396301, - 1190409889297339, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1388594989461809, - 316767091099457, - 2646098655878230, - 1230079486801004, - 1440737038838979, - ]), - y_minus_x: FieldElement51([ - 7380825640100, - 146210432690483, - 304903576448906, - 1198869323871120, - 997689833219095, - ]), - xy2d: FieldElement51([ - 1181317918772081, - 114573476638901, - 262805072233344, - 265712217171332, - 294181933805782, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2916800678241215, - 2065379846933858, - 2622030924071124, - 2602788184473875, - 1233371373142984, - ]), - y_minus_x: FieldElement51([ - 2019367628972465, - 676711900706637, - 110710997811333, - 1108646842542025, - 517791959672113, - ]), - xy2d: FieldElement51([ - 965130719900578, - 247011430587952, - 526356006571389, - 91986625355052, - 2157223321444601, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 4320419353804412, - 4218074731744053, - 957728544705548, - 729906502578991, - 2411634706750414, - ]), - y_minus_x: FieldElement51([ - 2073601412052185, - 31021124762708, - 264500969797082, - 248034690651703, - 1030252227928288, - ]), - xy2d: FieldElement51([ - 551790716293402, - 1989538725166328, - 801169423371717, - 2052451893578887, - 678432056995012, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1368953770187805, - 3042147450398169, - 2689308289352409, - 2142576377050579, - 1932081720066286, - ]), - y_minus_x: FieldElement51([ - 953638594433374, - 1092333936795051, - 1419774766716690, - 805677984380077, - 859228993502513, - ]), - xy2d: FieldElement51([ - 1200766035879111, - 20142053207432, - 1465634435977050, - 1645256912097844, - 295121984874596, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1735718747031538, - 1248237894295956, - 1204753118328107, - 976066523550493, - 2317743583219840, - ]), - y_minus_x: FieldElement51([ - 1060098822528990, - 1586825862073490, - 212301317240126, - 1975302711403555, - 666724059764335, - ]), - xy2d: FieldElement51([ - 1091990273418756, - 1572899409348578, - 80968014455247, - 306009358661350, - 1520450739132526, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3732317023121341, - 1511153322193951, - 3496143672676420, - 2556587964178488, - 2620936670181690, - ]), - y_minus_x: FieldElement51([ - 2151330273626164, - 762045184746182, - 1688074332551515, - 823046109005759, - 907602769079491, - ]), - xy2d: FieldElement51([ - 2047386910586836, - 168470092900250, - 1552838872594810, - 340951180073789, - 360819374702533, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1982622644432037, - 2014393600336956, - 2380709022489462, - 3869592437614438, - 2357094095599062, - ]), - y_minus_x: FieldElement51([ - 980234343912898, - 1712256739246056, - 588935272190264, - 204298813091998, - 841798321043288, - ]), - xy2d: FieldElement51([ - 197561292938973, - 454817274782871, - 1963754960082318, - 2113372252160468, - 971377527342673, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2416499262514576, - 2254927265442919, - 3451304785234000, - 1766155447043651, - 1899238924683527, - ]), - y_minus_x: FieldElement51([ - 732262946680281, - 1674412764227063, - 2182456405662809, - 1350894754474250, - 558458873295247, - ]), - xy2d: FieldElement51([ - 2103305098582922, - 1960809151316468, - 715134605001343, - 1454892949167181, - 40827143824949, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1239289043050193, - 1744654158124578, - 758702410031698, - 4048562808759936, - 2253402870349013, - ]), - y_minus_x: FieldElement51([ - 2232056027107988, - 987343914584615, - 2115594492994461, - 1819598072792159, - 1119305654014850, - ]), - xy2d: FieldElement51([ - 320153677847348, - 939613871605645, - 641883205761567, - 1930009789398224, - 329165806634126, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3232730304159378, - 1242488692177892, - 1251446316964684, - 1086618677993530, - 1961430968465772, - ]), - y_minus_x: FieldElement51([ - 276821765317453, - 1536835591188030, - 1305212741412361, - 61473904210175, - 2051377036983058, - ]), - xy2d: FieldElement51([ - 833449923882501, - 1750270368490475, - 1123347002068295, - 185477424765687, - 278090826653186, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 794524995833413, - 1849907304548286, - 2305148486158393, - 1272368559505216, - 1147304168324779, - ]), - y_minus_x: FieldElement51([ - 1504846112759364, - 1203096289004681, - 562139421471418, - 274333017451844, - 1284344053775441, - ]), - xy2d: FieldElement51([ - 483048732424432, - 2116063063343382, - 30120189902313, - 292451576741007, - 1156379271702225, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3180171966714267, - 2147692869914563, - 1455665844462196, - 1986737809425946, - 2437006863943337, - ]), - y_minus_x: FieldElement51([ - 137732961814206, - 706670923917341, - 1387038086865771, - 1965643813686352, - 1384777115696347, - ]), - xy2d: FieldElement51([ - 481144981981577, - 2053319313589856, - 2065402289827512, - 617954271490316, - 1106602634668125, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2948097833334040, - 3145099472726142, - 1148636718636008, - 2278533891034865, - 2203955659340680, - ]), - y_minus_x: FieldElement51([ - 657390353372855, - 998499966885562, - 991893336905797, - 810470207106761, - 343139804608786, - ]), - xy2d: FieldElement51([ - 791736669492960, - 934767652997115, - 824656780392914, - 1759463253018643, - 361530362383518, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2022541353055578, - 4346500076272714, - 3802807888710933, - 2494585331103411, - 2947785218648809, - ]), - y_minus_x: FieldElement51([ - 1287487199965223, - 2215311941380308, - 1552928390931986, - 1664859529680196, - 1125004975265243, - ]), - xy2d: FieldElement51([ - 677434665154918, - 989582503122485, - 1817429540898386, - 1052904935475344, - 1143826298169798, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2619066141993637, - 2570231002607651, - 2947429167440602, - 2885885471266079, - 2276381426249673, - ]), - y_minus_x: FieldElement51([ - 773360688841258, - 1815381330538070, - 363773437667376, - 539629987070205, - 783280434248437, - ]), - xy2d: FieldElement51([ - 180820816194166, - 168937968377394, - 748416242794470, - 1227281252254508, - 1567587861004268, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2730575372268893, - 2062896624554806, - 2951191072970647, - 2609899222113120, - 1277310261461760, - ]), - y_minus_x: FieldElement51([ - 1984740906540026, - 1079164179400229, - 1056021349262661, - 1659958556483663, - 1088529069025527, - ]), - xy2d: FieldElement51([ - 580736401511151, - 1842931091388998, - 1177201471228238, - 2075460256527244, - 1301133425678027, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1515728832059163, - 1575261009617579, - 1510246567196186, - 2442877836294952, - 2368461529974388, - ]), - y_minus_x: FieldElement51([ - 1295295738269652, - 1714742313707026, - 545583042462581, - 2034411676262552, - 1513248090013606, - ]), - xy2d: FieldElement51([ - 230710545179830, - 30821514358353, - 760704303452229, - 390668103790604, - 573437871383156, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3421179921230875, - 2514967047430861, - 4274701112739695, - 3071700566936367, - 4275698278559832, - ]), - y_minus_x: FieldElement51([ - 2102254323485823, - 1570832666216754, - 34696906544624, - 1993213739807337, - 70638552271463, - ]), - xy2d: FieldElement51([ - 894132856735058, - 548675863558441, - 845349339503395, - 1942269668326667, - 1615682209874691, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3539470031223082, - 1222355136884919, - 1846481788678694, - 1150426571265110, - 1613523400722047, - ]), - y_minus_x: FieldElement51([ - 793388516527298, - 1315457083650035, - 1972286999342417, - 1901825953052455, - 338269477222410, - ]), - xy2d: FieldElement51([ - 550201530671806, - 778605267108140, - 2063911101902983, - 115500557286349, - 2041641272971022, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 717255318455100, - 519313764361315, - 2080406977303708, - 541981206705521, - 774328150311600, - ]), - y_minus_x: FieldElement51([ - 261715221532238, - 1795354330069993, - 1496878026850283, - 499739720521052, - 389031152673770, - ]), - xy2d: FieldElement51([ - 1997217696294013, - 1717306351628065, - 1684313917746180, - 1644426076011410, - 1857378133465451, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3727234538477877, - 2328731709971226, - 3368528843456914, - 2002544139318041, - 2977347647489186, - ]), - y_minus_x: FieldElement51([ - 2022306639183567, - 726296063571875, - 315345054448644, - 1058733329149221, - 1448201136060677, - ]), - xy2d: FieldElement51([ - 1710065158525665, - 1895094923036397, - 123988286168546, - 1145519900776355, - 1607510767693874, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2813405189107769, - 1071733543815036, - 2383296312486238, - 1946868434569998, - 3079937947649451, - ]), - y_minus_x: FieldElement51([ - 1548495173745801, - 442310529226540, - 998072547000384, - 553054358385281, - 644824326376171, - ]), - xy2d: FieldElement51([ - 1445526537029440, - 2225519789662536, - 914628859347385, - 1064754194555068, - 1660295614401091, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3451490036797185, - 2275827949507588, - 2318438102929588, - 2309425969971222, - 2816893781664854, - ]), - y_minus_x: FieldElement51([ - 876926774220824, - 554618976488214, - 1012056309841565, - 839961821554611, - 1414499340307677, - ]), - xy2d: FieldElement51([ - 703047626104145, - 1266841406201770, - 165556500219173, - 486991595001879, - 1011325891650656, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1622861044480487, - 1156394801573634, - 4120932379100752, - 2578903799462977, - 2095342781472283, - ]), - y_minus_x: FieldElement51([ - 334886927423922, - 489511099221528, - 129160865966726, - 1720809113143481, - 619700195649254, - ]), - xy2d: FieldElement51([ - 1646545795166119, - 1758370782583567, - 714746174550637, - 1472693650165135, - 898994790308209, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2585203586724508, - 2547572356138185, - 1693106465353609, - 912330357530760, - 2723035471635610, - ]), - y_minus_x: FieldElement51([ - 1811196219982022, - 1068969825533602, - 289602974833439, - 1988956043611592, - 863562343398367, - ]), - xy2d: FieldElement51([ - 906282429780072, - 2108672665779781, - 432396390473936, - 150625823801893, - 1708930497638539, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 925664675702309, - 2273216662253932, - 4083236455546587, - 601157008940112, - 2623617868729744, - ]), - y_minus_x: FieldElement51([ - 1479786007267725, - 1738881859066675, - 68646196476567, - 2146507056100328, - 1247662817535471, - ]), - xy2d: FieldElement51([ - 52035296774456, - 939969390708103, - 312023458773250, - 59873523517659, - 1231345905848899, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2895154920100990, - 2541986621181021, - 2013561737429022, - 2571447883196794, - 2645536492181409, - ]), - y_minus_x: FieldElement51([ - 129358342392716, - 1932811617704777, - 1176749390799681, - 398040349861790, - 1170779668090425, - ]), - xy2d: FieldElement51([ - 2051980782668029, - 121859921510665, - 2048329875753063, - 1235229850149665, - 519062146124755, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3859970785658325, - 2667608874045675, - 1350468408164765, - 2038620059057678, - 3278704299674360, - ]), - y_minus_x: FieldElement51([ - 1837656083115103, - 1510134048812070, - 906263674192061, - 1821064197805734, - 565375124676301, - ]), - xy2d: FieldElement51([ - 578027192365650, - 2034800251375322, - 2128954087207123, - 478816193810521, - 2196171989962750, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1633188840273120, - 3104586986058956, - 1548762607215795, - 1266275218902681, - 3359018017010381, - ]), - y_minus_x: FieldElement51([ - 462189358480054, - 1784816734159228, - 1611334301651368, - 1303938263943540, - 707589560319424, - ]), - xy2d: FieldElement51([ - 1038829280972848, - 38176604650029, - 753193246598573, - 1136076426528122, - 595709990562434, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3660251634545082, - 2194984964010832, - 2198361797561729, - 1061962440055713, - 1645147963442934, - ]), - y_minus_x: FieldElement51([ - 4701053362120, - 1647641066302348, - 1047553002242085, - 1923635013395977, - 206970314902065, - ]), - xy2d: FieldElement51([ - 1750479161778571, - 1362553355169293, - 1891721260220598, - 966109370862782, - 1024913988299801, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2464498862816952, - 1117950018299774, - 1873945661751056, - 3655602735669306, - 2382695896337945, - ]), - y_minus_x: FieldElement51([ - 636808533673210, - 1262201711667560, - 390951380330599, - 1663420692697294, - 561951321757406, - ]), - xy2d: FieldElement51([ - 520731594438141, - 1446301499955692, - 273753264629267, - 1565101517999256, - 1019411827004672, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3178327305714638, - 3443653291096626, - 734233225181170, - 2435838701226518, - 4042225960010590, - ]), - y_minus_x: FieldElement51([ - 1464651961852572, - 1483737295721717, - 1519450561335517, - 1161429831763785, - 405914998179977, - ]), - xy2d: FieldElement51([ - 996126634382301, - 796204125879525, - 127517800546509, - 344155944689303, - 615279846169038, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2990523894660505, - 2188666632415295, - 1961313708559162, - 1506545807547587, - 3403101452654988, - ]), - y_minus_x: FieldElement51([ - 622917337413835, - 1218989177089035, - 1284857712846592, - 970502061709359, - 351025208117090, - ]), - xy2d: FieldElement51([ - 2067814584765580, - 1677855129927492, - 2086109782475197, - 235286517313238, - 1416314046739645, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2838644076315587, - 2559244195637442, - 458399356043425, - 2853867838192310, - 3280348017100490, - ]), - y_minus_x: FieldElement51([ - 678489922928203, - 2016657584724032, - 90977383049628, - 1026831907234582, - 615271492942522, - ]), - xy2d: FieldElement51([ - 301225714012278, - 1094837270268560, - 1202288391010439, - 644352775178361, - 1647055902137983, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1210746697896459, - 1416608304244708, - 2938287290903104, - 3496931005119382, - 3303038150540984, - ]), - y_minus_x: FieldElement51([ - 1135604073198207, - 1683322080485474, - 769147804376683, - 2086688130589414, - 900445683120379, - ]), - xy2d: FieldElement51([ - 1971518477615628, - 401909519527336, - 448627091057375, - 1409486868273821, - 1214789035034363, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1364039144731711, - 1897497433586190, - 2203097701135459, - 2397261210496499, - 1349844460790698, - ]), - y_minus_x: FieldElement51([ - 1045230323257973, - 818206601145807, - 630513189076103, - 1672046528998132, - 807204017562437, - ]), - xy2d: FieldElement51([ - 439961968385997, - 386362664488986, - 1382706320807688, - 309894000125359, - 2207801346498567, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3480804500082836, - 3172443782216110, - 2375775707596425, - 2933223806901024, - 1400559197080972, - ]), - y_minus_x: FieldElement51([ - 2003766096898049, - 170074059235165, - 1141124258967971, - 1485419893480973, - 1573762821028725, - ]), - xy2d: FieldElement51([ - 729905708611432, - 1270323270673202, - 123353058984288, - 426460209632942, - 2195574535456672, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1271140255321216, - 2044363183174497, - 2303925201319937, - 3696920060379952, - 3194341800024331, - ]), - y_minus_x: FieldElement51([ - 1761608437466135, - 583360847526804, - 1586706389685493, - 2157056599579261, - 1170692369685772, - ]), - xy2d: FieldElement51([ - 871476219910823, - 1878769545097794, - 2241832391238412, - 548957640601001, - 690047440233174, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2548994545820755, - 1366347803776819, - 3552985325930849, - 561849853336293, - 1533554921345731, - ]), - y_minus_x: FieldElement51([ - 999628998628371, - 1132836708493400, - 2084741674517453, - 469343353015612, - 678782988708035, - ]), - xy2d: FieldElement51([ - 2189427607417022, - 699801937082607, - 412764402319267, - 1478091893643349, - 2244675696854460, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3964091869651792, - 2456213404310121, - 3657538451018088, - 2660781114515010, - 3112882032961968, - ]), - y_minus_x: FieldElement51([ - 508561155940631, - 966928475686665, - 2236717801150132, - 424543858577297, - 2089272956986143, - ]), - xy2d: FieldElement51([ - 221245220129925, - 1156020201681217, - 491145634799213, - 542422431960839, - 828100817819207, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2405556784925632, - 1299874139923976, - 2644898978945750, - 1058234455773021, - 996989038681183, - ]), - y_minus_x: FieldElement51([ - 559086812798481, - 573177704212711, - 1629737083816402, - 1399819713462595, - 1646954378266038, - ]), - xy2d: FieldElement51([ - 1887963056288059, - 228507035730124, - 1468368348640282, - 930557653420194, - 613513962454686, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1224529808187534, - 1577022856702685, - 2206946542980843, - 625883007765001, - 2531730607197406, - ]), - y_minus_x: FieldElement51([ - 1076287717051609, - 1114455570543035, - 187297059715481, - 250446884292121, - 1885187512550540, - ]), - xy2d: FieldElement51([ - 902497362940219, - 76749815795675, - 1657927525633846, - 1420238379745202, - 1340321636548352, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1129576631190765, - 3533793823712575, - 996844254743017, - 2509676177174497, - 3402650555740265, - ]), - y_minus_x: FieldElement51([ - 628740660038789, - 1943038498527841, - 467786347793886, - 1093341428303375, - 235413859513003, - ]), - xy2d: FieldElement51([ - 237425418909360, - 469614029179605, - 1512389769174935, - 1241726368345357, - 441602891065214, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3988217766743784, - 726531315520507, - 1833335034432527, - 1629442561574747, - 2876218732971333, - ]), - y_minus_x: FieldElement51([ - 1960754663920689, - 497040957888962, - 1909832851283095, - 1271432136996826, - 2219780368020940, - ]), - xy2d: FieldElement51([ - 1537037379417136, - 1358865369268262, - 2130838645654099, - 828733687040705, - 1999987652890901, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 629042105241795, - 1098854999137608, - 887281544569320, - 3674901833560025, - 2259711072636808, - ]), - y_minus_x: FieldElement51([ - 1811562332665373, - 1501882019007673, - 2213763501088999, - 359573079719636, - 36370565049116, - ]), - xy2d: FieldElement51([ - 218907117361280, - 1209298913016966, - 1944312619096112, - 1130690631451061, - 1342327389191701, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1369976867854685, - 1396479602419169, - 4017456468084104, - 2203659200586298, - 3250127649802489, - ]), - y_minus_x: FieldElement51([ - 2230701885562825, - 1348173180338974, - 2172856128624598, - 1426538746123771, - 444193481326151, - ]), - xy2d: FieldElement51([ - 784210426627951, - 918204562375674, - 1284546780452985, - 1324534636134684, - 1872449409642708, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2571438643225542, - 2848082470493653, - 2037902696412607, - 1557219121643918, - 341938082688094, - ]), - y_minus_x: FieldElement51([ - 1901860206695915, - 2004489122065736, - 1625847061568236, - 973529743399879, - 2075287685312905, - ]), - xy2d: FieldElement51([ - 1371853944110545, - 1042332820512553, - 1949855697918254, - 1791195775521505, - 37487364849293, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 687200189577836, - 1082536651125675, - 2896024754556794, - 2592723009743198, - 2595381160432643, - ]), - y_minus_x: FieldElement51([ - 2082717129583892, - 27829425539422, - 145655066671970, - 1690527209845512, - 1865260509673478, - ]), - xy2d: FieldElement51([ - 1059729620568824, - 2163709103470266, - 1440302280256872, - 1769143160546397, - 869830310425069, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3861316033464273, - 777277757338816, - 2101121130363987, - 550762194946473, - 1905542338659364, - ]), - y_minus_x: FieldElement51([ - 2024821921041576, - 426948675450149, - 595133284085473, - 471860860885970, - 600321679413000, - ]), - xy2d: FieldElement51([ - 598474602406721, - 1468128276358244, - 1191923149557635, - 1501376424093216, - 1281662691293476, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1721138489890688, - 1264336102277790, - 2684864359106535, - 1359988423149465, - 3813671107094695, - ]), - y_minus_x: FieldElement51([ - 719520245587143, - 393380711632345, - 132350400863381, - 1543271270810729, - 1819543295798660, - ]), - xy2d: FieldElement51([ - 396397949784152, - 1811354474471839, - 1362679985304303, - 2117033964846756, - 498041172552279, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1812471844975748, - 1856491995543149, - 126579494584102, - 3288044672967868, - 1975108050082549, - ]), - y_minus_x: FieldElement51([ - 650623932407995, - 1137551288410575, - 2125223403615539, - 1725658013221271, - 2134892965117796, - ]), - xy2d: FieldElement51([ - 522584000310195, - 1241762481390450, - 1743702789495384, - 2227404127826575, - 1686746002148897, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 427904865186293, - 1703211129693455, - 1585368107547509, - 3688784302429584, - 3012988348299225, - ]), - y_minus_x: FieldElement51([ - 318101947455002, - 248138407995851, - 1481904195303927, - 309278454311197, - 1258516760217879, - ]), - xy2d: FieldElement51([ - 1275068538599310, - 513726919533379, - 349926553492294, - 688428871968420, - 1702400196000666, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3313663849950481, - 3213411074010628, - 2573659446386085, - 3297400443644764, - 1985130202504037, - ]), - y_minus_x: FieldElement51([ - 1558816436882417, - 1962896332636523, - 1337709822062152, - 1501413830776938, - 294436165831932, - ]), - xy2d: FieldElement51([ - 818359826554971, - 1862173000996177, - 626821592884859, - 573655738872376, - 1749691246745455, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1988022651432119, - 3333911312271288, - 1834020786104820, - 3706626690108935, - 692929915223121, - ]), - y_minus_x: FieldElement51([ - 2146513703733331, - 584788900394667, - 464965657279958, - 2183973639356127, - 238371159456790, - ]), - xy2d: FieldElement51([ - 1129007025494441, - 2197883144413266, - 265142755578169, - 971864464758890, - 1983715884903702, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1291366624493056, - 2633256531874362, - 1711482489312443, - 1815233647702022, - 3144079596677715, - ]), - y_minus_x: FieldElement51([ - 444548969917454, - 1452286453853356, - 2113731441506810, - 645188273895859, - 810317625309512, - ]), - xy2d: FieldElement51([ - 2242724082797924, - 1373354730327868, - 1006520110883049, - 2147330369940688, - 1151816104883620, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3997520014069025, - 4163522956860564, - 2056329390702073, - 2607026987995097, - 3131032608056347, - ]), - y_minus_x: FieldElement51([ - 163723479936298, - 115424889803150, - 1156016391581227, - 1894942220753364, - 1970549419986329, - ]), - xy2d: FieldElement51([ - 681981452362484, - 267208874112496, - 1374683991933094, - 638600984916117, - 646178654558546, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2265178468539480, - 2358037120714814, - 1944412051589650, - 4093776581610705, - 2482502633520820, - ]), - y_minus_x: FieldElement51([ - 260683893467075, - 854060306077237, - 913639551980112, - 4704576840123, - 280254810808712, - ]), - xy2d: FieldElement51([ - 715374893080287, - 1173334812210491, - 1806524662079626, - 1894596008000979, - 398905715033393, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2751826223412909, - 3848231101880618, - 1420380351989369, - 3237011375206737, - 392444930785632, - ]), - y_minus_x: FieldElement51([ - 2096421546958141, - 1922523000950363, - 789831022876840, - 427295144688779, - 320923973161730, - ]), - xy2d: FieldElement51([ - 1927770723575450, - 1485792977512719, - 1850996108474547, - 551696031508956, - 2126047405475647, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2112099158080129, - 2994370617594963, - 2258284371762679, - 1951119898618915, - 2344890196388664, - ]), - y_minus_x: FieldElement51([ - 383905201636970, - 859946997631870, - 855623867637644, - 1017125780577795, - 794250831877809, - ]), - xy2d: FieldElement51([ - 77571826285752, - 999304298101753, - 487841111777762, - 1038031143212339, - 339066367948762, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2926794589205781, - 2517835660016036, - 826951213393477, - 1405007746162285, - 1781791018620876, - ]), - y_minus_x: FieldElement51([ - 1001412661522686, - 348196197067298, - 1666614366723946, - 888424995032760, - 580747687801357, - ]), - xy2d: FieldElement51([ - 1939560076207777, - 1409892634407635, - 552574736069277, - 383854338280405, - 190706709864139, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2177087163428741, - 1439255351721944, - 3459870654068041, - 2230616362004768, - 1396886392021913, - ]), - y_minus_x: FieldElement51([ - 676962063230039, - 1880275537148808, - 2046721011602706, - 888463247083003, - 1318301552024067, - ]), - xy2d: FieldElement51([ - 1466980508178206, - 617045217998949, - 652303580573628, - 757303753529064, - 207583137376902, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3762856566592150, - 2357202940576524, - 2745234706458093, - 1091943425335975, - 1802717338077427, - ]), - y_minus_x: FieldElement51([ - 1853982405405128, - 1878664056251147, - 1528011020803992, - 1019626468153565, - 1128438412189035, - ]), - xy2d: FieldElement51([ - 1963939888391106, - 293456433791664, - 697897559513649, - 985882796904380, - 796244541237972, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2668570812315008, - 2641455366112301, - 1314476859406755, - 1749382513022778, - 3413705412424739, - ]), - y_minus_x: FieldElement51([ - 1428358296490651, - 1027115282420478, - 304840698058337, - 441410174026628, - 1819358356278573, - ]), - xy2d: FieldElement51([ - 204943430200135, - 1554861433819175, - 216426658514651, - 264149070665950, - 2047097371738319, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1934415182909015, - 1393285083565062, - 2768209145458208, - 3409490548679139, - 2372839480279515, - ]), - y_minus_x: FieldElement51([ - 662035583584445, - 286736105093098, - 1131773000510616, - 818494214211439, - 472943792054479, - ]), - xy2d: FieldElement51([ - 665784778135882, - 1893179629898606, - 808313193813106, - 276797254706413, - 1563426179676396, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 945205108984213, - 2778077376644543, - 1324180513733565, - 1666970227868664, - 2405347422974421, - ]), - y_minus_x: FieldElement51([ - 2031433403516252, - 203996615228162, - 170487168837083, - 981513604791390, - 843573964916831, - ]), - xy2d: FieldElement51([ - 1476570093962618, - 838514669399805, - 1857930577281364, - 2017007352225784, - 317085545220047, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1461557121912823, - 1600674043318359, - 2157134900399597, - 1670641601940616, - 2379565397488531, - ]), - y_minus_x: FieldElement51([ - 1293543509393474, - 2143624609202546, - 1058361566797508, - 214097127393994, - 946888515472729, - ]), - xy2d: FieldElement51([ - 357067959932916, - 1290876214345711, - 521245575443703, - 1494975468601005, - 800942377643885, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2817916472785262, - 820247422481739, - 994464017954148, - 2578957425371613, - 2344391131796991, - ]), - y_minus_x: FieldElement51([ - 617256647603209, - 1652107761099439, - 1857213046645471, - 1085597175214970, - 817432759830522, - ]), - xy2d: FieldElement51([ - 771808161440705, - 1323510426395069, - 680497615846440, - 851580615547985, - 1320806384849017, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1219260086131896, - 2898968820282063, - 2331400938444953, - 2161724213426747, - 2656661710745446, - ]), - y_minus_x: FieldElement51([ - 1327968293887866, - 1335500852943256, - 1401587164534264, - 558137311952440, - 1551360549268902, - ]), - xy2d: FieldElement51([ - 417621685193956, - 1429953819744454, - 396157358457099, - 1940470778873255, - 214000046234152, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1268047918491954, - 2172375426948536, - 1533916099229249, - 1761293575457130, - 3842422480712013, - ]), - y_minus_x: FieldElement51([ - 1627072914981959, - 2211603081280073, - 1912369601616504, - 1191770436221309, - 2187309757525860, - ]), - xy2d: FieldElement51([ - 1149147819689533, - 378692712667677, - 828475842424202, - 2218619146419342, - 70688125792186, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3551539230764990, - 3690416477138006, - 3788528892189659, - 2053896748919837, - 3260220846276494, - ]), - y_minus_x: FieldElement51([ - 2040723824657366, - 399555637875075, - 632543375452995, - 872649937008051, - 1235394727030233, - ]), - xy2d: FieldElement51([ - 2211311599327900, - 2139787259888175, - 938706616835350, - 12609661139114, - 2081897930719789, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1324994503390431, - 2588782144267879, - 1183998925654176, - 3343454479598522, - 2300527487656566, - ]), - y_minus_x: FieldElement51([ - 1845522914617879, - 1222198248335542, - 150841072760134, - 1927029069940982, - 1189913404498011, - ]), - xy2d: FieldElement51([ - 1079559557592645, - 2215338383666441, - 1903569501302605, - 49033973033940, - 305703433934152, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2346453219102138, - 3637921163538246, - 3313930291577009, - 2288353761164521, - 3085469462634093, - ]), - y_minus_x: FieldElement51([ - 1432015813136298, - 440364795295369, - 1395647062821501, - 1976874522764578, - 934452372723352, - ]), - xy2d: FieldElement51([ - 1296625309219774, - 2068273464883862, - 1858621048097805, - 1492281814208508, - 2235868981918946, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1490330266465551, - 1858795661361448, - 3688040948655011, - 2546373032584894, - 3459939824714180, - ]), - y_minus_x: FieldElement51([ - 1282462923712748, - 741885683986255, - 2027754642827561, - 518989529541027, - 1826610009555945, - ]), - xy2d: FieldElement51([ - 1525827120027511, - 723686461809551, - 1597702369236987, - 244802101764964, - 1502833890372311, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2365421849929742, - 3485539881431101, - 2925909765963743, - 2114345180342964, - 2418564326541511, - ]), - y_minus_x: FieldElement51([ - 2041668749310338, - 2184405322203901, - 1633400637611036, - 2110682505536899, - 2048144390084644, - ]), - xy2d: FieldElement51([ - 503058759232932, - 760293024620937, - 2027152777219493, - 666858468148475, - 1539184379870952, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1916168475367211, - 3167426246226591, - 883217071712574, - 363427871374304, - 1976029821251593, - ]), - y_minus_x: FieldElement51([ - 678039535434506, - 570587290189340, - 1605302676614120, - 2147762562875701, - 1706063797091704, - ]), - xy2d: FieldElement51([ - 1439489648586438, - 2194580753290951, - 832380563557396, - 561521973970522, - 584497280718389, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2439789269177838, - 681223515948274, - 1933493571072456, - 1872921007304880, - 2739962177820919, - ]), - y_minus_x: FieldElement51([ - 1413466089534451, - 410844090765630, - 1397263346404072, - 408227143123410, - 1594561803147811, - ]), - xy2d: FieldElement51([ - 2102170800973153, - 719462588665004, - 1479649438510153, - 1097529543970028, - 1302363283777685, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3193865531532443, - 3321113493038208, - 2007341951411050, - 2322773230131539, - 1419433790163705, - ]), - y_minus_x: FieldElement51([ - 1146565545556377, - 1661971299445212, - 406681704748893, - 564452436406089, - 1109109865829139, - ]), - xy2d: FieldElement51([ - 2214421081775077, - 1165671861210569, - 1890453018796184, - 3556249878661, - 442116172656317, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3005630360306059, - 1666955059895018, - 1530775289309243, - 3371786842789394, - 2164156153857579, - ]), - y_minus_x: FieldElement51([ - 615171919212796, - 1523849404854568, - 854560460547503, - 2067097370290715, - 1765325848586042, - ]), - xy2d: FieldElement51([ - 1094538949313667, - 1796592198908825, - 870221004284388, - 2025558921863561, - 1699010892802384, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1951351290725195, - 1916457206844795, - 2449824998123274, - 1909076887557594, - 1938542290318919, - ]), - y_minus_x: FieldElement51([ - 1014323197538413, - 869150639940606, - 1756009942696599, - 1334952557375672, - 1544945379082874, - ]), - xy2d: FieldElement51([ - 764055910920305, - 1603590757375439, - 146805246592357, - 1843313433854297, - 954279890114939, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 80113526615731, - 764536758732259, - 3306939158785481, - 2721052465444637, - 2869697326116762, - ]), - y_minus_x: FieldElement51([ - 74497112547268, - 740094153192149, - 1745254631717581, - 727713886503130, - 1283034364416928, - ]), - xy2d: FieldElement51([ - 525892105991110, - 1723776830270342, - 1476444848991936, - 573789489857760, - 133864092632978, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2794411533877810, - 1986812262899320, - 1162535242465837, - 2733298779828712, - 2796400347268869, - ]), - y_minus_x: FieldElement51([ - 64123227344372, - 1239927720647794, - 1360722983445904, - 222610813654661, - 62429487187991, - ]), - xy2d: FieldElement51([ - 1793193323953132, - 91096687857833, - 70945970938921, - 2158587638946380, - 1537042406482111, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1895854577604590, - 3646695522634664, - 1728548428495943, - 3392664713925397, - 2815445147288308, - ]), - y_minus_x: FieldElement51([ - 141358280486863, - 91435889572504, - 1087208572552643, - 1829599652522921, - 1193307020643647, - ]), - xy2d: FieldElement51([ - 1611230858525381, - 950720175540785, - 499589887488610, - 2001656988495019, - 88977313255908, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3440880315164906, - 2184348804772596, - 3292618539427567, - 2018318290311833, - 1712060030915354, - ]), - y_minus_x: FieldElement51([ - 873966876953756, - 1090638350350440, - 1708559325189137, - 672344594801910, - 1320437969700239, - ]), - xy2d: FieldElement51([ - 1508590048271766, - 1131769479776094, - 101550868699323, - 428297785557897, - 561791648661744, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3008217384184691, - 2489682092917849, - 2136263418594015, - 1701968045454886, - 2955512998822720, - ]), - y_minus_x: FieldElement51([ - 1781187809325462, - 1697624151492346, - 1381393690939988, - 175194132284669, - 1483054666415238, - ]), - xy2d: FieldElement51([ - 2175517777364616, - 708781536456029, - 955668231122942, - 1967557500069555, - 2021208005604118, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3366935780292116, - 2476017186636029, - 915967306279221, - 593866251291540, - 2813546907893254, - ]), - y_minus_x: FieldElement51([ - 1443163092879439, - 391875531646162, - 2180847134654632, - 464538543018753, - 1594098196837178, - ]), - xy2d: FieldElement51([ - 850858855888869, - 319436476624586, - 327807784938441, - 740785849558761, - 17128415486016, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2132756334090048, - 2788047633840893, - 2300706964962114, - 2860273011285942, - 3513489358708031, - ]), - y_minus_x: FieldElement51([ - 1525176236978354, - 974205476721062, - 293436255662638, - 148269621098039, - 137961998433963, - ]), - xy2d: FieldElement51([ - 1121075518299410, - 2071745529082111, - 1265567917414828, - 1648196578317805, - 496232102750820, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2374121042985030, - 3274721891178932, - 2001275453369483, - 2017441881607947, - 3245005694463250, - ]), - y_minus_x: FieldElement51([ - 654925550560074, - 1168810995576858, - 575655959430926, - 905758704861388, - 496774564663534, - ]), - xy2d: FieldElement51([ - 1954109525779738, - 2117022646152485, - 338102630417180, - 1194140505732026, - 107881734943492, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1714785840001267, - 4288299832366837, - 1876380234251965, - 2056717182974196, - 1645855254384642, - ]), - y_minus_x: FieldElement51([ - 106431476499341, - 62482972120563, - 1513446655109411, - 807258751769522, - 538491469114, - ]), - xy2d: FieldElement51([ - 2002850762893643, - 1243624520538135, - 1486040410574605, - 2184752338181213, - 378495998083531, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 922510868424903, - 1089502620807680, - 402544072617374, - 1131446598479839, - 1290278588136533, - ]), - y_minus_x: FieldElement51([ - 1867998812076769, - 715425053580701, - 39968586461416, - 2173068014586163, - 653822651801304, - ]), - xy2d: FieldElement51([ - 162892278589453, - 182585796682149, - 75093073137630, - 497037941226502, - 133871727117371, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 4166396390264918, - 1608999621851577, - 1987629837704609, - 1519655314857977, - 1819193753409464, - ]), - y_minus_x: FieldElement51([ - 1949315551096831, - 1069003344994464, - 1939165033499916, - 1548227205730856, - 1933767655861407, - ]), - xy2d: FieldElement51([ - 1730519386931635, - 1393284965610134, - 1597143735726030, - 416032382447158, - 1429665248828629, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 360275475604546, - 2799635544748326, - 2467160717872776, - 2848446553564254, - 2584509464110332, - ]), - y_minus_x: FieldElement51([ - 47602113726801, - 1522314509708010, - 437706261372925, - 814035330438027, - 335930650933545, - ]), - xy2d: FieldElement51([ - 1291597595523886, - 1058020588994081, - 402837842324045, - 1363323695882781, - 2105763393033193, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2361321796251793, - 3967057562270386, - 1112231216891515, - 2046641005101484, - 2386048970842261, - ]), - y_minus_x: FieldElement51([ - 2156991030936798, - 2227544497153325, - 1869050094431622, - 754875860479115, - 1754242344267058, - ]), - xy2d: FieldElement51([ - 1846089562873800, - 98894784984326, - 1412430299204844, - 171351226625762, - 1100604760929008, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2335972195815721, - 2751510784385293, - 425749630620777, - 1762872794206857, - 2864642415813208, - ]), - y_minus_x: FieldElement51([ - 868309334532756, - 1703010512741873, - 1952690008738057, - 4325269926064, - 2071083554962116, - ]), - xy2d: FieldElement51([ - 523094549451158, - 401938899487815, - 1407690589076010, - 2022387426254453, - 158660516411257, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 612867287630009, - 2700012425789062, - 2823428891104443, - 1466796750919375, - 1728478129663858, - ]), - y_minus_x: FieldElement51([ - 1723848973783452, - 2208822520534681, - 1718748322776940, - 1974268454121942, - 1194212502258141, - ]), - xy2d: FieldElement51([ - 1254114807944608, - 977770684047110, - 2010756238954993, - 1783628927194099, - 1525962994408256, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2484263871921055, - 1948628555342433, - 1835348780427694, - 1031609499437291, - 2316271920603621, - ]), - y_minus_x: FieldElement51([ - 767338676040683, - 754089548318405, - 1523192045639075, - 435746025122062, - 512692508440385, - ]), - xy2d: FieldElement51([ - 1255955808701983, - 1700487367990941, - 1166401238800299, - 1175121994891534, - 1190934801395380, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2600943821853521, - 1337012557669161, - 1475912332999108, - 3573418268585706, - 2299411105589567, - ]), - y_minus_x: FieldElement51([ - 877519947135419, - 2172838026132651, - 272304391224129, - 1655143327559984, - 886229406429814, - ]), - xy2d: FieldElement51([ - 375806028254706, - 214463229793940, - 572906353144089, - 572168269875638, - 697556386112979, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1168827102357825, - 823864273033637, - 4323338565789945, - 788062026895923, - 2851378154428610, - ]), - y_minus_x: FieldElement51([ - 1948116082078088, - 2054898304487796, - 2204939184983900, - 210526805152138, - 786593586607626, - ]), - xy2d: FieldElement51([ - 1915320147894736, - 156481169009469, - 655050471180417, - 592917090415421, - 2165897438660879, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1726336468579724, - 1119932070398949, - 1929199510967666, - 2285718602008207, - 1836837863503149, - ]), - y_minus_x: FieldElement51([ - 829996854845988, - 217061778005138, - 1686565909803640, - 1346948817219846, - 1723823550730181, - ]), - xy2d: FieldElement51([ - 384301494966394, - 687038900403062, - 2211195391021739, - 254684538421383, - 1245698430589680, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1247567493562669, - 4229981908141095, - 2435671288478202, - 806570235643434, - 2540261331753164, - ]), - y_minus_x: FieldElement51([ - 1449077384734201, - 38285445457996, - 2136537659177832, - 2146493000841573, - 725161151123125, - ]), - xy2d: FieldElement51([ - 1201928866368855, - 800415690605445, - 1703146756828343, - 997278587541744, - 1858284414104014, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2608268623334125, - 3034173730618399, - 1718002439402869, - 3644022065904502, - 663171266061950, - ]), - y_minus_x: FieldElement51([ - 759628738230460, - 1012693474275852, - 353780233086498, - 246080061387552, - 2030378857679162, - ]), - xy2d: FieldElement51([ - 2040672435071076, - 888593182036908, - 1298443657189359, - 1804780278521327, - 354070726137060, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1894938527423184, - 3715012855162525, - 2726210319182898, - 2499094776718546, - 877975941029127, - ]), - y_minus_x: FieldElement51([ - 207937160991127, - 12966911039119, - 820997788283092, - 1010440472205286, - 1701372890140810, - ]), - xy2d: FieldElement51([ - 218882774543183, - 533427444716285, - 1233243976733245, - 435054256891319, - 1509568989549904, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 4140638349397055, - 3303977572025869, - 3465353617009382, - 2420981822812579, - 2715174081801119, - ]), - y_minus_x: FieldElement51([ - 299137589460312, - 1594371588983567, - 868058494039073, - 257771590636681, - 1805012993142921, - ]), - xy2d: FieldElement51([ - 1806842755664364, - 2098896946025095, - 1356630998422878, - 1458279806348064, - 347755825962072, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1402334161391744, - 3811883484731547, - 1008585416617746, - 1147797150908892, - 1420416683642459, - ]), - y_minus_x: FieldElement51([ - 665506704253369, - 273770475169863, - 799236974202630, - 848328990077558, - 1811448782807931, - ]), - xy2d: FieldElement51([ - 1468412523962641, - 771866649897997, - 1931766110147832, - 799561180078482, - 524837559150077, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2223212657821831, - 2882216061048914, - 2144451165500327, - 3068710944633039, - 3276150872095279, - ]), - y_minus_x: FieldElement51([ - 1266603897524861, - 156378408858100, - 1275649024228779, - 447738405888420, - 253186462063095, - ]), - xy2d: FieldElement51([ - 2022215964509735, - 136144366993649, - 1800716593296582, - 1193970603800203, - 871675847064218, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1862751661970309, - 851596246739884, - 1519315554814041, - 3794598280232697, - 3669775149586767, - ]), - y_minus_x: FieldElement51([ - 1228168094547481, - 334133883362894, - 587567568420081, - 433612590281181, - 603390400373205, - ]), - xy2d: FieldElement51([ - 121893973206505, - 1843345804916664, - 1703118377384911, - 497810164760654, - 101150811654673, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2710146069631716, - 2542709749304591, - 1452768413850678, - 2802722688939463, - 1537286854336537, - ]), - y_minus_x: FieldElement51([ - 584322311184395, - 380661238802118, - 114839394528060, - 655082270500073, - 2111856026034852, - ]), - xy2d: FieldElement51([ - 996965581008991, - 2148998626477022, - 1012273164934654, - 1073876063914522, - 1688031788934939, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3175286832534829, - 2085106799623354, - 2779882615305384, - 1606206360876187, - 2987706905397772, - ]), - y_minus_x: FieldElement51([ - 1697697887804317, - 1335343703828273, - 831288615207040, - 949416685250051, - 288760277392022, - ]), - xy2d: FieldElement51([ - 1419122478109648, - 1325574567803701, - 602393874111094, - 2107893372601700, - 1314159682671307, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2201150872731785, - 2180241023425241, - 2349463270108411, - 1633405770247823, - 3100744856129234, - ]), - y_minus_x: FieldElement51([ - 1173339555550611, - 818605084277583, - 47521504364289, - 924108720564965, - 735423405754506, - ]), - xy2d: FieldElement51([ - 830104860549448, - 1886653193241086, - 1600929509383773, - 1475051275443631, - 286679780900937, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3828911108518224, - 3282698983453994, - 2396700729978777, - 4216472406664814, - 2820189914640497, - ]), - y_minus_x: FieldElement51([ - 278388655910247, - 487143369099838, - 927762205508727, - 181017540174210, - 1616886700741287, - ]), - xy2d: FieldElement51([ - 1191033906638969, - 940823957346562, - 1606870843663445, - 861684761499847, - 658674867251089, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1875032594195527, - 1427106132796197, - 2976536204647406, - 3153660325729987, - 2887068310954007, - ]), - y_minus_x: FieldElement51([ - 622869792298357, - 1903919278950367, - 1922588621661629, - 1520574711600434, - 1087100760174640, - ]), - xy2d: FieldElement51([ - 25465949416618, - 1693639527318811, - 1526153382657203, - 125943137857169, - 145276964043999, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2466539671654587, - 920212862967914, - 4191701364657517, - 3463662605460468, - 2336897329405367, - ]), - y_minus_x: FieldElement51([ - 2006245852772938, - 734762734836159, - 254642929763427, - 1406213292755966, - 239303749517686, - ]), - xy2d: FieldElement51([ - 1619678837192149, - 1919424032779215, - 1357391272956794, - 1525634040073113, - 1310226789796241, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3292563523447371, - 1704449869235351, - 2857062884141577, - 1998838089036354, - 1312142911487502, - ]), - y_minus_x: FieldElement51([ - 1996723311435669, - 1844342766567060, - 985455700466044, - 1165924681400960, - 311508689870129, - ]), - xy2d: FieldElement51([ - 43173156290518, - 2202883069785309, - 1137787467085917, - 1733636061944606, - 1394992037553852, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 670078326344559, - 2807454838744604, - 2723759199967685, - 2141455487356408, - 849015953823125, - ]), - y_minus_x: FieldElement51([ - 2197214573372804, - 794254097241315, - 1030190060513737, - 267632515541902, - 2040478049202624, - ]), - xy2d: FieldElement51([ - 1812516004670529, - 1609256702920783, - 1706897079364493, - 258549904773295, - 996051247540686, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1540374301420565, - 1764656898914615, - 1810104162020396, - 3175608592848336, - 2916189887881826, - ]), - y_minus_x: FieldElement51([ - 1323460699404750, - 1262690757880991, - 871777133477900, - 1060078894988977, - 1712236889662886, - ]), - xy2d: FieldElement51([ - 1696163952057966, - 1391710137550823, - 608793846867416, - 1034391509472039, - 1780770894075012, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1367603834210822, - 4383788460268472, - 890353773628143, - 1908908219165595, - 2522636708938139, - ]), - y_minus_x: FieldElement51([ - 597536315471731, - 40375058742586, - 1942256403956049, - 1185484645495932, - 312666282024145, - ]), - xy2d: FieldElement51([ - 1919411405316294, - 1234508526402192, - 1066863051997083, - 1008444703737597, - 1348810787701552, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2102881477513865, - 3822074379630609, - 1573617900503707, - 2270462449417831, - 2232324307922097, - ]), - y_minus_x: FieldElement51([ - 1853931367696942, - 8107973870707, - 350214504129299, - 775206934582587, - 1752317649166792, - ]), - xy2d: FieldElement51([ - 1417148368003523, - 721357181628282, - 505725498207811, - 373232277872983, - 261634707184480, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2186733281493248, - 2250694917008620, - 1014829812957440, - 2731797975137637, - 2335366007561721, - ]), - y_minus_x: FieldElement51([ - 1268116367301224, - 560157088142809, - 802626839600444, - 2210189936605713, - 1129993785579988, - ]), - xy2d: FieldElement51([ - 615183387352312, - 917611676109240, - 878893615973325, - 978940963313282, - 938686890583575, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 522024729211672, - 3296859129001056, - 1892245413707789, - 1907891107684253, - 2059998109500714, - ]), - y_minus_x: FieldElement51([ - 1799679152208884, - 912132775900387, - 25967768040979, - 432130448590461, - 274568990261996, - ]), - xy2d: FieldElement51([ - 98698809797682, - 2144627600856209, - 1907959298569602, - 811491302610148, - 1262481774981493, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1791451399743152, - 1713538728337276, - 2370149810942738, - 1882306388849953, - 158235232210248, - ]), - y_minus_x: FieldElement51([ - 1217809823321928, - 2173947284933160, - 1986927836272325, - 1388114931125539, - 12686131160169, - ]), - xy2d: FieldElement51([ - 1650875518872272, - 1136263858253897, - 1732115601395988, - 734312880662190, - 1252904681142109, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2624786269799113, - 2777230729143418, - 2116279931702134, - 2753222527273063, - 1907002872974924, - ]), - y_minus_x: FieldElement51([ - 803147181835288, - 868941437997146, - 316299302989663, - 943495589630550, - 571224287904572, - ]), - xy2d: FieldElement51([ - 227742695588364, - 1776969298667369, - 628602552821802, - 457210915378118, - 2041906378111140, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 815000523470260, - 3164885502413555, - 3303859931956420, - 1345536665214222, - 541623413135555, - ]), - y_minus_x: FieldElement51([ - 1580216071604333, - 1877997504342444, - 857147161260913, - 703522726778478, - 2182763974211603, - ]), - xy2d: FieldElement51([ - 1870080310923419, - 71988220958492, - 1783225432016732, - 615915287105016, - 1035570475990230, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2982787564515398, - 857613889540279, - 1083813157271766, - 1002817255970169, - 1719228484436074, - ]), - y_minus_x: FieldElement51([ - 377616581647602, - 1581980403078513, - 804044118130621, - 2034382823044191, - 643844048472185, - ]), - xy2d: FieldElement51([ - 176957326463017, - 1573744060478586, - 528642225008045, - 1816109618372371, - 1515140189765006, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1888911448245718, - 3638910709296328, - 4176303607751676, - 1731539523700948, - 2230378382645454, - ]), - y_minus_x: FieldElement51([ - 443392177002051, - 233793396845137, - 2199506622312416, - 1011858706515937, - 974676837063129, - ]), - xy2d: FieldElement51([ - 1846351103143623, - 1949984838808427, - 671247021915253, - 1946756846184401, - 1929296930380217, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 849646212451983, - 1410198775302919, - 2325567699868943, - 1641663456615811, - 3014056086137659, - ]), - y_minus_x: FieldElement51([ - 692017667358279, - 723305578826727, - 1638042139863265, - 748219305990306, - 334589200523901, - ]), - xy2d: FieldElement51([ - 22893968530686, - 2235758574399251, - 1661465835630252, - 925707319443452, - 1203475116966621, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3053098849470395, - 3985092410411378, - 1664508947088595, - 2719548934677170, - 3899298398220870, - ]), - y_minus_x: FieldElement51([ - 903105258014366, - 427141894933047, - 561187017169777, - 1884330244401954, - 1914145708422219, - ]), - xy2d: FieldElement51([ - 1344191060517578, - 1960935031767890, - 1518838929955259, - 1781502350597190, - 1564784025565682, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2925523165433334, - 1979969272514922, - 3427087126180756, - 1187589090978665, - 1881897672213940, - ]), - y_minus_x: FieldElement51([ - 1917185587363432, - 1098342571752737, - 5935801044414, - 2000527662351839, - 1538640296181569, - ]), - xy2d: FieldElement51([ - 2495540013192, - 678856913479236, - 224998292422872, - 219635787698590, - 1972465269000940, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 271413961212179, - 3604851875156899, - 2596511104968730, - 2014925838520661, - 2006221033113941, - ]), - y_minus_x: FieldElement51([ - 194583029968109, - 514316781467765, - 829677956235672, - 1676415686873082, - 810104584395840, - ]), - xy2d: FieldElement51([ - 1980510813313589, - 1948645276483975, - 152063780665900, - 129968026417582, - 256984195613935, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1860190562533083, - 1936576191345085, - 2712900106391212, - 1811043097042829, - 3209286562992083, - ]), - y_minus_x: FieldElement51([ - 796664815624365, - 1543160838872951, - 1500897791837765, - 1667315977988401, - 599303877030711, - ]), - xy2d: FieldElement51([ - 1151480509533204, - 2136010406720455, - 738796060240027, - 319298003765044, - 1150614464349587, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1731069268103131, - 2987442261301335, - 1364750481334267, - 2669032653668119, - 3178908082812908, - ]), - y_minus_x: FieldElement51([ - 1017222050227968, - 1987716148359, - 2234319589635701, - 621282683093392, - 2132553131763026, - ]), - xy2d: FieldElement51([ - 1567828528453324, - 1017807205202360, - 565295260895298, - 829541698429100, - 307243822276582, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 249079270936229, - 1501514259790706, - 3199709537890096, - 944551802437486, - 2804458577667728, - ]), - y_minus_x: FieldElement51([ - 2089966982947227, - 1854140343916181, - 2151980759220007, - 2139781292261749, - 158070445864917, - ]), - xy2d: FieldElement51([ - 1338766321464554, - 1906702607371284, - 1519569445519894, - 115384726262267, - 1393058953390992, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3616421371950629, - 3764188048593604, - 1926731583198685, - 2041482526432505, - 3172200936019022, - ]), - y_minus_x: FieldElement51([ - 1884844597333588, - 601480070269079, - 620203503079537, - 1079527400117915, - 1202076693132015, - ]), - xy2d: FieldElement51([ - 840922919763324, - 727955812569642, - 1303406629750194, - 522898432152867, - 294161410441865, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2605560604520539, - 1598361541848742, - 3374705511887547, - 4174333403844152, - 2670907514351827, - ]), - y_minus_x: FieldElement51([ - 359856369838236, - 180914355488683, - 861726472646627, - 218807937262986, - 575626773232501, - ]), - xy2d: FieldElement51([ - 755467689082474, - 909202735047934, - 730078068932500, - 936309075711518, - 2007798262842972, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1609384177904054, - 2614544999293875, - 1335318541768200, - 3052765584121496, - 2799677792952659, - ]), - y_minus_x: FieldElement51([ - 984339177776787, - 815727786505884, - 1645154585713747, - 1659074964378553, - 1686601651984156, - ]), - xy2d: FieldElement51([ - 1697863093781930, - 599794399429786, - 1104556219769607, - 830560774794755, - 12812858601017, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1168737550514982, - 897832437380552, - 463140296333799, - 2554364413707795, - 2008360505135500, - ]), - y_minus_x: FieldElement51([ - 1856930662813910, - 678090852002597, - 1920179140755167, - 1259527833759868, - 55540971895511, - ]), - xy2d: FieldElement51([ - 1158643631044921, - 476554103621892, - 178447851439725, - 1305025542653569, - 103433927680625, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2176793111709008, - 3828525530035639, - 2009350167273522, - 2012390194631546, - 2125297410909580, - ]), - y_minus_x: FieldElement51([ - 825403285195098, - 2144208587560784, - 1925552004644643, - 1915177840006985, - 1015952128947864, - ]), - xy2d: FieldElement51([ - 1807108316634472, - 1534392066433717, - 347342975407218, - 1153820745616376, - 7375003497471, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3234860815484973, - 2683011703586488, - 2201903782961092, - 3069193724749589, - 2214616493042166, - ]), - y_minus_x: FieldElement51([ - 228567918409756, - 865093958780220, - 358083886450556, - 159617889659320, - 1360637926292598, - ]), - xy2d: FieldElement51([ - 234147501399755, - 2229469128637390, - 2175289352258889, - 1397401514549353, - 1885288963089922, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3363562226636810, - 2504649386192636, - 3300514047508588, - 2397910909286693, - 1237505378776769, - ]), - y_minus_x: FieldElement51([ - 1113790697840279, - 1051167139966244, - 1045930658550944, - 2011366241542643, - 1686166824620755, - ]), - xy2d: FieldElement51([ - 1054097349305049, - 1872495070333352, - 182121071220717, - 1064378906787311, - 100273572924182, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3558210666856834, - 1627717417672446, - 2302783034773665, - 1109249951172249, - 3122001602766640, - ]), - y_minus_x: FieldElement51([ - 104233794644221, - 1548919791188248, - 2224541913267306, - 2054909377116478, - 1043803389015153, - ]), - xy2d: FieldElement51([ - 216762189468802, - 707284285441622, - 190678557969733, - 973969342604308, - 1403009538434867, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3530824104723725, - 2596576648903557, - 2525521909702446, - 4086000250496689, - 634517197663803, - ]), - y_minus_x: FieldElement51([ - 343805853118335, - 1302216857414201, - 566872543223541, - 2051138939539004, - 321428858384280, - ]), - xy2d: FieldElement51([ - 470067171324852, - 1618629234173951, - 2000092177515639, - 7307679772789, - 1117521120249968, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2529951391976704, - 1810282338562946, - 1771599529530998, - 3635459223356879, - 2937173228157088, - ]), - y_minus_x: FieldElement51([ - 577009397403102, - 1791440261786291, - 2177643735971638, - 174546149911960, - 1412505077782326, - ]), - xy2d: FieldElement51([ - 893719721537457, - 1201282458018197, - 1522349501711173, - 58011597740583, - 1130406465887139, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 412607348255434, - 1280455764199780, - 2233277987330768, - 2265979894086913, - 2583384512102412, - ]), - y_minus_x: FieldElement51([ - 262483770854550, - 990511055108216, - 526885552771698, - 571664396646158, - 354086190278723, - ]), - xy2d: FieldElement51([ - 1820352417585487, - 24495617171480, - 1547899057533253, - 10041836186225, - 480457105094042, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2023310314989233, - 2889705151211129, - 2106474638900686, - 2809620524769320, - 1687858215057825, - ]), - y_minus_x: FieldElement51([ - 1144168702609745, - 604444390410187, - 1544541121756138, - 1925315550126027, - 626401428894002, - ]), - xy2d: FieldElement51([ - 1922168257351784, - 2018674099908659, - 1776454117494445, - 956539191509034, - 36031129147635, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2796444352433270, - 1039872944430373, - 3128550222815858, - 2962457525011798, - 3468752501170219, - ]), - y_minus_x: FieldElement51([ - 58242421545916, - 2035812695641843, - 2118491866122923, - 1191684463816273, - 46921517454099, - ]), - xy2d: FieldElement51([ - 272268252444639, - 1374166457774292, - 2230115177009552, - 1053149803909880, - 1354288411641016, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1857910905368338, - 1754729879288912, - 3137745277795125, - 1516096106802165, - 1602902393369811, - ]), - y_minus_x: FieldElement51([ - 1193437069800958, - 901107149704790, - 999672920611411, - 477584824802207, - 364239578697845, - ]), - xy2d: FieldElement51([ - 886299989548838, - 1538292895758047, - 1590564179491896, - 1944527126709657, - 837344427345298, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3006358179063534, - 1712186480903617, - 3955456640022779, - 3002110732175033, - 2770795853936147, - ]), - y_minus_x: FieldElement51([ - 1309847803895382, - 1462151862813074, - 211370866671570, - 1544595152703681, - 1027691798954090, - ]), - xy2d: FieldElement51([ - 803217563745370, - 1884799722343599, - 1357706345069218, - 2244955901722095, - 730869460037413, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2941099284981214, - 1831210565161070, - 3626987155270686, - 3358084791231418, - 1893781834054268, - ]), - y_minus_x: FieldElement51([ - 696351368613042, - 1494385251239250, - 738037133616932, - 636385507851544, - 927483222611406, - ]), - xy2d: FieldElement51([ - 1949114198209333, - 1104419699537997, - 783495707664463, - 1747473107602770, - 2002634765788641, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1607325776830197, - 2782683755100581, - 1451089452727894, - 3833490970768671, - 496100432831153, - ]), - y_minus_x: FieldElement51([ - 1068900648804224, - 2006891997072550, - 1134049269345549, - 1638760646180091, - 2055396084625778, - ]), - xy2d: FieldElement51([ - 2222475519314561, - 1870703901472013, - 1884051508440561, - 1344072275216753, - 1318025677799069, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 155711679280637, - 681100400509288, - 389811735211209, - 2135723811340709, - 2660533024889373, - ]), - y_minus_x: FieldElement51([ - 7813206966729, - 194444201427550, - 2071405409526507, - 1065605076176312, - 1645486789731291, - ]), - xy2d: FieldElement51([ - 16625790644959, - 1647648827778410, - 1579910185572704, - 436452271048548, - 121070048451050, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3289062842237779, - 2820185594063076, - 2549752917829677, - 3810384325616458, - 2238221839292470, - ]), - y_minus_x: FieldElement51([ - 190565267697443, - 672855706028058, - 338796554369226, - 337687268493904, - 853246848691734, - ]), - xy2d: FieldElement51([ - 1763863028400139, - 766498079432444, - 1321118624818005, - 69494294452268, - 858786744165651, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3543856582248253, - 1456632109855637, - 3352431060735432, - 1386133165675320, - 3484698163879000, - ]), - y_minus_x: FieldElement51([ - 366253102478259, - 525676242508811, - 1449610995265438, - 1183300845322183, - 185960306491545, - ]), - xy2d: FieldElement51([ - 28315355815982, - 460422265558930, - 1799675876678724, - 1969256312504498, - 1051823843138725, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2408714813047231, - 3857948219405196, - 1665208410108429, - 2569443092377519, - 1383783705665319, - ]), - y_minus_x: FieldElement51([ - 54684536365732, - 2210010038536222, - 1194984798155308, - 535239027773705, - 1516355079301361, - ]), - xy2d: FieldElement51([ - 1484387703771650, - 198537510937949, - 2186282186359116, - 617687444857508, - 647477376402122, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2147715541830533, - 2751832352131065, - 2898179830570073, - 2604027669016369, - 1488268620408051, - ]), - y_minus_x: FieldElement51([ - 159386186465542, - 1877626593362941, - 618737197060512, - 1026674284330807, - 1158121760792685, - ]), - xy2d: FieldElement51([ - 1744544377739822, - 1964054180355661, - 1685781755873170, - 2169740670377448, - 1286112621104591, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2333777063470241, - 3919742931398333, - 3920783633320113, - 1605016835177614, - 1353960708075544, - ]), - y_minus_x: FieldElement51([ - 1602253788689063, - 439542044889886, - 2220348297664483, - 657877410752869, - 157451572512238, - ]), - xy2d: FieldElement51([ - 1029287186166717, - 65860128430192, - 525298368814832, - 1491902500801986, - 1461064796385400, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2660016802414475, - 2121095722306988, - 913562102267595, - 1879708920318308, - 2492861262121979, - ]), - y_minus_x: FieldElement51([ - 1185483484383269, - 1356339572588553, - 584932367316448, - 102132779946470, - 1792922621116791, - ]), - xy2d: FieldElement51([ - 1966196870701923, - 2230044620318636, - 1425982460745905, - 261167817826569, - 46517743394330, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2358877405280588, - 3136759755857592, - 2279106683482647, - 2224911448949389, - 3216151871930471, - ]), - y_minus_x: FieldElement51([ - 1730194207717538, - 431790042319772, - 1831515233279467, - 1372080552768581, - 1074513929381760, - ]), - xy2d: FieldElement51([ - 1450880638731607, - 1019861580989005, - 1229729455116861, - 1174945729836143, - 826083146840706, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1899935429242705, - 1602068751520477, - 940583196550370, - 2334230882739107, - 1540863155745695, - ]), - y_minus_x: FieldElement51([ - 2136688454840028, - 2099509000964294, - 1690800495246475, - 1217643678575476, - 828720645084218, - ]), - xy2d: FieldElement51([ - 765548025667841, - 462473984016099, - 998061409979798, - 546353034089527, - 2212508972466858, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2298375097456408, - 3144370785258318, - 1281983193144089, - 1491520128287375, - 75847005908304, - ]), - y_minus_x: FieldElement51([ - 1801436127943107, - 1734436817907890, - 1268728090345068, - 167003097070711, - 2233597765834956, - ]), - xy2d: FieldElement51([ - 1997562060465113, - 1048700225534011, - 7615603985628, - 1855310849546841, - 2242557647635213, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1161017320376250, - 2744424393854291, - 2169815802355236, - 3228296595417790, - 1770879511019628, - ]), - y_minus_x: FieldElement51([ - 1357044908364776, - 729130645262438, - 1762469072918979, - 1365633616878458, - 181282906404941, - ]), - xy2d: FieldElement51([ - 1080413443139865, - 1155205815510486, - 1848782073549786, - 622566975152580, - 124965574467971, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1184526762066993, - 247622751762817, - 2943928830891604, - 3071818503097743, - 2188697339828084, - ]), - y_minus_x: FieldElement51([ - 2020536369003019, - 202261491735136, - 1053169669150884, - 2056531979272544, - 778165514694311, - ]), - xy2d: FieldElement51([ - 237404399610207, - 1308324858405118, - 1229680749538400, - 720131409105291, - 1958958863624906, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2767383321724075, - 2269456792542436, - 1717918437373988, - 1568052070792483, - 2298775616809171, - ]), - y_minus_x: FieldElement51([ - 281527309158085, - 36970532401524, - 866906920877543, - 2222282602952734, - 1289598729589882, - ]), - xy2d: FieldElement51([ - 1278207464902042, - 494742455008756, - 1262082121427081, - 1577236621659884, - 1888786707293291, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 353042527954210, - 1830056151907359, - 1111731275799225, - 2426760769524072, - 404312815582674, - ]), - y_minus_x: FieldElement51([ - 2064251142068628, - 1666421603389706, - 1419271365315441, - 468767774902855, - 191535130366583, - ]), - xy2d: FieldElement51([ - 1716987058588002, - 1859366439773457, - 1767194234188234, - 64476199777924, - 1117233614485261, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3236091949205521, - 2386938060636506, - 2220652137473166, - 1722843421165029, - 2442282371698157, - ]), - y_minus_x: FieldElement51([ - 298845952651262, - 1166086588952562, - 1179896526238434, - 1347812759398693, - 1412945390096208, - ]), - xy2d: FieldElement51([ - 1143239552672925, - 906436640714209, - 2177000572812152, - 2075299936108548, - 325186347798433, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2972824668060020, - 2936287674948563, - 3625238557779406, - 2193186935276994, - 1387043709851261, - ]), - y_minus_x: FieldElement51([ - 418098668140962, - 715065997721283, - 1471916138376055, - 2168570337288357, - 937812682637044, - ]), - xy2d: FieldElement51([ - 1043584187226485, - 2143395746619356, - 2209558562919611, - 482427979307092, - 847556718384018, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1248731221520740, - 1465200936117687, - 2792603306395388, - 2304778448366139, - 2513234303861356, - ]), - y_minus_x: FieldElement51([ - 1057329623869501, - 620334067429122, - 461700859268034, - 2012481616501857, - 297268569108938, - ]), - xy2d: FieldElement51([ - 1055352180870759, - 1553151421852298, - 1510903185371259, - 1470458349428097, - 1226259419062731, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3744788603986897, - 3042126439258578, - 3441906842094992, - 3641194565844440, - 3872208010289441, - ]), - y_minus_x: FieldElement51([ - 47000654413729, - 1004754424173864, - 1868044813557703, - 173236934059409, - 588771199737015, - ]), - xy2d: FieldElement51([ - 30498470091663, - 1082245510489825, - 576771653181956, - 806509986132686, - 1317634017056939, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2672107869436803, - 3745154677001249, - 2417006535213335, - 4136645508605033, - 2065456951573058, - ]), - y_minus_x: FieldElement51([ - 1115636332012334, - 1854340990964155, - 83792697369514, - 1972177451994021, - 457455116057587, - ]), - xy2d: FieldElement51([ - 1698968457310898, - 1435137169051090, - 1083661677032510, - 938363267483709, - 340103887207182, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1995325341336555, - 911500251774648, - 2415810569088940, - 855378419194761, - 3825401211214090, - ]), - y_minus_x: FieldElement51([ - 241719380661528, - 310028521317150, - 1215881323380194, - 1408214976493624, - 2141142156467363, - ]), - xy2d: FieldElement51([ - 1315157046163473, - 727368447885818, - 1363466668108618, - 1668921439990361, - 1398483384337907, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2326829491984875, - 3267188020145720, - 1849729037055211, - 4191614430138232, - 2696204044080201, - ]), - y_minus_x: FieldElement51([ - 2053597130993710, - 2024431685856332, - 2233550957004860, - 2012407275509545, - 872546993104440, - ]), - xy2d: FieldElement51([ - 1217269667678610, - 599909351968693, - 1390077048548598, - 1471879360694802, - 739586172317596, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3970118453066023, - 1560510726633957, - 3156262694845170, - 1418028351780051, - 2346204163137185, - ]), - y_minus_x: FieldElement51([ - 2132502667405250, - 214379346175414, - 1502748313768060, - 1960071701057800, - 1353971822643138, - ]), - xy2d: FieldElement51([ - 319394212043702, - 2127459436033571, - 717646691535162, - 663366796076914, - 318459064945314, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2657789238608841, - 1960452633787082, - 2919148848086913, - 3744474074452359, - 1451061489880786, - ]), - y_minus_x: FieldElement51([ - 947085906234007, - 323284730494107, - 1485778563977200, - 728576821512394, - 901584347702286, - ]), - xy2d: FieldElement51([ - 1575783124125742, - 2126210792434375, - 1569430791264065, - 1402582372904727, - 1891780248341114, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3090232019245924, - 4249503325136911, - 3270591693593114, - 1662001808174330, - 2330127946643001, - ]), - y_minus_x: FieldElement51([ - 739152638255629, - 2074935399403557, - 505483666745895, - 1611883356514088, - 628654635394878, - ]), - xy2d: FieldElement51([ - 1822054032121349, - 643057948186973, - 7306757352712, - 577249257962099, - 284735863382083, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3618358370049178, - 1448606567552085, - 3730680834630016, - 2417602993041145, - 1115718458123497, - ]), - y_minus_x: FieldElement51([ - 204146226972102, - 1630511199034723, - 2215235214174763, - 174665910283542, - 956127674017216, - ]), - xy2d: FieldElement51([ - 1562934578796716, - 1070893489712745, - 11324610642270, - 958989751581897, - 2172552325473805, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1770564423056008, - 2987323445349813, - 1326060113795288, - 1509650369341127, - 2317692235267932, - ]), - y_minus_x: FieldElement51([ - 623682558650637, - 1337866509471512, - 990313350206649, - 1314236615762469, - 1164772974270275, - ]), - xy2d: FieldElement51([ - 223256821462517, - 723690150104139, - 1000261663630601, - 933280913953265, - 254872671543046, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1969087237026022, - 2876595539132372, - 1335555107635968, - 2069986355593023, - 3963899963027150, - ]), - y_minus_x: FieldElement51([ - 1236103475266979, - 1837885883267218, - 1026072585230455, - 1025865513954973, - 1801964901432134, - ]), - xy2d: FieldElement51([ - 1115241013365517, - 1712251818829143, - 2148864332502771, - 2096001471438138, - 2235017246626125, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3551068012286861, - 2047148477845620, - 2165648650132450, - 1612539282026145, - 2765997725314138, - ]), - y_minus_x: FieldElement51([ - 118352772338543, - 1067608711804704, - 1434796676193498, - 1683240170548391, - 230866769907437, - ]), - xy2d: FieldElement51([ - 1850689576796636, - 1601590730430274, - 1139674615958142, - 1954384401440257, - 76039205311, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1723387471374172, - 3249101280723658, - 2785727448808904, - 2272728458379212, - 1756575222802512, - ]), - y_minus_x: FieldElement51([ - 2146711623855116, - 503278928021499, - 625853062251406, - 1109121378393107, - 1033853809911861, - ]), - xy2d: FieldElement51([ - 571005965509422, - 2005213373292546, - 1016697270349626, - 56607856974274, - 914438579435146, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1346698876211176, - 2076651707527589, - 3336561384795453, - 2517134292513653, - 1068954492309670, - ]), - y_minus_x: FieldElement51([ - 1769967932677654, - 1695893319756416, - 1151863389675920, - 1781042784397689, - 400287774418285, - ]), - xy2d: FieldElement51([ - 1851867764003121, - 403841933237558, - 820549523771987, - 761292590207581, - 1743735048551143, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 410915148140008, - 2107072311871739, - 3256167275561751, - 2351484709082008, - 1180818713503223, - ]), - y_minus_x: FieldElement51([ - 285945406881439, - 648174397347453, - 1098403762631981, - 1366547441102991, - 1505876883139217, - ]), - xy2d: FieldElement51([ - 672095903120153, - 1675918957959872, - 636236529315028, - 1569297300327696, - 2164144194785875, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1902708175321798, - 3287143344600686, - 1178560808893262, - 2552895497743394, - 1280977479761117, - ]), - y_minus_x: FieldElement51([ - 1615357281742403, - 404257611616381, - 2160201349780978, - 1160947379188955, - 1578038619549541, - ]), - xy2d: FieldElement51([ - 2013087639791217, - 822734930507457, - 1785668418619014, - 1668650702946164, - 389450875221715, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2705718263383616, - 2358206633614248, - 2072540975937134, - 308588860670238, - 1304394580755385, - ]), - y_minus_x: FieldElement51([ - 1295082798350326, - 2091844511495996, - 1851348972587817, - 3375039684596, - 789440738712837, - ]), - xy2d: FieldElement51([ - 2083069137186154, - 848523102004566, - 993982213589257, - 1405313299916317, - 1532824818698468, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3747761112537659, - 1397203457344778, - 4026750030752190, - 2391102557240943, - 2318403398028034, - ]), - y_minus_x: FieldElement51([ - 1782411379088302, - 1096724939964781, - 27593390721418, - 542241850291353, - 1540337798439873, - ]), - xy2d: FieldElement51([ - 693543956581437, - 171507720360750, - 1557908942697227, - 1074697073443438, - 1104093109037196, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 345288228393400, - 3351443383432420, - 2386681722088990, - 1740551994106739, - 2500011992985018, - ]), - y_minus_x: FieldElement51([ - 231429562203065, - 1526290236421172, - 2021375064026423, - 1520954495658041, - 806337791525116, - ]), - xy2d: FieldElement51([ - 1079623667189886, - 872403650198613, - 766894200588288, - 2163700860774109, - 2023464507911816, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 854645372543796, - 1936406001954827, - 2403260476226501, - 3077125552956802, - 1554306377287555, - ]), - y_minus_x: FieldElement51([ - 1497138821904622, - 1044820250515590, - 1742593886423484, - 1237204112746837, - 849047450816987, - ]), - xy2d: FieldElement51([ - 667962773375330, - 1897271816877105, - 1399712621683474, - 1143302161683099, - 2081798441209593, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2378947665252234, - 1936114012888109, - 1704424366552046, - 3108474694401560, - 2968403435020606, - ]), - y_minus_x: FieldElement51([ - 1072409664800960, - 2146937497077528, - 1508780108920651, - 935767602384853, - 1112800433544068, - ]), - xy2d: FieldElement51([ - 333549023751292, - 280219272863308, - 2104176666454852, - 1036466864875785, - 536135186520207, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2625466093568366, - 2398257055215356, - 2555916080813104, - 2667888562832962, - 3510376944868638, - ]), - y_minus_x: FieldElement51([ - 1186115062588401, - 2251609796968486, - 1098944457878953, - 1153112761201374, - 1791625503417267, - ]), - xy2d: FieldElement51([ - 1870078460219737, - 2129630962183380, - 852283639691142, - 292865602592851, - 401904317342226, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1361070124828016, - 815664541425524, - 3278598711049919, - 1951790935390646, - 2807674705520038, - ]), - y_minus_x: FieldElement51([ - 1546301003424277, - 459094500062839, - 1097668518375311, - 1780297770129643, - 720763293687608, - ]), - xy2d: FieldElement51([ - 1212405311403990, - 1536693382542438, - 61028431067459, - 1863929423417129, - 1223219538638038, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1294303766540260, - 3435357279640341, - 3134071170918340, - 2315654383110622, - 2213283684565086, - ]), - y_minus_x: FieldElement51([ - 339050984211414, - 601386726509773, - 413735232134068, - 966191255137228, - 1839475899458159, - ]), - xy2d: FieldElement51([ - 235605972169408, - 2174055643032978, - 1538335001838863, - 1281866796917192, - 1815940222628465, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1632352921721536, - 1833328609514701, - 2092779091951987, - 4175756015558474, - 2210068022482918, - ]), - y_minus_x: FieldElement51([ - 35271216625062, - 1712350667021807, - 983664255668860, - 98571260373038, - 1232645608559836, - ]), - xy2d: FieldElement51([ - 1998172393429622, - 1798947921427073, - 784387737563581, - 1589352214827263, - 1589861734168180, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1733739258725305, - 2283515530744786, - 2453769758904107, - 3243892858242237, - 1194308773174555, - ]), - y_minus_x: FieldElement51([ - 846415389605137, - 746163495539180, - 829658752826080, - 592067705956946, - 957242537821393, - ]), - xy2d: FieldElement51([ - 1758148849754419, - 619249044817679, - 168089007997045, - 1371497636330523, - 1867101418880350, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2578433797894864, - 2513559319756263, - 1700682323676192, - 1577907266349064, - 3469447477068264, - ]), - y_minus_x: FieldElement51([ - 1714182387328607, - 1477856482074168, - 574895689942184, - 2159118410227270, - 1555532449716575, - ]), - xy2d: FieldElement51([ - 853828206885131, - 998498946036955, - 1835887550391235, - 207627336608048, - 258363815956050, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2392941288336925, - 3488528558590503, - 2894901233585134, - 1646615130509172, - 1208239602291765, - ]), - y_minus_x: FieldElement51([ - 1501663228068911, - 1354879465566912, - 1444432675498247, - 897812463852601, - 855062598754348, - ]), - xy2d: FieldElement51([ - 714380763546606, - 1032824444965790, - 1774073483745338, - 1063840874947367, - 1738680636537158, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1640635546696233, - 2884968766877360, - 2212651044092395, - 2282390772269100, - 2620315074574625, - ]), - y_minus_x: FieldElement51([ - 1171650314802029, - 1567085444565577, - 1453660792008405, - 757914533009261, - 1619511342778196, - ]), - xy2d: FieldElement51([ - 420958967093237, - 971103481109486, - 2169549185607107, - 1301191633558497, - 1661514101014240, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3158923465503550, - 1332556122804145, - 4075855067109735, - 3619414031128206, - 1982558335973171, - ]), - y_minus_x: FieldElement51([ - 1121533090144639, - 1021251337022187, - 110469995947421, - 1511059774758394, - 2110035908131662, - ]), - xy2d: FieldElement51([ - 303213233384524, - 2061932261128138, - 352862124777736, - 40828818670255, - 249879468482660, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 856559257852200, - 2760317478634258, - 3629993581580163, - 3975258940632376, - 1962275756614520, - ]), - y_minus_x: FieldElement51([ - 1445691340537320, - 40614383122127, - 402104303144865, - 485134269878232, - 1659439323587426, - ]), - xy2d: FieldElement51([ - 20057458979482, - 1183363722525800, - 2140003847237215, - 2053873950687614, - 2112017736174909, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2228654250927986, - 3735391177100515, - 1368661293910955, - 3328311098862539, - 526650682059607, - ]), - y_minus_x: FieldElement51([ - 709481497028540, - 531682216165724, - 316963769431931, - 1814315888453765, - 258560242424104, - ]), - xy2d: FieldElement51([ - 1053447823660455, - 1955135194248683, - 1010900954918985, - 1182614026976701, - 1240051576966610, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1957943897155478, - 1788667368028035, - 2389492723714354, - 2252839333292309, - 3078204576998275, - ]), - y_minus_x: FieldElement51([ - 1848942433095597, - 1582009882530495, - 1849292741020143, - 1068498323302788, - 2001402229799484, - ]), - xy2d: FieldElement51([ - 1528282417624269, - 2142492439828191, - 2179662545816034, - 362568973150328, - 1591374675250271, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2411826493119617, - 2484141002903963, - 2149181472355544, - 598041771119831, - 2435658815595421, - ]), - y_minus_x: FieldElement51([ - 2013278155187349, - 662660471354454, - 793981225706267, - 411706605985744, - 804490933124791, - ]), - xy2d: FieldElement51([ - 2051892037280204, - 488391251096321, - 2230187337030708, - 930221970662692, - 679002758255210, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1530723630438670, - 875873929577927, - 2593359947955236, - 2701702933216000, - 1055551308214178, - ]), - y_minus_x: FieldElement51([ - 1461835919309432, - 1955256480136428, - 180866187813063, - 1551979252664528, - 557743861963950, - ]), - xy2d: FieldElement51([ - 359179641731115, - 1324915145732949, - 902828372691474, - 294254275669987, - 1887036027752957, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 4295071423139571, - 2038225437857463, - 1317528426475850, - 1398989128982787, - 2027639881006861, - ]), - y_minus_x: FieldElement51([ - 2072902725256516, - 312132452743412, - 309930885642209, - 996244312618453, - 1590501300352303, - ]), - xy2d: FieldElement51([ - 1397254305160710, - 695734355138021, - 2233992044438756, - 1776180593969996, - 1085588199351115, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2692366865016258, - 2506694600041928, - 2745669038615469, - 1556322069683365, - 3819256354004466, - ]), - y_minus_x: FieldElement51([ - 1950722461391320, - 1907845598854797, - 1822757481635527, - 2121567704750244, - 73811931471221, - ]), - xy2d: FieldElement51([ - 387139307395758, - 2058036430315676, - 1220915649965325, - 1794832055328951, - 1230009312169328, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1765973779329498, - 2911143873132225, - 2271621715291913, - 3553728154996461, - 3368065817761132, - ]), - y_minus_x: FieldElement51([ - 1127572801181483, - 1224743760571696, - 1276219889847274, - 1529738721702581, - 1589819666871853, - ]), - xy2d: FieldElement51([ - 2181229378964934, - 2190885205260020, - 1511536077659137, - 1246504208580490, - 668883326494241, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2689666469258543, - 2920826224880015, - 2333696811665585, - 523874406393177, - 2496851874620484, - ]), - y_minus_x: FieldElement51([ - 1975438052228868, - 1071801519999806, - 594652299224319, - 1877697652668809, - 1489635366987285, - ]), - xy2d: FieldElement51([ - 958592545673770, - 233048016518599, - 851568750216589, - 567703851596087, - 1740300006094761, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2014540178270324, - 192672779514432, - 2465676996326778, - 2194819933853410, - 1716422829364835, - ]), - y_minus_x: FieldElement51([ - 1540769606609725, - 2148289943846077, - 1597804156127445, - 1230603716683868, - 815423458809453, - ]), - xy2d: FieldElement51([ - 1738560251245018, - 1779576754536888, - 1783765347671392, - 1880170990446751, - 1088225159617541, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2911103727614740, - 1956447718227572, - 1830568515922666, - 3092868863429656, - 1669607124206367, - ]), - y_minus_x: FieldElement51([ - 1143465490433355, - 1532194726196059, - 1093276745494697, - 481041706116088, - 2121405433561163, - ]), - xy2d: FieldElement51([ - 1686424298744462, - 1451806974487153, - 266296068846582, - 1834686947542675, - 1720762336132256, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3141016840074207, - 3295090436969907, - 3107924901237156, - 1669272323124635, - 1603340330827879, - ]), - y_minus_x: FieldElement51([ - 1206396181488998, - 333158148435054, - 1402633492821422, - 1120091191722026, - 1945474114550509, - ]), - xy2d: FieldElement51([ - 766720088232571, - 1512222781191002, - 1189719893490790, - 2091302129467914, - 2141418006894941, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2671463460991841, - 1998875112167986, - 3678399683938955, - 3406728169064757, - 2738338345823434, - ]), - y_minus_x: FieldElement51([ - 938160078005954, - 1421776319053174, - 1941643234741774, - 180002183320818, - 1414380336750546, - ]), - xy2d: FieldElement51([ - 398001940109652, - 1577721237663248, - 1012748649830402, - 1540516006905144, - 1011684812884559, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1653276489969611, - 2257881638852872, - 1921777941170835, - 1604139841794531, - 3113010867325889, - ]), - y_minus_x: FieldElement51([ - 996661541407379, - 1455877387952927, - 744312806857277, - 139213896196746, - 1000282908547789, - ]), - xy2d: FieldElement51([ - 1450817495603008, - 1476865707053229, - 1030490562252053, - 620966950353376, - 1744760161539058, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2811528223687828, - 2288856475326432, - 2038622963352005, - 1637244893271723, - 3278365165924196, - ]), - y_minus_x: FieldElement51([ - 962165956135846, - 1116599660248791, - 182090178006815, - 1455605467021751, - 196053588803284, - ]), - xy2d: FieldElement51([ - 796863823080135, - 1897365583584155, - 420466939481601, - 2165972651724672, - 932177357788289, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 877047233620613, - 1375632631944375, - 2895573425567369, - 2911822552533124, - 2271153746017078, - ]), - y_minus_x: FieldElement51([ - 2216943882299338, - 394841323190322, - 2222656898319671, - 558186553950529, - 1077236877025190, - ]), - xy2d: FieldElement51([ - 801118384953213, - 1914330175515892, - 574541023311511, - 1471123787903705, - 1526158900256288, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3201417702772463, - 2207116611267330, - 3164719852826535, - 2752958352884036, - 2314162374456719, - ]), - y_minus_x: FieldElement51([ - 1474518386765335, - 1760793622169197, - 1157399790472736, - 1622864308058898, - 165428294422792, - ]), - xy2d: FieldElement51([ - 1961673048027128, - 102619413083113, - 1051982726768458, - 1603657989805485, - 1941613251499678, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1401939116319247, - 2587106153588320, - 2323846009771033, - 862423201496005, - 3102318568216632, - ]), - y_minus_x: FieldElement51([ - 1234706593321979, - 1083343891215917, - 898273974314935, - 1640859118399498, - 157578398571149, - ]), - xy2d: FieldElement51([ - 1143483057726416, - 1992614991758919, - 674268662140796, - 1773370048077526, - 674318359920189, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1835401379538542, - 173900035308392, - 818247630716732, - 4013900225838034, - 1021506399448290, - ]), - y_minus_x: FieldElement51([ - 1506632088156630, - 2127481795522179, - 513812919490255, - 140643715928370, - 442476620300318, - ]), - xy2d: FieldElement51([ - 2056683376856736, - 219094741662735, - 2193541883188309, - 1841182310235800, - 556477468664293, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3566819241596075, - 1049075855992602, - 4318372866671791, - 2518704280870781, - 2040482348591519, - ]), - y_minus_x: FieldElement51([ - 94096246544434, - 922482381166992, - 24517828745563, - 2139430508542503, - 2097139044231004, - ]), - xy2d: FieldElement51([ - 537697207950515, - 1399352016347350, - 1563663552106345, - 2148749520888918, - 549922092988516, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1747985413252415, - 680511052635695, - 1809559829982725, - 2846074064615302, - 2453472984431229, - ]), - y_minus_x: FieldElement51([ - 323583936109569, - 1973572998577657, - 1192219029966558, - 79354804385273, - 1374043025560347, - ]), - xy2d: FieldElement51([ - 213277331329947, - 416202017849623, - 1950535221091783, - 1313441578103244, - 2171386783823658, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2440888617915079, - 993969372859109, - 3147669935222235, - 3799101348983503, - 1477373024911349, - ]), - y_minus_x: FieldElement51([ - 1620578418245010, - 541035331188469, - 2235785724453865, - 2154865809088198, - 1974627268751826, - ]), - xy2d: FieldElement51([ - 1346805451740245, - 1350981335690626, - 942744349501813, - 2155094562545502, - 1012483751693409, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2107080134091762, - 1132567062788208, - 1824935377687210, - 769194804343737, - 1857941799971888, - ]), - y_minus_x: FieldElement51([ - 1074666112436467, - 249279386739593, - 1174337926625354, - 1559013532006480, - 1472287775519121, - ]), - xy2d: FieldElement51([ - 1872620123779532, - 1892932666768992, - 1921559078394978, - 1270573311796160, - 1438913646755037, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3089190001333428, - 3264053113908846, - 989780015893986, - 1351393287739814, - 2580427560230798, - ]), - y_minus_x: FieldElement51([ - 1028328827183114, - 1711043289969857, - 1350832470374933, - 1923164689604327, - 1495656368846911, - ]), - xy2d: FieldElement51([ - 1900828492104143, - 430212361082163, - 687437570852799, - 832514536673512, - 1685641495940794, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3094432661621646, - 605670026766215, - 290836444839585, - 2415010588577604, - 2213815011799644, - ]), - y_minus_x: FieldElement51([ - 1176336383453996, - 1725477294339771, - 12700622672454, - 678015708818208, - 162724078519879, - ]), - xy2d: FieldElement51([ - 1448049969043497, - 1789411762943521, - 385587766217753, - 90201620913498, - 832999441066823, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2767886146978542, - 2240508292484615, - 3603469341851756, - 3475055379001735, - 3002035638112385, - ]), - y_minus_x: FieldElement51([ - 1263624896582495, - 1102602401673328, - 526302183714372, - 2152015839128799, - 1483839308490010, - ]), - xy2d: FieldElement51([ - 442991718646863, - 1599275157036458, - 1925389027579192, - 899514691371390, - 350263251085160, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1689713572022124, - 2845654372939621, - 3229894858477217, - 1985127338729498, - 3927868934032873, - ]), - y_minus_x: FieldElement51([ - 1557207018622683, - 340631692799603, - 1477725909476187, - 614735951619419, - 2033237123746766, - ]), - xy2d: FieldElement51([ - 968764929340557, - 1225534776710944, - 662967304013036, - 1155521416178595, - 791142883466590, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1487081286167458, - 3244839255500182, - 1792378982844639, - 2950452258685122, - 2153908693179753, - ]), - y_minus_x: FieldElement51([ - 1123181311102823, - 685575944875442, - 507605465509927, - 1412590462117473, - 568017325228626, - ]), - xy2d: FieldElement51([ - 560258797465417, - 2193971151466401, - 1824086900849026, - 579056363542056, - 1690063960036441, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1918407319222397, - 2605567366745211, - 1930426334528098, - 1564816146005724, - 4113142195393344, - ]), - y_minus_x: FieldElement51([ - 2131325168777276, - 1176636658428908, - 1756922641512981, - 1390243617176012, - 1966325177038383, - ]), - xy2d: FieldElement51([ - 2063958120364491, - 2140267332393533, - 699896251574968, - 273268351312140, - 375580724713232, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2024297515263178, - 2668759143407935, - 3330814048702549, - 2423412039258430, - 1031677520051052, - ]), - y_minus_x: FieldElement51([ - 2033900009388450, - 1744902869870788, - 2190580087917640, - 1949474984254121, - 231049754293748, - ]), - xy2d: FieldElement51([ - 343868674606581, - 550155864008088, - 1450580864229630, - 481603765195050, - 896972360018042, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2151139328380127, - 2566545695770176, - 2311556639460451, - 1676664391494650, - 2048348075599360, - ]), - y_minus_x: FieldElement51([ - 1528930066340597, - 1605003907059576, - 1055061081337675, - 1458319101947665, - 1234195845213142, - ]), - xy2d: FieldElement51([ - 830430507734812, - 1780282976102377, - 1425386760709037, - 362399353095425, - 2168861579799910, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3407562046415562, - 980662895504005, - 2053766700883521, - 2742766027762854, - 2762205690726604, - ]), - y_minus_x: FieldElement51([ - 1683750316716132, - 652278688286128, - 1221798761193539, - 1897360681476669, - 319658166027343, - ]), - xy2d: FieldElement51([ - 618808732869972, - 72755186759744, - 2060379135624181, - 1730731526741822, - 48862757828238, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3714971784278753, - 3394840525452699, - 614590986558882, - 1409210575145591, - 1882816996436803, - ]), - y_minus_x: FieldElement51([ - 2230133264691131, - 563950955091024, - 2042915975426398, - 827314356293472, - 672028980152815, - ]), - xy2d: FieldElement51([ - 264204366029760, - 1654686424479449, - 2185050199932931, - 2207056159091748, - 506015669043634, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1784446333136550, - 1973746527984364, - 334856327359575, - 3408569589569858, - 3275749938360725, - ]), - y_minus_x: FieldElement51([ - 2065270940578383, - 31477096270353, - 306421879113491, - 181958643936686, - 1907105536686083, - ]), - xy2d: FieldElement51([ - 1496516440779464, - 1748485652986458, - 872778352227340, - 818358834654919, - 97932669284220, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2723435829455580, - 2924255216478824, - 1804995246884102, - 1842309243470804, - 3753662318666930, - ]), - y_minus_x: FieldElement51([ - 1013216974933691, - 538921919682598, - 1915776722521558, - 1742822441583877, - 1886550687916656, - ]), - xy2d: FieldElement51([ - 2094270000643336, - 303971879192276, - 40801275554748, - 649448917027930, - 1818544418535447, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2241737709499146, - 549397817447461, - 838180519319392, - 1725686958520781, - 3957438894582995, - ]), - y_minus_x: FieldElement51([ - 1216074541925116, - 50120933933509, - 1565829004133810, - 721728156134580, - 349206064666188, - ]), - xy2d: FieldElement51([ - 948617110470858, - 346222547451945, - 1126511960599975, - 1759386906004538, - 493053284802266, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1454933046815146, - 3126495827951610, - 1467170975468587, - 1432316382418897, - 2111710746366763, - ]), - y_minus_x: FieldElement51([ - 2105387117364450, - 1996463405126433, - 1303008614294500, - 851908115948209, - 1353742049788635, - ]), - xy2d: FieldElement51([ - 750300956351719, - 1487736556065813, - 15158817002104, - 1511998221598392, - 971739901354129, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1874648163531674, - 2124487685930551, - 1810030029384882, - 918400043048335, - 2838148440985898, - ]), - y_minus_x: FieldElement51([ - 1235084464747900, - 1166111146432082, - 1745394857881591, - 1405516473883040, - 4463504151617, - ]), - xy2d: FieldElement51([ - 1663810156463827, - 327797390285791, - 1341846161759410, - 1964121122800605, - 1747470312055380, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 660005247548214, - 2071860029952887, - 3610548013635355, - 911703252219106, - 3266179736709079, - ]), - y_minus_x: FieldElement51([ - 2206641276178231, - 1690587809721504, - 1600173622825126, - 2156096097634421, - 1106822408548216, - ]), - xy2d: FieldElement51([ - 1344788193552206, - 1949552134239140, - 1735915881729557, - 675891104100469, - 1834220014427292, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1920949492387945, - 2410685102072778, - 2322108077349280, - 2877838278583064, - 3719881539786256, - ]), - y_minus_x: FieldElement51([ - 622221042073383, - 1210146474039168, - 1742246422343683, - 1403839361379025, - 417189490895736, - ]), - xy2d: FieldElement51([ - 22727256592983, - 168471543384997, - 1324340989803650, - 1839310709638189, - 504999476432775, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3565040332441556, - 1721896294296941, - 2304063388272514, - 2065069734239231, - 3056710287109878, - ]), - y_minus_x: FieldElement51([ - 1337466662091884, - 1287645354669772, - 2018019646776184, - 652181229374245, - 898011753211715, - ]), - xy2d: FieldElement51([ - 1969792547910734, - 779969968247557, - 2011350094423418, - 1823964252907487, - 1058949448296945, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2459143550747250, - 1118176942430252, - 3010694408233412, - 806764629546265, - 1157700123092949, - ]), - y_minus_x: FieldElement51([ - 1273565321399022, - 1638509681964574, - 759235866488935, - 666015124346707, - 897983460943405, - ]), - xy2d: FieldElement51([ - 1717263794012298, - 1059601762860786, - 1837819172257618, - 1054130665797229, - 680893204263559, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2237039662793603, - 2249022333361206, - 2058613546633703, - 2401253908530527, - 2215176649164581, - ]), - y_minus_x: FieldElement51([ - 79472182719605, - 1851130257050174, - 1825744808933107, - 821667333481068, - 781795293511946, - ]), - xy2d: FieldElement51([ - 755822026485370, - 152464789723500, - 1178207602290608, - 410307889503239, - 156581253571278, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3669985309815545, - 2736319981413860, - 3898537095128197, - 3653287498355512, - 1349185550126960, - ]), - y_minus_x: FieldElement51([ - 1495380034400429, - 325049476417173, - 46346894893933, - 1553408840354856, - 828980101835683, - ]), - xy2d: FieldElement51([ - 1280337889310282, - 2070832742866672, - 1640940617225222, - 2098284908289951, - 450929509534434, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2659503167684029, - 2378371955168899, - 2537839641198868, - 1999255076709337, - 2030511179441770, - ]), - y_minus_x: FieldElement51([ - 1254958221100483, - 1153235960999843, - 942907704968834, - 637105404087392, - 1149293270147267, - ]), - xy2d: FieldElement51([ - 894249020470196, - 400291701616810, - 406878712230981, - 1599128793487393, - 1145868722604026, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3749755063888563, - 2361916158338507, - 1128535642171975, - 1900106496009660, - 2381592531146157, - ]), - y_minus_x: FieldElement51([ - 452487513298665, - 1352120549024569, - 1173495883910956, - 1999111705922009, - 367328130454226, - ]), - xy2d: FieldElement51([ - 1717539401269642, - 1475188995688487, - 891921989653942, - 836824441505699, - 1885988485608364, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3493583935107776, - 2439136865632830, - 3370281625921440, - 2680547565621609, - 2282158712612572, - ]), - y_minus_x: FieldElement51([ - 2022432361201842, - 1088816090685051, - 1977843398539868, - 1854834215890724, - 564238862029357, - ]), - xy2d: FieldElement51([ - 938868489100585, - 1100285072929025, - 1017806255688848, - 1957262154788833, - 152787950560442, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3119119231364171, - 2872271776627789, - 2477832016990963, - 2593801257642876, - 1761675818237335, - ]), - y_minus_x: FieldElement51([ - 1295072362439987, - 931227904689414, - 1355731432641687, - 922235735834035, - 892227229410209, - ]), - xy2d: FieldElement51([ - 1680989767906154, - 535362787031440, - 2136691276706570, - 1942228485381244, - 1267350086882274, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2617818047455756, - 2684460443440843, - 2378209521329782, - 1973842949591661, - 2897427157127624, - ]), - y_minus_x: FieldElement51([ - 535509430575217, - 546885533737322, - 1524675609547799, - 2138095752851703, - 1260738089896827, - ]), - xy2d: FieldElement51([ - 1159906385590467, - 2198530004321610, - 714559485023225, - 81880727882151, - 1484020820037082, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1377485731340769, - 2046328105512000, - 1802058637158797, - 2313945950453421, - 1356993908853900, - ]), - y_minus_x: FieldElement51([ - 2013612215646735, - 1830770575920375, - 536135310219832, - 609272325580394, - 270684344495013, - ]), - xy2d: FieldElement51([ - 1237542585982777, - 2228682050256790, - 1385281931622824, - 593183794882890, - 493654978552689, - ]), - }, - ]), - LookupTable([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2299141301692989, - 1891414891220256, - 983894663308928, - 2427961581972066, - 3378060928864955, - ]), - y_minus_x: FieldElement51([ - 1694030170963455, - 502038567066200, - 1691160065225467, - 949628319562187, - 275110186693066, - ]), - xy2d: FieldElement51([ - 1124515748676336, - 1661673816593408, - 1499640319059718, - 1584929449166988, - 558148594103306, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1784525599998356, - 1619698033617383, - 2097300287550715, - 2510065271789004, - 1905684794832757, - ]), - y_minus_x: FieldElement51([ - 1288941072872766, - 931787902039402, - 190731008859042, - 2006859954667190, - 1005931482221702, - ]), - xy2d: FieldElement51([ - 1465551264822703, - 152905080555927, - 680334307368453, - 173227184634745, - 666407097159852, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2111017076203943, - 3630560299479595, - 1248583954016455, - 3604089008549670, - 1895180776543895, - ]), - y_minus_x: FieldElement51([ - 171348223915638, - 662766099800389, - 462338943760497, - 466917763340314, - 656911292869115, - ]), - xy2d: FieldElement51([ - 488623681976577, - 866497561541722, - 1708105560937768, - 1673781214218839, - 1506146329818807, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2412225278142205, - 950394373239688, - 2682296937026182, - 711676555398831, - 320964687779005, - ]), - y_minus_x: FieldElement51([ - 988979367990485, - 1359729327576302, - 1301834257246029, - 294141160829308, - 29348272277475, - ]), - xy2d: FieldElement51([ - 1434382743317910, - 100082049942065, - 221102347892623, - 186982837860588, - 1305765053501834, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2205916462268190, - 2751663643476068, - 961960554686615, - 2409862576442233, - 1841471168298304, - ]), - y_minus_x: FieldElement51([ - 1191737341426592, - 1847042034978363, - 1382213545049056, - 1039952395710448, - 788812858896859, - ]), - xy2d: FieldElement51([ - 1346965964571152, - 1291881610839830, - 2142916164336056, - 786821641205979, - 1571709146321039, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 787164375951248, - 2454669019058437, - 3608390234717387, - 1431233331032509, - 786341368775957, - ]), - y_minus_x: FieldElement51([ - 492448143532951, - 304105152670757, - 1761767168301056, - 233782684697790, - 1981295323106089, - ]), - xy2d: FieldElement51([ - 665807507761866, - 1343384868355425, - 895831046139653, - 439338948736892, - 1986828765695105, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3007896024559801, - 1721699973539148, - 2510565115413133, - 1390588532210644, - 1212530909934781, - ]), - y_minus_x: FieldElement51([ - 852891097972275, - 1816988871354562, - 1543772755726524, - 1174710635522444, - 202129090724628, - ]), - xy2d: FieldElement51([ - 1205281565824323, - 22430498399418, - 992947814485516, - 1392458699738672, - 688441466734558, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3302427242100220, - 1955849529137134, - 2171162376368357, - 2343545681983462, - 447733118757825, - ]), - y_minus_x: FieldElement51([ - 1287181461435438, - 622722465530711, - 880952150571872, - 741035693459198, - 311565274989772, - ]), - xy2d: FieldElement51([ - 1003649078149734, - 545233927396469, - 1849786171789880, - 1318943684880434, - 280345687170552, - ]), - }, - ]), - ]); - -/// Odd multiples of the basepoint `[B, 3B, 5B, 7B, 9B, 11B, 13B, 15B, ..., 127B]`. -pub(crate) const AFFINE_ODD_MULTIPLES_OF_BASEPOINT: NafLookupTable8 = - NafLookupTable8([ - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3540182452943730, - 2497478415033846, - 2521227595762870, - 1462984067271729, - 2389212253076811, - ]), - y_minus_x: FieldElement51([ - 62697248952638, - 204681361388450, - 631292143396476, - 338455783676468, - 1213667448819585, - ]), - xy2d: FieldElement51([ - 301289933810280, - 1259582250014073, - 1422107436869536, - 796239922652654, - 1953934009299142, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1601611775252272, - 1720807796594148, - 1132070835939856, - 3512254832574799, - 2147779492816910, - ]), - y_minus_x: FieldElement51([ - 316559037616741, - 2177824224946892, - 1459442586438991, - 1461528397712656, - 751590696113597, - ]), - xy2d: FieldElement51([ - 1850748884277385, - 1200145853858453, - 1068094770532492, - 672251375690438, - 1586055907191707, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 769950342298400, - 2384754244604994, - 3095885746880802, - 3225892188161580, - 2977876099231263, - ]), - y_minus_x: FieldElement51([ - 425251763115706, - 608463272472562, - 442562545713235, - 837766094556764, - 374555092627893, - ]), - xy2d: FieldElement51([ - 1086255230780037, - 274979815921559, - 1960002765731872, - 929474102396301, - 1190409889297339, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2916800678241215, - 2065379846933858, - 2622030924071124, - 2602788184473875, - 1233371373142984, - ]), - y_minus_x: FieldElement51([ - 2019367628972465, - 676711900706637, - 110710997811333, - 1108646842542025, - 517791959672113, - ]), - xy2d: FieldElement51([ - 965130719900578, - 247011430587952, - 526356006571389, - 91986625355052, - 2157223321444601, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1802695059464988, - 1664899123557221, - 2845359304426105, - 2160434469266658, - 3179370264440279, - ]), - y_minus_x: FieldElement51([ - 1725674970513508, - 1933645953859181, - 1542344539275782, - 1767788773573747, - 1297447965928905, - ]), - xy2d: FieldElement51([ - 1381809363726107, - 1430341051343062, - 2061843536018959, - 1551778050872521, - 2036394857967624, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 4222693909998302, - 2779866139518454, - 1619374932191226, - 2207306624415883, - 1169170329061080, - ]), - y_minus_x: FieldElement51([ - 2070390218572616, - 1458919061857835, - 624171843017421, - 1055332792707765, - 433987520732508, - ]), - xy2d: FieldElement51([ - 893653801273833, - 1168026499324677, - 1242553501121234, - 1306366254304474, - 1086752658510815, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2465253816303469, - 3191571337672685, - 1159882208056013, - 2569188183312765, - 621213314200686, - ]), - y_minus_x: FieldElement51([ - 1971678598905747, - 338026507889165, - 762398079972271, - 655096486107477, - 42299032696322, - ]), - xy2d: FieldElement51([ - 177130678690680, - 1754759263300204, - 1864311296286618, - 1180675631479880, - 1292726903152791, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1913163449625248, - 2712579013977241, - 2193883288642313, - 1008900146920800, - 1721983679009502, - ]), - y_minus_x: FieldElement51([ - 1070401523076875, - 1272492007800961, - 1910153608563310, - 2075579521696771, - 1191169788841221, - ]), - xy2d: FieldElement51([ - 692896803108118, - 500174642072499, - 2068223309439677, - 1162190621851337, - 1426986007309901, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1819621230288238, - 2735700366193240, - 1755134670739586, - 3080648199451191, - 4172807995775876, - ]), - y_minus_x: FieldElement51([ - 992069868904071, - 799011518185730, - 1777586403832768, - 1134820506145684, - 1999461475558530, - ]), - xy2d: FieldElement51([ - 425204543703124, - 2040469794090382, - 1651690622153809, - 1500530168597569, - 1253908377065966, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2105824306960939, - 1387520302709358, - 3633176580451016, - 2211816663841753, - 1629085891776489, - ]), - y_minus_x: FieldElement51([ - 1485201376284999, - 1022406647424656, - 504181009209019, - 962621520820995, - 590876713147230, - ]), - xy2d: FieldElement51([ - 265873406365287, - 1192742653492898, - 88553098803050, - 525037770869640, - 1266933811251234, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3552316659826612, - 1254279525791875, - 1609927932077699, - 3578654071679972, - 3750681296069893, - ]), - y_minus_x: FieldElement51([ - 37186803519861, - 1404297334376301, - 578519728836650, - 1740727951192592, - 2095534282477028, - ]), - xy2d: FieldElement51([ - 833234263154399, - 2023862470013762, - 1854137933982069, - 853924318090959, - 1589812702805850, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3679150557957763, - 1319179453661745, - 497496853611112, - 2665464286942351, - 1208137952365560, - ]), - y_minus_x: FieldElement51([ - 1654513078530905, - 907489875842908, - 126098711296368, - 1726320004173677, - 28269495058173, - ]), - xy2d: FieldElement51([ - 114436686957443, - 532739313025996, - 115428841215897, - 2191499400074366, - 370280402676434, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1111146849833253, - 2016430049079759, - 1860522747477948, - 3537164738290194, - 4137142824844184, - ]), - y_minus_x: FieldElement51([ - 429069864577128, - 975327637149449, - 237881983565075, - 1654761232378630, - 2122527599091807, - ]), - xy2d: FieldElement51([ - 2093793463548278, - 754827233241879, - 1420389751719629, - 1829952782588138, - 2011865756773717, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 676293365438898, - 2850296017886344, - 1205350322490195, - 2763699392265669, - 2133931188538142, - ]), - y_minus_x: FieldElement51([ - 48340340349120, - 1299261101494832, - 1137329686775218, - 1534848106674340, - 1351662218216799, - ]), - xy2d: FieldElement51([ - 1904520614137939, - 1590301001714014, - 215781420985270, - 2043534301034629, - 1970888949300424, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2365217962409710, - 2061307169694064, - 1887478590157603, - 2169639621284316, - 2373810867477200, - ]), - y_minus_x: FieldElement51([ - 1020052624656948, - 1260412094216707, - 366721640607121, - 585331442306596, - 345876457758061, - ]), - xy2d: FieldElement51([ - 975390299880933, - 1066555195234642, - 12651997758352, - 1184252205433068, - 1058378155074223, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1431537716602643, - 2024827957433813, - 3746434518400495, - 1087794891033550, - 2156817571680455, - ]), - y_minus_x: FieldElement51([ - 929288033346881, - 255179964546973, - 711057989588035, - 208899572612840, - 185348357387383, - ]), - xy2d: FieldElement51([ - 823689746424808, - 47266130989546, - 209403309368097, - 1100966895202707, - 710792075292719, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2311213117823762, - 3296668540922318, - 2004276520649823, - 1861500579441125, - 3148029033359833, - ]), - y_minus_x: FieldElement51([ - 1563693677475261, - 1843782073741194, - 1950700654453170, - 911540858113949, - 2085151496302359, - ]), - xy2d: FieldElement51([ - 1427880892005482, - 106216431121745, - 42608394782284, - 1217295886989793, - 1514235272796882, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3544335535746750, - 2367994491347456, - 2567261456502612, - 1854058085060971, - 2263545563461076, - ]), - y_minus_x: FieldElement51([ - 787426011300053, - 2105981035769060, - 1130476291127206, - 1748659348100075, - 53470983013756, - ]), - xy2d: FieldElement51([ - 553548273865386, - 5927805718390, - 65184587381926, - 633576679686953, - 576048559439973, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 993787326657446, - 3868807161609258, - 1615796046728943, - 2514644292681953, - 2059021068660907, - ]), - y_minus_x: FieldElement51([ - 251010270518880, - 1681684095763484, - 1521949356387564, - 431593457045116, - 1855308922422910, - ]), - xy2d: FieldElement51([ - 618490909691959, - 1257497595618257, - 202952467594088, - 35577762721238, - 1494883566841973, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1673474571932262, - 2409784519770613, - 2636095316260487, - 2761112584601925, - 3333713288149876, - ]), - y_minus_x: FieldElement51([ - 1600640202645197, - 1019569075331823, - 1041916487915822, - 1680448171313267, - 2126903137527901, - ]), - xy2d: FieldElement51([ - 894964745143659, - 106116880092678, - 1009869382959477, - 317866368542032, - 1986983122763912, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1765281781276487, - 2863247187455184, - 2589075472439062, - 1386435905543054, - 2182338478845320, - ]), - y_minus_x: FieldElement51([ - 1144730936996693, - 2213315231278180, - 1489676672185125, - 665039429138074, - 1131283313040268, - ]), - xy2d: FieldElement51([ - 2004734176670602, - 1738311085075235, - 418866995976618, - 1050782508034394, - 577747313404652, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2185209688340293, - 1309276076461009, - 2514740038571278, - 3994889904012999, - 3018098826231021, - ]), - y_minus_x: FieldElement51([ - 1405936970888515, - 1754621155316654, - 1211862168554999, - 1813045702919083, - 997853418197172, - ]), - xy2d: FieldElement51([ - 82037622045021, - 1646398333621944, - 613095452763466, - 1312329542583705, - 81014679202721, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2389287991277873, - 403851022333257, - 1597473361477193, - 2953351602509212, - 2135174663049062, - ]), - y_minus_x: FieldElement51([ - 1826548187201150, - 302299893734126, - 1475477168615781, - 842617616347376, - 1438600873676130, - ]), - xy2d: FieldElement51([ - 663049852468609, - 1649295727846569, - 1048009692742781, - 628866177992421, - 1914360327429204, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1795645928096646, - 306878154408959, - 2924901319092394, - 2801261341654799, - 1653782432983523, - ]), - y_minus_x: FieldElement51([ - 2077597317438627, - 212642017882064, - 674844477518888, - 875487498687554, - 2060550250171182, - ]), - xy2d: FieldElement51([ - 1420448018683809, - 1032663994771382, - 1341927003385267, - 1340360916546159, - 1988547473895228, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1082660122598844, - 2545055705583789, - 3888919679589007, - 1670283344995811, - 3403239134794618, - ]), - y_minus_x: FieldElement51([ - 90430593339788, - 1838338032241275, - 571293238480915, - 1639938867416883, - 257378872001111, - ]), - xy2d: FieldElement51([ - 1528535658865034, - 1516636853043960, - 787000569996728, - 1464531394704506, - 1684822625133795, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 811329918113934, - 2783463529007378, - 1769095754634835, - 2970819621866866, - 881037178164325, - ]), - y_minus_x: FieldElement51([ - 1784566501964517, - 433890943689325, - 1186055625589419, - 1496077405487512, - 1731807117886548, - ]), - xy2d: FieldElement51([ - 424909811816304, - 1355993963741797, - 409606483251841, - 455665350637068, - 1617009023642808, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2478728492077816, - 2780289048655501, - 2328687177473769, - 4107341333582032, - 1316147724308250, - ]), - y_minus_x: FieldElement51([ - 1617420574301156, - 1741273341070467, - 667135503486508, - 2100436564640123, - 1032223920000865, - ]), - xy2d: FieldElement51([ - 1753947659404033, - 247279202390193, - 1819288880178945, - 737334285670249, - 1037873664856104, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1762568490530034, - 673742465299012, - 2054571050635888, - 2040165159255111, - 3040123733327257, - ]), - y_minus_x: FieldElement51([ - 1627187989987422, - 1686331580821752, - 1309895873498183, - 719718719104086, - 300063199808722, - ]), - xy2d: FieldElement51([ - 238176707016164, - 1440454788877048, - 203336037573144, - 1437789888677072, - 101522256664211, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1895216760098480, - 1934324337975022, - 3677350688973167, - 2536415965456176, - 714678003308640, - ]), - y_minus_x: FieldElement51([ - 508185358728815, - 1691320535341855, - 2168887448239256, - 1035124393070661, - 1936603999698584, - ]), - xy2d: FieldElement51([ - 390562831571647, - 1390223890708972, - 1383183990676371, - 435998174196410, - 1882086414390730, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3747620842612921, - 2081794785291195, - 3284594056262745, - 2090090346797895, - 2581692978935809, - ]), - y_minus_x: FieldElement51([ - 244144781251265, - 1290834426417077, - 1888701171101942, - 1233922456644870, - 241117402207491, - ]), - xy2d: FieldElement51([ - 1266169390045455, - 1148042013187970, - 878921907853942, - 1815738019658093, - 908920199341621, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2521768507305118, - 953557056811112, - 2015863732865770, - 1358382511861315, - 2835421647899992, - ]), - y_minus_x: FieldElement51([ - 2239837206240498, - 330928973149665, - 422268062913642, - 1481280019493032, - 619879520439841, - ]), - xy2d: FieldElement51([ - 1360166735366017, - 1770556573948510, - 1395061284191031, - 1814003148068126, - 522781147076884, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2611794802645686, - 707234844948070, - 1314059396506491, - 2919250341703934, - 2161831667832785, - ]), - y_minus_x: FieldElement51([ - 934831784182383, - 433734253968318, - 1660867106725771, - 1968393082772831, - 873946300968490, - ]), - xy2d: FieldElement51([ - 26306827827554, - 430884999378685, - 1504310424376419, - 1761358720837522, - 542195685418530, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1762131062631725, - 3123952634417535, - 3619918390837537, - 2909990877347294, - 1411594230004385, - ]), - y_minus_x: FieldElement51([ - 538272372224622, - 1425714779586199, - 588313661410172, - 1497062084392578, - 1602174047128512, - ]), - xy2d: FieldElement51([ - 907490361939255, - 1963620338391363, - 626927432296975, - 1250748516081414, - 959901171882527, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1335066153744413, - 2887804660779657, - 2653073855954038, - 2765226981667422, - 938831784476763, - ]), - y_minus_x: FieldElement51([ - 296699434737224, - 2047543711075683, - 2076451038937139, - 227783599906901, - 1602062110967627, - ]), - xy2d: FieldElement51([ - 1574834773194203, - 1384279952062839, - 393652417255803, - 2166968242848859, - 1552890441390820, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1619646774410947, - 1576090644023562, - 3035228391320965, - 1735328519940543, - 2355324535937066, - ]), - y_minus_x: FieldElement51([ - 1024074573633446, - 957088456885874, - 1690425531356997, - 2102187380180052, - 1082544623222033, - ]), - xy2d: FieldElement51([ - 1871906170635853, - 1719383891167200, - 1584032250247862, - 823764804192117, - 2244048510084261, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 642147846489775, - 3334304977145699, - 305205716788147, - 2589176626729533, - 2224680511484174, - ]), - y_minus_x: FieldElement51([ - 1734162377166545, - 260713621840346, - 157174591942595, - 952544272517991, - 222818702471733, - ]), - xy2d: FieldElement51([ - 1213115494182947, - 286778704335711, - 2130189536016490, - 308349182281342, - 1217623948685491, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3360052266973635, - 1843486583624091, - 1561693837124349, - 1084041964025479, - 1866270922024009, - ]), - y_minus_x: FieldElement51([ - 460705465481210, - 1968151453817859, - 497005926994844, - 625618055866751, - 2176893440866887, - ]), - xy2d: FieldElement51([ - 1655800250476757, - 2036588542300609, - 666447448675243, - 1615721995750683, - 1508669225186765, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2245948203759141, - 1058306669699396, - 1452898014240582, - 3961024141962768, - 1633235287338608, - ]), - y_minus_x: FieldElement51([ - 986647273684279, - 1507266907811370, - 1260572633649005, - 2071672342077446, - 695976026010857, - ]), - xy2d: FieldElement51([ - 1312356620823495, - 1635278548098567, - 901946076841033, - 585120475533168, - 1240667113237384, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2313723935779695, - 1506054666773895, - 996040223525031, - 636592914999692, - 1497801917020297, - ]), - y_minus_x: FieldElement51([ - 292042016419794, - 1158932298133044, - 2062611870323738, - 1946058478962569, - 1749165808126286, - ]), - xy2d: FieldElement51([ - 654683942212830, - 1526897351349087, - 2006818439922838, - 2194919327350361, - 1451960776874416, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3015041017808905, - 2951823141773809, - 2584865668253675, - 2508192032998563, - 2582137700042019, - ]), - y_minus_x: FieldElement51([ - 1628123495344283, - 2072923641214546, - 1647225812023982, - 855655925244679, - 1758126430071140, - ]), - xy2d: FieldElement51([ - 1615895096489599, - 275295258643784, - 937665541219916, - 1313496726746346, - 1186468946422626, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1603070202850694, - 2072127623773242, - 1692648737212158, - 2493373404187852, - 1248948672117105, - ]), - y_minus_x: FieldElement51([ - 11167836031898, - 596565174397990, - 2196351068723859, - 314744641791907, - 1102014997250781, - ]), - xy2d: FieldElement51([ - 1409047922401191, - 69960384467966, - 688103515547600, - 1309746102488044, - 150292892873778, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1986083055103168, - 691715819340300, - 1361811659746933, - 3459052030333434, - 1063594696046061, - ]), - y_minus_x: FieldElement51([ - 1201987338414749, - 2198784582460616, - 1203335513981498, - 489243077045066, - 2205278143582433, - ]), - xy2d: FieldElement51([ - 2034744376624534, - 2077387101466387, - 148448542974969, - 1502697574577258, - 473186584705655, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 472016956315960, - 720786972252993, - 2840633661190043, - 3150798753357827, - 2816563335499153, - ]), - y_minus_x: FieldElement51([ - 253464247569755, - 168314237403057, - 511780806170295, - 1058862316549135, - 1646858476817137, - ]), - xy2d: FieldElement51([ - 595092995922219, - 1491311840717691, - 291581784452778, - 1569186646367854, - 1031385061400544, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3483137021572755, - 1526955102024322, - 2778006642704458, - 457549634924205, - 1097420237736736, - ]), - y_minus_x: FieldElement51([ - 1246991699537710, - 81367319519439, - 530844036072196, - 163656863755855, - 1950742455979290, - ]), - xy2d: FieldElement51([ - 191532664076407, - 539378506082089, - 1021612562876554, - 1026603384732632, - 1773368780410653, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 4144620731387879, - 590179521333342, - 4034023318016108, - 2255745030335426, - 2699746851701250, - ]), - y_minus_x: FieldElement51([ - 2206599697359952, - 553895797384417, - 181689161933786, - 1153123447919104, - 778568064152659, - ]), - xy2d: FieldElement51([ - 1706307000059211, - 1885601289314487, - 889758608505788, - 550131729999853, - 1006862664714268, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3210197754285058, - 2048500453422630, - 3403309827888207, - 927154428508963, - 4199813798872019, - ]), - y_minus_x: FieldElement51([ - 992058915374933, - 476120535358775, - 1973648780784340, - 2025282643598818, - 2182318983793230, - ]), - xy2d: FieldElement51([ - 1343440812005821, - 1316045839091795, - 1884951299078063, - 1765919609219175, - 2197567554627988, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3129247779382818, - 4415026969054274, - 1900265885969643, - 1528796215447059, - 2172730393748688, - ]), - y_minus_x: FieldElement51([ - 1773355092297603, - 64654329538271, - 1332124041660957, - 748492100858001, - 895500006200535, - ]), - xy2d: FieldElement51([ - 2000840647851980, - 546565968824914, - 420633283457524, - 195470736374507, - 1958689297569520, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 743138980705446, - 3411117504637167, - 2591389959690621, - 2380042066577202, - 3022267940115114, - ]), - y_minus_x: FieldElement51([ - 165947002229363, - 115186103724967, - 1068573292121517, - 1842565776920938, - 1969395681111987, - ]), - xy2d: FieldElement51([ - 553322266190633, - 234265665613185, - 484544650202821, - 1238773526575826, - 2017991917953668, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2581954631514051, - 1245093644265357, - 3537016673825374, - 1834216551713857, - 923978372152807, - ]), - y_minus_x: FieldElement51([ - 1855378315339552, - 890045579230758, - 1764718173975590, - 197904186055854, - 1718129022310327, - ]), - xy2d: FieldElement51([ - 1278162928734862, - 1894118254109862, - 987503995465517, - 177406744098996, - 781538103127693, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1996603431230215, - 1191888797552937, - 1207440075928499, - 2765853449051137, - 2525314961343288, - ]), - y_minus_x: FieldElement51([ - 808903879370889, - 990820108751280, - 1084429472258867, - 1078562781312589, - 254514692695625, - ]), - xy2d: FieldElement51([ - 615855140068469, - 586046731175395, - 693470779212674, - 1964537100203868, - 1350330550265229, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3344544372023708, - 720386671449874, - 2480841360702110, - 2036034126860286, - 2015744690201389, - ]), - y_minus_x: FieldElement51([ - 1337446193390478, - 1984110761311871, - 746489405020285, - 407347127604128, - 1740475330360596, - ]), - xy2d: FieldElement51([ - 140840424783613, - 1063284623568331, - 1136446106453878, - 372042229029799, - 442607248430694, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2330781679120937, - 376801425148230, - 2032603686676107, - 1488926293635130, - 1317278311532959, - ]), - y_minus_x: FieldElement51([ - 1290116731380016, - 2166899563471713, - 831997001838078, - 870954980505220, - 2108537278055823, - ]), - xy2d: FieldElement51([ - 1912719171026343, - 846194720551034, - 2043988124740726, - 993234269653961, - 421229796383281, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2651184584992902, - 2775702557638963, - 2539786009779572, - 2575974880015305, - 2122619079836732, - ]), - y_minus_x: FieldElement51([ - 1154054290132562, - 931753998725577, - 1647742001778052, - 865765466488226, - 1083816107290025, - ]), - xy2d: FieldElement51([ - 986341121095108, - 1522330369638573, - 1990880546211047, - 501525962272123, - 198539304862139, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1496414019192687, - 3991034436173951, - 3380311659062196, - 2854747485359158, - 3346958036643152, - ]), - y_minus_x: FieldElement51([ - 805612068303425, - 1891790027761335, - 1587008567571549, - 722120737390201, - 378156757163816, - ]), - xy2d: FieldElement51([ - 1588994517921951, - 977362751042302, - 1329302387067714, - 2069348224564088, - 1586007159625211, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2490539421551682, - 1985699850375015, - 2331762317128172, - 4145097393776678, - 2521049460190674, - ]), - y_minus_x: FieldElement51([ - 615817553313996, - 2245962768078178, - 482564324326173, - 2101336843140780, - 1240914880829407, - ]), - xy2d: FieldElement51([ - 1438242482238189, - 874267817785463, - 1620810389770625, - 866155221338671, - 1040426546798301, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 2403083624110300, - 2548561409802975, - 2492699136535911, - 2358289519456539, - 3203964320363148, - ]), - y_minus_x: FieldElement51([ - 1913986535403097, - 1977163223054199, - 1972905914623196, - 1650122133472502, - 1905849310819035, - ]), - xy2d: FieldElement51([ - 858174816360838, - 614595356564037, - 1099584959044836, - 636998087084906, - 1070393269058348, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3666695924830668, - 3585640662737501, - 2372994528684236, - 2628565977288995, - 3482812783469694, - ]), - y_minus_x: FieldElement51([ - 1994161359147952, - 2198039369802658, - 62790022842537, - 1522306785848169, - 951223194802833, - ]), - xy2d: FieldElement51([ - 852296621440717, - 431889737774209, - 370755457746189, - 437604073958073, - 627857326892757, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1794955764684156, - 2586904290013612, - 1322647643615887, - 856117964085888, - 2652432778663153, - ]), - y_minus_x: FieldElement51([ - 933592377399646, - 78031722952813, - 926049890685253, - 1471649501316246, - 33789909190376, - ]), - xy2d: FieldElement51([ - 1479319468832059, - 203906207621608, - 659828362330083, - 44358398435755, - 1273573524210803, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1592342143350813, - 3227219208247713, - 2345240352078765, - 2577750109932929, - 2933512841197243, - ]), - y_minus_x: FieldElement51([ - 2184946892642995, - 1517382324576002, - 1557940277419806, - 2170635134813213, - 747314658627002, - ]), - xy2d: FieldElement51([ - 1823193620577742, - 1135817878516419, - 1731253819308581, - 1031652967267804, - 2123506616999453, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1346190246005805, - 2052692552023851, - 1718128041785940, - 2491557332978474, - 3474370880388305, - ]), - y_minus_x: FieldElement51([ - 424776012994573, - 281050757243423, - 626466040846420, - 990194703866532, - 38571969885982, - ]), - xy2d: FieldElement51([ - 192408346595466, - 1054889725292349, - 584097975693004, - 1447909807397749, - 2134645004369136, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3169895788615063, - 3503097743181446, - 601598510029975, - 1422812237223371, - 2121009661378329, - ]), - y_minus_x: FieldElement51([ - 1603348391996783, - 2066143816131699, - 1789627290363958, - 2145705961178118, - 1985578641438222, - ]), - xy2d: FieldElement51([ - 352633958653380, - 856927627345554, - 793925083122702, - 93551575767286, - 1222010153634215, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1756866499986349, - 911731956999969, - 2707505543214075, - 4006920335263786, - 822501008147910, - ]), - y_minus_x: FieldElement51([ - 1094036422864347, - 1897208881572508, - 1503607738246960, - 1901060196071406, - 294068411105729, - ]), - xy2d: FieldElement51([ - 587776484399576, - 1116861711228807, - 343398777436088, - 936544065763093, - 1643746750211060, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 3477749685790410, - 267997399528836, - 2953780922004404, - 3252368924080907, - 3787792887348381, - ]), - y_minus_x: FieldElement51([ - 2042368155872443, - 41662387210459, - 1676313264498480, - 1333968523426810, - 1765708383352310, - ]), - xy2d: FieldElement51([ - 1453394896690938, - 1585795827439909, - 1469309456804303, - 1294645324464404, - 2042954198665899, - ]), - }, - AffineNielsPoint { - y_plus_x: FieldElement51([ - 1810069207599881, - 1358344669503239, - 1989371257548167, - 2316270051121225, - 3019675451276507, - ]), - y_minus_x: FieldElement51([ - 1866114438287676, - 1663420339568364, - 1437691317033088, - 538298302628038, - 1212711449614363, - ]), - xy2d: FieldElement51([ - 1769235035677897, - 1562012115317882, - 31277513664750, - 536198657928416, - 1976134212537183, - ]), - }, - ]); diff --git a/src/backend/vector/avx2/constants.rs b/src/backend/vector/avx2/constants.rs deleted file mode 100644 index 122068e31..000000000 --- a/src/backend/vector/avx2/constants.rs +++ /dev/null @@ -1,3428 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! This module contains constants used by the AVX2 backend. - -use packed_simd::u32x8; - -use backend::vector::avx2::edwards::{CachedPoint, ExtendedPoint}; -use backend::vector::avx2::field::FieldElement2625x4; -use window::NafLookupTable8; - -/// The identity element as an `ExtendedPoint`. -pub(crate) static EXTENDEDPOINT_IDENTITY: ExtendedPoint = ExtendedPoint(FieldElement2625x4([ - u32x8::new(0, 1, 0, 0, 1, 0, 0, 0), - u32x8::splat(0), - u32x8::splat(0), - u32x8::splat(0), - u32x8::splat(0), -])); - -/// The identity element as a `CachedPoint`. -pub(crate) static CACHEDPOINT_IDENTITY: CachedPoint = CachedPoint(FieldElement2625x4([ - u32x8::new(121647, 121666, 0, 0, 243332, 67108845, 0, 33554431), - u32x8::new(67108864, 0, 33554431, 0, 0, 67108863, 0, 33554431), - u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), - u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), - u32x8::new(67108863, 0, 33554431, 0, 0, 67108863, 0, 33554431), -])); - -/// The low limbs of (2p, 2p, 2p, 2p), so that -/// ```ascii,no_run -/// (2p, 2p, 2p, 2p) = [P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI] -/// ``` -pub(crate) static P_TIMES_2_LO: u32x8 = u32x8::new( - 67108845 << 1, - 67108845 << 1, - 33554431 << 1, - 33554431 << 1, - 67108845 << 1, - 67108845 << 1, - 33554431 << 1, - 33554431 << 1, -); - -/// The high limbs of (2p, 2p, 2p, 2p), so that -/// ```ascii,no_run -/// (2p, 2p, 2p, 2p) = [P_TIMES_2_LO, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI, P_TIMES_2_HI] -/// ``` -pub(crate) static P_TIMES_2_HI: u32x8 = u32x8::new( - 67108863 << 1, - 67108863 << 1, - 33554431 << 1, - 33554431 << 1, - 67108863 << 1, - 67108863 << 1, - 33554431 << 1, - 33554431 << 1, -); - -/// The low limbs of (16p, 16p, 16p, 16p), so that -/// ```ascii,no_run -/// (16p, 16p, 16p, 16p) = [P_TIMES_16_LO, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI] -/// ``` -pub(crate) static P_TIMES_16_LO: u32x8 = u32x8::new( - 67108845 << 4, - 67108845 << 4, - 33554431 << 4, - 33554431 << 4, - 67108845 << 4, - 67108845 << 4, - 33554431 << 4, - 33554431 << 4, -); - -/// The high limbs of (16p, 16p, 16p, 16p), so that -/// ```ascii,no_run -/// (16p, 16p, 16p, 16p) = [P_TIMES_16_LO, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI, P_TIMES_16_HI] -/// ``` -pub(crate) static P_TIMES_16_HI: u32x8 = u32x8::new( - 67108863 << 4, - 67108863 << 4, - 33554431 << 4, - 33554431 << 4, - 67108863 << 4, - 67108863 << 4, - 33554431 << 4, - 33554431 << 4, -); - -/// Odd multiples of the Ed25519 basepoint: -pub(crate) static BASEPOINT_ODD_LOOKUP_TABLE: NafLookupTable8 = NafLookupTable8([ - CachedPoint(FieldElement2625x4([ - u32x8::new( - 3571425, - 10045002, - 19036563, - 1096096, - 243332, - 65897020, - 0, - 28963681, - ), - u32x8::new( - 30896895, - 63055514, - 1614915, - 5095970, - 0, - 53791688, - 0, - 31258312, - ), - u32x8::new( - 13347627, - 40339464, - 2236269, - 11185503, - 0, - 22520087, - 0, - 8659512, - ), - u32x8::new( - 11125413, - 29139905, - 32037254, - 28360723, - 0, - 64556417, - 0, - 9635759, - ), - u32x8::new( - 33268144, - 47262491, - 4336918, - 15795740, - 0, - 22027545, - 0, - 4846528, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 47099681, - 31447946, - 29365447, - 24740513, - 42991046, - 18317844, - 16051644, - 21404226, - ), - u32x8::new( - 31708133, - 28909527, - 2366091, - 13703791, - 469246, - 54159622, - 2601402, - 32988002, - ), - u32x8::new( - 63432457, - 30251794, - 15163516, - 18491340, - 28144087, - 35605455, - 13682295, - 18474872, - ), - u32x8::new( - 12221607, - 4967598, - 26061980, - 26008006, - 20226147, - 9726961, - 17410, - 18051083, - ), - u32x8::new( - 60569645, - 62487085, - 11911242, - 21920922, - 4092105, - 38186967, - 22431483, - 31366585, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 18147205, - 62587998, - 2554617, - 536692, - 11924528, - 26674131, - 17645433, - 24341419, - ), - u32x8::new( - 11573357, - 27579485, - 31491870, - 29000885, - 10800976, - 51902791, - 28076395, - 20464029, - ), - u32x8::new( - 56031649, - 10856669, - 11791193, - 26769430, - 25306956, - 5922200, - 6630685, - 9385098, - ), - u32x8::new( - 31319348, - 23906711, - 16290213, - 32142166, - 61106354, - 17181823, - 3548308, - 12022566, - ), - u32x8::new( - 5904298, - 50218605, - 11826440, - 5492249, - 10379071, - 3472255, - 172742, - 31948344, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 10625852, - 15193821, - 22918394, - 23676410, - 53695416, - 54987793, - 10067515, - 11747680, - ), - u32x8::new( - 65013325, - 1309652, - 29616320, - 28922974, - 60360891, - 19621771, - 9938982, - 30406429, - ), - u32x8::new( - 54967954, - 65931918, - 5595602, - 25719523, - 64909864, - 30566415, - 15945272, - 8495317, - ), - u32x8::new( - 1167157, - 55265018, - 11507029, - 31641054, - 43497904, - 2367338, - 12937761, - 27517066, - ), - u32x8::new( - 656704, - 2544994, - 13006713, - 480979, - 38471594, - 62541240, - 25353597, - 11531760, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 22176662, - 3984313, - 27495285, - 4110608, - 2909584, - 30594106, - 15677919, - 2549183, - ), - u32x8::new( - 33979105, - 62269905, - 2071511, - 6894756, - 53189950, - 47232857, - 6408191, - 6123225, - ), - u32x8::new( - 32553873, - 63948030, - 12612401, - 3633166, - 24054373, - 37626618, - 14481327, - 8520484, - ), - u32x8::new( - 56552486, - 10749438, - 12034813, - 28811946, - 1445640, - 36755601, - 12104575, - 10257833, - ), - u32x8::new( - 22795808, - 48761311, - 1136056, - 9380768, - 1411523, - 5341811, - 27318329, - 9686767, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 21157200, - 39156966, - 20473176, - 4934657, - 61478183, - 45121537, - 5429856, - 13035023, - ), - u32x8::new( - 7954529, - 58789246, - 31440083, - 7054221, - 38438565, - 36856107, - 1364112, - 14548122, - ), - u32x8::new( - 26120083, - 36321360, - 4919997, - 31687496, - 33757765, - 36237559, - 15243054, - 32163861, - ), - u32x8::new( - 25878307, - 46544824, - 19455951, - 2414935, - 16844726, - 56521560, - 32680554, - 26660660, - ), - u32x8::new( - 48360220, - 43407178, - 12187042, - 24925816, - 7423722, - 25746484, - 12814654, - 17395963, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 63153652, - 32195955, - 4087908, - 8431689, - 30392384, - 47203165, - 8986649, - 9053039, - ), - u32x8::new( - 63659241, - 47988767, - 2931872, - 19953600, - 11747107, - 51610101, - 20952181, - 13364887, - ), - u32x8::new( - 3659197, - 58790649, - 5930099, - 2605312, - 28477896, - 580728, - 20579735, - 2610622, - ), - u32x8::new( - 41781607, - 17161358, - 10690531, - 24368015, - 47027031, - 36742339, - 5414694, - 13156365, - ), - u32x8::new( - 13237853, - 51182423, - 8954802, - 29006542, - 22643989, - 56896541, - 22830593, - 10289708, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 1401265, - 58846825, - 30911620, - 32239180, - 15391552, - 15200821, - 6339309, - 16403588, - ), - u32x8::new( - 55913797, - 29541724, - 1664461, - 21709410, - 38470488, - 47097092, - 17674945, - 32666066, - ), - u32x8::new( - 22844482, - 10797709, - 27548106, - 31638735, - 34500968, - 26611503, - 19727211, - 13160873, - ), - u32x8::new( - 31485204, - 14496164, - 13981208, - 10276888, - 5748808, - 35024436, - 2740987, - 7479021, - ), - u32x8::new( - 58541207, - 14866135, - 32344041, - 545930, - 62661488, - 6941250, - 27940205, - 11976112, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 39849808, - 44781685, - 15697329, - 24387845, - 12501486, - 50260092, - 23199481, - 31929024, - ), - u32x8::new( - 24823070, - 27956017, - 27034296, - 10316465, - 47664045, - 11152446, - 15719183, - 30181617, - ), - u32x8::new( - 20771189, - 19969144, - 31433937, - 19185213, - 27565920, - 10384445, - 2893359, - 9255362, - ), - u32x8::new( - 42894974, - 11925545, - 32134441, - 32738810, - 55916336, - 32479272, - 19563550, - 5511385, - ), - u32x8::new( - 17857161, - 47809169, - 14564114, - 27997751, - 33024640, - 38669671, - 31956536, - 27313245, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 58237774, - 15917425, - 18872208, - 19394230, - 17374297, - 6101419, - 4839741, - 6596900, - ), - u32x8::new( - 66947393, - 15744215, - 18368993, - 17750160, - 41006525, - 9205497, - 2629667, - 32170865, - ), - u32x8::new( - 66481381, - 1919414, - 28338762, - 7372967, - 33819153, - 4156199, - 27126309, - 12739816, - ), - u32x8::new( - 44117158, - 58545296, - 22521371, - 11809712, - 28998792, - 50731010, - 30215699, - 25748377, - ), - u32x8::new( - 23561284, - 4160244, - 9035405, - 24895184, - 39761639, - 59253416, - 8684759, - 22487864, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 12671134, - 56419053, - 16092401, - 30038207, - 4002647, - 47822606, - 7151311, - 28430768, - ), - u32x8::new( - 61041684, - 35765374, - 30598048, - 19666539, - 44150175, - 40140037, - 290469, - 28442674, - ), - u32x8::new( - 18847796, - 1371617, - 33316881, - 13199936, - 43646578, - 17068881, - 12074900, - 1537415, - ), - u32x8::new( - 10052225, - 38316070, - 27469797, - 5297537, - 50725570, - 20435349, - 10339121, - 2779737, - ), - u32x8::new( - 18372189, - 15466385, - 24762130, - 22217964, - 23503887, - 47844464, - 10415034, - 2606889, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 55082775, - 45300503, - 16032654, - 5964396, - 17743504, - 24634761, - 19493066, - 5184611, - ), - u32x8::new( - 50172633, - 35093294, - 10040575, - 23616256, - 4543900, - 61852191, - 4049821, - 7423669, - ), - u32x8::new( - 20295398, - 40009376, - 10487190, - 15670429, - 51972856, - 58649552, - 20436392, - 3432497, - ), - u32x8::new( - 35189420, - 54117751, - 12825868, - 6283038, - 27540739, - 30648758, - 22658912, - 9466689, - ), - u32x8::new( - 51737549, - 40725785, - 17409814, - 25201086, - 21156239, - 34176168, - 26814520, - 5956424, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 8211442, - 8014184, - 6260823, - 22108096, - 32182620, - 51844847, - 2466270, - 28582231, - ), - u32x8::new( - 27199739, - 3848333, - 31738017, - 10892045, - 4963982, - 65391770, - 32551997, - 28906469, - ), - u32x8::new( - 16606846, - 32207068, - 26404535, - 7614129, - 45416902, - 65584718, - 13821785, - 2646060, - ), - u32x8::new( - 36090634, - 57981287, - 32247670, - 22837502, - 31003861, - 55448117, - 6062915, - 20369975, - ), - u32x8::new( - 27381403, - 50578107, - 522631, - 29521058, - 31137497, - 40220737, - 27628049, - 1824195, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 59402443, - 17056879, - 29262689, - 6131785, - 52551472, - 43367471, - 29423199, - 18899208, - ), - u32x8::new( - 5749414, - 43514612, - 11365899, - 21514624, - 65591890, - 60945892, - 19841732, - 5628567, - ), - u32x8::new( - 19334369, - 52500268, - 12307673, - 5267367, - 3212103, - 9035822, - 29142161, - 30520954, - ), - u32x8::new( - 57261330, - 6819646, - 22089161, - 9800373, - 55155453, - 62250856, - 13766735, - 25244545, - ), - u32x8::new( - 54370226, - 61888301, - 24496089, - 2540581, - 65637506, - 60274355, - 18154273, - 11687259, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 12521903, - 26014045, - 13995625, - 33360175, - 23605474, - 7376434, - 27229267, - 17195036, - ), - u32x8::new( - 59482891, - 10074423, - 574357, - 3857753, - 61377787, - 50306685, - 5241065, - 20234396, - ), - u32x8::new( - 23674717, - 6997172, - 20771841, - 16858511, - 40565304, - 29973136, - 7049812, - 14585010, - ), - u32x8::new( - 1427477, - 13295732, - 31762066, - 31499740, - 60419925, - 54666164, - 22009424, - 8089609, - ), - u32x8::new( - 58154031, - 41593020, - 15342328, - 957047, - 38937260, - 37037498, - 24871992, - 32973409, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 30654745, - 51286025, - 21206982, - 2433562, - 12780105, - 31732574, - 33087964, - 33081189, - ), - u32x8::new( - 66640017, - 42720009, - 16567620, - 15300745, - 1530367, - 33001123, - 20930247, - 21042661, - ), - u32x8::new( - 15003356, - 5294119, - 22985605, - 18928772, - 32628461, - 18230172, - 14773298, - 27193722, - ), - u32x8::new( - 27555, - 65346287, - 17017174, - 7837720, - 21499787, - 42855613, - 22474984, - 13675085, - ), - u32x8::new( - 24164369, - 50130116, - 5973149, - 24152073, - 1577334, - 25400030, - 18648484, - 32228854, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 49518649, - 59119280, - 31670678, - 20396561, - 61728330, - 651402, - 176032, - 9529498, - ), - u32x8::new( - 61765532, - 9082232, - 32794568, - 15526956, - 48543100, - 32614212, - 19001206, - 25680229, - ), - u32x8::new( - 32086091, - 10373081, - 8996131, - 31822823, - 35788988, - 49973190, - 30542040, - 17858455, - ), - u32x8::new( - 48130197, - 58121889, - 27753291, - 29923268, - 54448075, - 43300790, - 9336565, - 15770022, - ), - u32x8::new( - 57725546, - 20557498, - 9366233, - 16023566, - 16189031, - 2837363, - 24315301, - 27003505, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 28286608, - 10767548, - 18220739, - 5413236, - 48253387, - 58255702, - 11864864, - 28527159, - ), - u32x8::new( - 45038176, - 58655197, - 25648758, - 10951484, - 42564382, - 34542843, - 23146954, - 22234334, - ), - u32x8::new( - 14858710, - 24978793, - 15040559, - 4379220, - 47621477, - 40271440, - 15650420, - 1998736, - ), - u32x8::new( - 24106391, - 9626149, - 344505, - 25253814, - 34579800, - 59687089, - 25718289, - 25904133, - ), - u32x8::new( - 1981195, - 37751302, - 26132048, - 1764722, - 13288231, - 28808622, - 12531301, - 18292949, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 13869851, - 31448904, - 14963539, - 7581293, - 20536485, - 35021083, - 21257574, - 33356609, - ), - u32x8::new( - 36903364, - 18429241, - 11097857, - 5943856, - 60583077, - 40015815, - 30509523, - 31915271, - ), - u32x8::new( - 49161801, - 40681915, - 67892, - 25454357, - 22779677, - 25798439, - 15964829, - 5863227, - ), - u32x8::new( - 60810637, - 4496471, - 5217137, - 14095116, - 50942411, - 50712663, - 2507380, - 26844507, - ), - u32x8::new( - 34579752, - 53519385, - 10859797, - 18816024, - 42552864, - 39478521, - 6783896, - 17277037, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 43287109, - 27900723, - 33182187, - 2766754, - 17041989, - 1018260, - 33392790, - 4830032, - ), - u32x8::new( - 60194178, - 30788903, - 24728888, - 14513195, - 20897010, - 28843233, - 20111980, - 17475240, - ), - u32x8::new( - 46042274, - 19257042, - 4628173, - 31649727, - 27388316, - 66631493, - 11541886, - 6408028, - ), - u32x8::new( - 57024680, - 49536568, - 32050358, - 31321917, - 17437691, - 49672356, - 2884755, - 20493991, - ), - u32x8::new( - 59553007, - 46782643, - 29001173, - 1814088, - 21930692, - 51319706, - 14965872, - 30748046, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 16441817, - 36111849, - 6900424, - 602234, - 46522199, - 16441484, - 8135070, - 21726541, - ), - u32x8::new( - 37711225, - 32701959, - 11679112, - 13125533, - 32154135, - 9407918, - 26554289, - 620848, - ), - u32x8::new( - 19233407, - 30086864, - 14679568, - 2797374, - 4892806, - 7993077, - 247658, - 5632804, - ), - u32x8::new( - 37427262, - 26675495, - 27125659, - 13496131, - 50718473, - 40115609, - 28505351, - 27837393, - ), - u32x8::new( - 196819, - 18410429, - 7070012, - 21691388, - 29763371, - 24754123, - 9727048, - 10930179, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 28319289, - 40734650, - 16225680, - 24739184, - 64272368, - 35356897, - 7866648, - 13635853, - ), - u32x8::new( - 34165295, - 48328447, - 27041670, - 23643655, - 48949950, - 52963288, - 30411133, - 6045174, - ), - u32x8::new( - 18583559, - 41649834, - 9813585, - 26098520, - 25682734, - 26733526, - 19276490, - 10654728, - ), - u32x8::new( - 34867476, - 52715968, - 5694571, - 13380978, - 15134994, - 1831255, - 8608001, - 17266401, - ), - u32x8::new( - 59925903, - 44282172, - 27802465, - 1855069, - 14234749, - 36635487, - 11302294, - 10938429, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 8373273, - 49064494, - 4932071, - 32997499, - 38472880, - 29335908, - 14504412, - 22460029, - ), - u32x8::new( - 31795930, - 50785923, - 25835990, - 25790073, - 65669841, - 11360450, - 9969157, - 9008164, - ), - u32x8::new( - 50262498, - 45869261, - 16124434, - 15336007, - 882762, - 42522623, - 11277198, - 26296377, - ), - u32x8::new( - 42332732, - 59129236, - 14452816, - 567985, - 208061, - 34722729, - 32008143, - 14828749, - ), - u32x8::new( - 17937794, - 36846032, - 32102665, - 4442466, - 19745435, - 31633451, - 7146411, - 15812027, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 30741269, - 38648744, - 12562645, - 30092623, - 25073992, - 28730659, - 27911745, - 30000958, - ), - u32x8::new( - 2859794, - 25991700, - 17776078, - 27091930, - 2328322, - 60061146, - 18581824, - 18039008, - ), - u32x8::new( - 58206333, - 17917354, - 1972306, - 11853766, - 2655376, - 60543390, - 18416710, - 13287440, - ), - u32x8::new( - 62746330, - 61423885, - 21246577, - 2266675, - 60099139, - 14804707, - 14772234, - 20679434, - ), - u32x8::new( - 26987698, - 15488817, - 715616, - 2339565, - 51980752, - 17333865, - 21965103, - 10839820, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 18672548, - 57660959, - 16042910, - 19519287, - 62865851, - 17580961, - 26628347, - 23774759, - ), - u32x8::new( - 368070, - 3464471, - 25888304, - 30370559, - 52396053, - 45426828, - 28745251, - 9246829, - ), - u32x8::new( - 29090099, - 57950037, - 23104657, - 4903923, - 10987778, - 56163684, - 23621539, - 10332760, - ), - u32x8::new( - 53338235, - 44851161, - 21606845, - 31069622, - 4243630, - 34464392, - 11286454, - 5802022, - ), - u32x8::new( - 46710757, - 63389067, - 11642865, - 1980986, - 12967337, - 28162061, - 3854192, - 30432268, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 12179834, - 41005450, - 12809619, - 33525228, - 4624405, - 46957889, - 16968743, - 11827816, - ), - u32x8::new( - 51521162, - 12466775, - 31791271, - 15303651, - 49798465, - 62714504, - 6509600, - 12918560, - ), - u32x8::new( - 20445559, - 1756449, - 28848701, - 7920171, - 9835040, - 5900071, - 28757409, - 12376688, - ), - u32x8::new( - 18259496, - 14281012, - 21767026, - 10232236, - 20000226, - 12400540, - 4104902, - 23570543, - ), - u32x8::new( - 3687440, - 26546648, - 13328821, - 26841081, - 49822734, - 22334054, - 244496, - 24862543, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 59523541, - 62195428, - 3853227, - 13954801, - 12387708, - 47627615, - 27221350, - 17899572, - ), - u32x8::new( - 63193587, - 36343307, - 14595132, - 6880795, - 1364792, - 37648434, - 3259017, - 20536046, - ), - u32x8::new( - 30362834, - 10440372, - 9574624, - 11729232, - 63861613, - 21748389, - 5530846, - 2721586, - ), - u32x8::new( - 18339760, - 1550632, - 17170271, - 25732971, - 28459263, - 63142237, - 21642345, - 31557672, - ), - u32x8::new( - 10611282, - 5204623, - 18049257, - 214175, - 19432723, - 49809070, - 26010406, - 27449522, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 19770733, - 26478685, - 9464541, - 29158041, - 28604307, - 45196604, - 7586524, - 6641859, - ), - u32x8::new( - 65654484, - 52230498, - 30886612, - 19112823, - 47271809, - 38942611, - 16020035, - 10773481, - ), - u32x8::new( - 27464323, - 54451016, - 20646645, - 17732915, - 23008717, - 53626684, - 3253189, - 15614410, - ), - u32x8::new( - 52381752, - 40693008, - 7063024, - 28469981, - 51159478, - 44543211, - 19941777, - 5985451, - ), - u32x8::new( - 13553668, - 35524849, - 14788737, - 1883845, - 12385775, - 47958835, - 29135466, - 1776722, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 36719806, - 20827965, - 23175373, - 32996806, - 42041892, - 65708790, - 5467143, - 20884008, - ), - u32x8::new( - 43256281, - 40770646, - 17244063, - 31959819, - 64366384, - 43544617, - 25057754, - 12628720, - ), - u32x8::new( - 17337782, - 58472057, - 27906934, - 15305274, - 30292418, - 39284317, - 16946773, - 24806712, - ), - u32x8::new( - 6485126, - 32447403, - 16261486, - 13561940, - 49439635, - 10738368, - 16419889, - 8897231, - ), - u32x8::new( - 44812203, - 40122262, - 25496058, - 2759794, - 25295304, - 52178368, - 24154195, - 29334408, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 42307254, - 57217102, - 1088936, - 3832827, - 33905401, - 23130334, - 6958056, - 12622851, - ), - u32x8::new( - 3881189, - 14870059, - 19712830, - 6071598, - 38147944, - 60776394, - 3427938, - 13765703, - ), - u32x8::new( - 7666911, - 24227591, - 17077136, - 22967588, - 6874639, - 30915523, - 11451695, - 24292224, - ), - u32x8::new( - 13659529, - 31984463, - 28764736, - 20506164, - 64729627, - 49321636, - 28284636, - 25472371, - ), - u32x8::new( - 39360308, - 42281399, - 9446504, - 868960, - 49227724, - 21351115, - 30561851, - 11292096, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 7071115, - 46444090, - 5387916, - 15432877, - 27226682, - 41506862, - 2398278, - 3978240, - ), - u32x8::new( - 51009614, - 54216973, - 24368938, - 31392616, - 38456150, - 62313644, - 6729154, - 99724, - ), - u32x8::new( - 17474332, - 62857913, - 2619930, - 30659308, - 18268181, - 32809239, - 22826292, - 24561895, - ), - u32x8::new( - 38187020, - 67003092, - 14118280, - 16500577, - 18808560, - 64983716, - 25712929, - 32518261, - ), - u32x8::new( - 25735813, - 62284262, - 10824872, - 20558596, - 48149681, - 31162667, - 22608274, - 26285185, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 963440, - 63742255, - 10230323, - 25515008, - 32506414, - 6105697, - 25980317, - 24645129, - ), - u32x8::new( - 7162189, - 8101249, - 14679265, - 33443386, - 2002396, - 8541405, - 19442276, - 4795881, - ), - u32x8::new( - 8116694, - 51463069, - 4415528, - 25599140, - 55805721, - 39582709, - 6719436, - 30033839, - ), - u32x8::new( - 14468202, - 42181869, - 25188826, - 9639755, - 47546189, - 62711146, - 32762447, - 18338064, - ), - u32x8::new( - 33880058, - 32810909, - 8969931, - 13095238, - 38360605, - 40138517, - 9246134, - 4928058, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 63655588, - 17883670, - 9410246, - 26162761, - 5000571, - 7349225, - 23785252, - 32751089, - ), - u32x8::new( - 28568737, - 10733123, - 9342397, - 21570673, - 54096560, - 32467591, - 20494687, - 21511513, - ), - u32x8::new( - 47675157, - 47932807, - 29250946, - 15672208, - 59760469, - 9945465, - 14939287, - 18437405, - ), - u32x8::new( - 37985267, - 8609815, - 31573002, - 3373596, - 47828883, - 20834216, - 13248616, - 24154292, - ), - u32x8::new( - 5543543, - 29553242, - 3386453, - 30501150, - 25058089, - 15236571, - 8814395, - 32462955, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 39158670, - 15322548, - 20495103, - 3312736, - 14557171, - 12985179, - 8044741, - 3176899, - ), - u32x8::new( - 24673290, - 29693310, - 21412266, - 18324699, - 2154518, - 40329021, - 17500543, - 3954277, - ), - u32x8::new( - 36758685, - 38738957, - 165513, - 14691866, - 3070475, - 10424235, - 17096536, - 16896898, - ), - u32x8::new( - 59790459, - 43094586, - 8720681, - 10423589, - 1122030, - 31545615, - 4463786, - 31811293, - ), - u32x8::new( - 49778992, - 60881044, - 20509974, - 5832494, - 64155961, - 31483358, - 4511231, - 20307815, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 2863373, - 40876242, - 26865913, - 24067353, - 15726407, - 40919070, - 12953902, - 9931535, - ), - u32x8::new( - 60934877, - 42512204, - 21649141, - 21945190, - 52211954, - 60984193, - 7046207, - 5363493, - ), - u32x8::new( - 4205971, - 64068464, - 18197273, - 7327176, - 51527794, - 21166920, - 20669933, - 11828242, - ), - u32x8::new( - 59782815, - 49617225, - 15379924, - 457923, - 9320508, - 21498914, - 3242540, - 31563182, - ), - u32x8::new( - 27714753, - 8664670, - 3366162, - 26338598, - 56775518, - 25796006, - 13129151, - 21388876, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 59276548, - 49972346, - 16795002, - 33455915, - 48430097, - 53857205, - 18627071, - 32474471, - ), - u32x8::new( - 42160315, - 50705892, - 13530540, - 28012698, - 19833221, - 55886870, - 20191784, - 9644313, - ), - u32x8::new( - 20372416, - 28414713, - 24084234, - 31804096, - 33815377, - 36131001, - 17251241, - 18291088, - ), - u32x8::new( - 56234667, - 14920441, - 2033267, - 29572003, - 1724043, - 45519699, - 17873735, - 501988, - ), - u32x8::new( - 50031659, - 31517850, - 15697583, - 1016845, - 43104661, - 54769582, - 8008601, - 27257051, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 52951491, - 66542164, - 14853573, - 30444631, - 12045973, - 24321813, - 16545674, - 18160646, - ), - u32x8::new( - 60107911, - 1126003, - 5947677, - 19486116, - 41119984, - 30860440, - 7935395, - 13354438, - ), - u32x8::new( - 17841328, - 11063269, - 1664538, - 26687568, - 6268968, - 22280371, - 17275484, - 4523163, - ), - u32x8::new( - 15886041, - 56799482, - 15446552, - 21712778, - 1005290, - 17827215, - 4978741, - 6854882, - ), - u32x8::new( - 34319277, - 47731002, - 20321804, - 28544575, - 29591814, - 63376351, - 24754545, - 26001714, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 66783087, - 5234346, - 46102, - 8566476, - 19947339, - 20180418, - 25398238, - 3726678, - ), - u32x8::new( - 63890180, - 46380965, - 20674069, - 5366544, - 59661487, - 48406612, - 31533614, - 7071217, - ), - u32x8::new( - 13104676, - 1406631, - 24326736, - 19854367, - 61039528, - 11019904, - 31967425, - 19219275, - ), - u32x8::new( - 39003597, - 30143957, - 15351834, - 8639435, - 57309582, - 61436794, - 15830475, - 10090318, - ), - u32x8::new( - 45923044, - 6700175, - 99413, - 21263025, - 23762647, - 53905481, - 6063914, - 10065424, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 42822326, - 57678669, - 4052879, - 25452667, - 54049411, - 2373092, - 22337016, - 7701046, - ), - u32x8::new( - 44382355, - 43307377, - 16761537, - 30373573, - 49790216, - 23230748, - 25655306, - 10519391, - ), - u32x8::new( - 919475, - 59371245, - 1273450, - 25558666, - 9724711, - 8556709, - 25755845, - 10887647, - ), - u32x8::new( - 25465699, - 44651158, - 17658392, - 11257418, - 29735193, - 22885150, - 7094716, - 26828565, - ), - u32x8::new( - 48237389, - 47661599, - 27054393, - 7328070, - 27280193, - 65616691, - 23062005, - 4170709, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 26535281, - 60238317, - 30343788, - 25790743, - 37993933, - 24614372, - 9523840, - 10401918, - ), - u32x8::new( - 2783987, - 29468958, - 4697011, - 19804475, - 37246678, - 46797720, - 10261254, - 18942252, - ), - u32x8::new( - 58135580, - 60247753, - 25301938, - 6844561, - 20949454, - 39844754, - 4552026, - 919057, - ), - u32x8::new( - 6694071, - 44126261, - 32285330, - 31370180, - 24603698, - 53328179, - 13971149, - 5325636, - ), - u32x8::new( - 64879487, - 582094, - 17982081, - 19190425, - 24951286, - 26923842, - 29077174, - 33286062, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 54863941, - 67016431, - 1224043, - 23371240, - 62940074, - 52101083, - 13523637, - 30366406, - ), - u32x8::new( - 36324581, - 25407485, - 18258623, - 4698602, - 50300544, - 2658516, - 26300935, - 2611030, - ), - u32x8::new( - 27183975, - 21791014, - 18105064, - 9875199, - 58118912, - 54198635, - 6400311, - 14767984, - ), - u32x8::new( - 33918318, - 42937962, - 14809334, - 22136592, - 10636588, - 29082337, - 29829692, - 28549776, - ), - u32x8::new( - 61080905, - 854212, - 12202487, - 20004503, - 9256495, - 6903981, - 20567109, - 347423, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 41391822, - 34336880, - 22362564, - 14247996, - 12115604, - 41583344, - 7639288, - 28910945, - ), - u32x8::new( - 62066617, - 59758859, - 26665947, - 11614812, - 65737664, - 45704543, - 30324810, - 12868376, - ), - u32x8::new( - 17491771, - 43589814, - 9454919, - 26047850, - 52629282, - 39304244, - 3868968, - 19296062, - ), - u32x8::new( - 17826638, - 30413590, - 32534225, - 32741469, - 15012391, - 14365713, - 33039233, - 14791399, - ), - u32x8::new( - 64115596, - 59197067, - 32739005, - 23275744, - 32954320, - 22241406, - 20788442, - 4942942, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 31956192, - 59570132, - 2784352, - 4237732, - 47222312, - 4860927, - 18658867, - 15279314, - ), - u32x8::new( - 63240583, - 28160478, - 23524941, - 13390861, - 66437406, - 57718120, - 33345312, - 28896298, - ), - u32x8::new( - 39026193, - 46239965, - 21440243, - 25070488, - 64012383, - 60999016, - 16517060, - 29565907, - ), - u32x8::new( - 18118181, - 60161496, - 4212092, - 23976240, - 36277753, - 62363144, - 5816868, - 16964362, - ), - u32x8::new( - 18196138, - 62490693, - 281468, - 7934713, - 56027312, - 62015725, - 4837237, - 32932252, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 29885826, - 51028067, - 30418143, - 33438769, - 62542283, - 39442528, - 31535876, - 143299, - ), - u32x8::new( - 17143063, - 56709783, - 14451852, - 15782104, - 32762665, - 14047066, - 26295037, - 5432487, - ), - u32x8::new( - 75151, - 533606, - 7539077, - 30926189, - 38410914, - 23771680, - 4872443, - 29199566, - ), - u32x8::new( - 61522396, - 48934708, - 16223126, - 207380, - 11171993, - 47975147, - 14164574, - 352966, - ), - u32x8::new( - 15449006, - 56530757, - 26796528, - 12045834, - 63738697, - 40667227, - 33001582, - 9101885, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 43331297, - 18431341, - 25801195, - 17267698, - 19365485, - 57295202, - 22218985, - 21284590, - ), - u32x8::new( - 2429849, - 19152559, - 10762172, - 22564684, - 21880390, - 66866426, - 20357935, - 22641906, - ), - u32x8::new( - 19771185, - 31652693, - 3666117, - 28136958, - 23624283, - 55101502, - 6313920, - 6783662, - ), - u32x8::new( - 3487137, - 7092443, - 11001876, - 26196524, - 47319246, - 44542068, - 17594073, - 15027760, - ), - u32x8::new( - 49563607, - 32191113, - 4991283, - 25400512, - 46539152, - 4155103, - 32368171, - 201203, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 20548943, - 14334571, - 4073874, - 6368588, - 53208883, - 56484515, - 15970071, - 25561889, - ), - u32x8::new( - 49915097, - 44030795, - 11202344, - 29284344, - 60258023, - 66225712, - 8075764, - 12383512, - ), - u32x8::new( - 45248912, - 4933668, - 9592153, - 5819559, - 31030983, - 38174071, - 32435814, - 7442522, - ), - u32x8::new( - 62688129, - 48218381, - 22089545, - 12897361, - 21050881, - 34278889, - 7569163, - 3225449, - ), - u32x8::new( - 19050183, - 51089071, - 32935757, - 22640195, - 66122318, - 47144608, - 18743677, - 25177079, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 41186817, - 46681702, - 31819867, - 32997133, - 38559207, - 27147015, - 30293819, - 16762988, - ), - u32x8::new( - 24154689, - 51762873, - 23883879, - 13510519, - 55338250, - 61224161, - 11663149, - 30803960, - ), - u32x8::new( - 18104238, - 14117824, - 11724021, - 21362053, - 65704761, - 35530242, - 13498058, - 33522849, - ), - u32x8::new( - 63812888, - 23995539, - 28920539, - 24005193, - 26412223, - 36582218, - 4251418, - 26160309, - ), - u32x8::new( - 16822053, - 66064082, - 3482145, - 31979593, - 45937188, - 54475379, - 612917, - 7976478, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 46509314, - 55327128, - 8944536, - 274914, - 26432930, - 53829300, - 21192572, - 3569894, - ), - u32x8::new( - 20919764, - 64356651, - 30642344, - 17215170, - 20335124, - 11203745, - 18663316, - 19024174, - ), - u32x8::new( - 59297055, - 53842463, - 3680204, - 9806710, - 54004169, - 51484914, - 29807998, - 20134199, - ), - u32x8::new( - 14781592, - 22628010, - 26877930, - 25880359, - 30434803, - 190607, - 30184292, - 8991040, - ), - u32x8::new( - 64400983, - 64591751, - 854562, - 28216111, - 20010398, - 50414793, - 9803872, - 22687008, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 15091184, - 32550863, - 8818643, - 4244752, - 43123513, - 64565526, - 408838, - 13206998, - ), - u32x8::new( - 16405061, - 60379639, - 31489017, - 20949281, - 27568751, - 38734986, - 8364264, - 12451020, - ), - u32x8::new( - 16005217, - 58008076, - 1406778, - 26546927, - 39571784, - 56365493, - 31274296, - 8918790, - ), - u32x8::new( - 23271122, - 19453469, - 27718201, - 32742670, - 234332, - 36785342, - 22601675, - 14331046, - ), - u32x8::new( - 40636025, - 22442705, - 22115403, - 23745859, - 41164945, - 61012, - 12499614, - 542137, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 62776018, - 32835413, - 17373246, - 17187309, - 54469193, - 21770290, - 15923753, - 28996575, - ), - u32x8::new( - 59385210, - 63082298, - 12568449, - 8509004, - 9483342, - 16105238, - 5756054, - 26890758, - ), - u32x8::new( - 53987996, - 38201748, - 5521661, - 19060159, - 18663191, - 9093637, - 27786835, - 31189196, - ), - u32x8::new( - 65872678, - 43635130, - 27903055, - 25020300, - 65772737, - 38110437, - 5213502, - 21909342, - ), - u32x8::new( - 4438979, - 9680838, - 10212446, - 4764184, - 13235684, - 58245995, - 20264570, - 21024049, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 60835961, - 48209103, - 31049052, - 4688268, - 12426713, - 59829045, - 22302488, - 29008521, - ), - u32x8::new( - 50401667, - 29716596, - 23531224, - 7581281, - 49071895, - 6952617, - 14934683, - 8218256, - ), - u32x8::new( - 1601446, - 36631413, - 31774811, - 29625330, - 56786114, - 8331539, - 23129509, - 19783344, - ), - u32x8::new( - 59514327, - 64513110, - 1772300, - 5701338, - 5737511, - 16147555, - 9461515, - 5703271, - ), - u32x8::new( - 33072974, - 54300426, - 11940114, - 1308663, - 15627555, - 4931627, - 28443714, - 20924342, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 18135013, - 20358426, - 4922557, - 10015355, - 65729669, - 34786528, - 26248549, - 29194359, - ), - u32x8::new( - 797666, - 34997544, - 24316856, - 25107230, - 24612576, - 4761401, - 15307321, - 32404252, - ), - u32x8::new( - 16501152, - 60565831, - 9487105, - 9316022, - 24986054, - 31917592, - 3962024, - 2501883, - ), - u32x8::new( - 63356796, - 50432342, - 18044926, - 30566881, - 42032028, - 31415202, - 13524600, - 16119907, - ), - u32x8::new( - 3927286, - 57022374, - 9265437, - 21620772, - 19481940, - 3806938, - 24836192, - 14572399, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 10785787, - 46564798, - 368445, - 33181384, - 5319843, - 52687136, - 30347110, - 29837357, - ), - u32x8::new( - 56436732, - 47859251, - 24141084, - 22250712, - 59046084, - 4963427, - 33463413, - 17168859, - ), - u32x8::new( - 15512044, - 6366740, - 4737504, - 27644548, - 30307977, - 25037929, - 14593903, - 12836490, - ), - u32x8::new( - 63878897, - 34013023, - 5860752, - 7244096, - 3689461, - 57012135, - 18389096, - 11589351, - ), - u32x8::new( - 4682110, - 36302830, - 653422, - 22316819, - 14081831, - 5657024, - 11088376, - 24110612, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 39907267, - 45940262, - 24887471, - 18342609, - 878445, - 40456159, - 12019082, - 345107, - ), - u32x8::new( - 12794982, - 28893944, - 9447505, - 11387200, - 16961963, - 13916996, - 10893728, - 25898006, - ), - u32x8::new( - 44934162, - 53465865, - 3583620, - 1102334, - 53917811, - 63478576, - 2426066, - 10389549, - ), - u32x8::new( - 45096036, - 37595344, - 19367718, - 20257175, - 10280866, - 41653449, - 27665642, - 375926, - ), - u32x8::new( - 45847901, - 24064074, - 32494820, - 32204556, - 10720704, - 51079060, - 1297436, - 29853825, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 66303987, - 36060363, - 16494578, - 24962147, - 11971403, - 49538586, - 25060560, - 1964341, - ), - u32x8::new( - 25988481, - 27641502, - 24909517, - 27237087, - 66646363, - 52777626, - 16360849, - 10459972, - ), - u32x8::new( - 43930529, - 34374176, - 31225968, - 8807030, - 10394758, - 35904854, - 25325589, - 19335583, - ), - u32x8::new( - 25094697, - 34380951, - 20051185, - 32287161, - 11739332, - 53887441, - 30517319, - 26601892, - ), - u32x8::new( - 8868546, - 35635502, - 32513071, - 28248087, - 51946989, - 14222744, - 19198839, - 23261841, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 51218008, - 5070126, - 11046681, - 5320810, - 61212079, - 34104447, - 23895089, - 6460727, - ), - u32x8::new( - 39843528, - 46278671, - 10426120, - 25624792, - 66658766, - 37140083, - 28933107, - 12969597, - ), - u32x8::new( - 59635793, - 40220191, - 5751421, - 173680, - 58321825, - 740337, - 1412847, - 7682623, - ), - u32x8::new( - 975962, - 56440763, - 20812276, - 22631115, - 49095824, - 19883130, - 2419746, - 31043648, - ), - u32x8::new( - 66208703, - 39669328, - 22525915, - 3748897, - 65994776, - 34533552, - 8126286, - 18326047, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 64176557, - 3912400, - 19351673, - 30068471, - 31190055, - 24221683, - 33142424, - 28698542, - ), - u32x8::new( - 34784792, - 4109933, - 3867193, - 19557314, - 2112512, - 32715890, - 24550117, - 16595976, - ), - u32x8::new( - 35542761, - 48024875, - 10925431, - 31526577, - 66577735, - 23189821, - 13375709, - 1735095, - ), - u32x8::new( - 59699254, - 43854093, - 29783239, - 24777271, - 19600372, - 39924461, - 2896720, - 1472185, - ), - u32x8::new( - 56389656, - 35980854, - 33172342, - 1370336, - 23707480, - 57654949, - 7850973, - 12655016, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 38372660, - 57101970, - 7044964, - 12732710, - 57535705, - 6043201, - 30858914, - 10946592, - ), - u32x8::new( - 21023468, - 6946992, - 26403324, - 23901823, - 35695559, - 23440687, - 4763891, - 6514074, - ), - u32x8::new( - 28662273, - 30933699, - 9352242, - 26354829, - 37402243, - 3145176, - 8770289, - 525937, - ), - u32x8::new( - 54933102, - 36695832, - 3281859, - 4755022, - 23043294, - 32794379, - 15618886, - 23602412, - ), - u32x8::new( - 9931565, - 29897140, - 2480737, - 24193701, - 7833615, - 2284939, - 893926, - 13421882, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 22917795, - 22088359, - 28978099, - 19794863, - 60542318, - 29878494, - 31053731, - 9080720, - ), - u32x8::new( - 23679072, - 52547035, - 28424916, - 20647332, - 4008761, - 28267029, - 12961289, - 1589095, - ), - u32x8::new( - 55616194, - 26678929, - 14998265, - 23274397, - 54625466, - 46244264, - 28627706, - 33030665, - ), - u32x8::new( - 11527330, - 6449415, - 26531607, - 3472938, - 41541592, - 62607682, - 19862690, - 20564723, - ), - u32x8::new( - 32843805, - 49066843, - 28425824, - 19521495, - 48792073, - 48242878, - 27392443, - 13175986, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 16185025, - 61537525, - 2961305, - 1492442, - 25123147, - 3095034, - 31896958, - 33089615, - ), - u32x8::new( - 64748157, - 18336595, - 16522231, - 25426312, - 65718949, - 35485695, - 30554083, - 10205918, - ), - u32x8::new( - 39626934, - 39271045, - 16420458, - 9826240, - 56483981, - 27128085, - 3783403, - 13360006, - ), - u32x8::new( - 30793778, - 66771960, - 17241420, - 6564573, - 61102581, - 29974476, - 32385512, - 9011754, - ), - u32x8::new( - 28068166, - 11862220, - 14323567, - 12380617, - 52090465, - 16029056, - 24495309, - 21409233, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 59411973, - 57437124, - 11695483, - 17586857, - 16108987, - 43449109, - 31098002, - 6248476, - ), - u32x8::new( - 42258047, - 61595931, - 29308533, - 11742653, - 43042345, - 27373650, - 30165249, - 21929989, - ), - u32x8::new( - 49907221, - 9620337, - 21888081, - 20981082, - 56288861, - 61562203, - 33223566, - 3582446, - ), - u32x8::new( - 57535017, - 41003416, - 22080416, - 14463796, - 65518565, - 18127889, - 24370863, - 33332664, - ), - u32x8::new( - 66655380, - 6430175, - 471782, - 11947673, - 30596400, - 18898659, - 15930721, - 4211851, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 6757410, - 65455566, - 13584784, - 11362173, - 10797127, - 24451471, - 19541370, - 29309435, - ), - u32x8::new( - 40360156, - 17685025, - 18326181, - 3846903, - 13693365, - 63049479, - 31900359, - 23385063, - ), - u32x8::new( - 52455038, - 57513503, - 22163311, - 27095042, - 48610726, - 66454160, - 12085341, - 26357004, - ), - u32x8::new( - 22097042, - 14063840, - 6705778, - 14342902, - 66139825, - 20702105, - 31279090, - 7495745, - ), - u32x8::new( - 27360710, - 49314837, - 18774847, - 7146436, - 37066216, - 42004961, - 22409916, - 10524446, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 1497507, - 33054449, - 11839906, - 2960428, - 40538463, - 18884538, - 25018820, - 4073970, - ), - u32x8::new( - 54484385, - 43640735, - 2808257, - 20710708, - 39840730, - 27222424, - 21783544, - 11848522, - ), - u32x8::new( - 45765237, - 48200555, - 9299019, - 9393151, - 34818188, - 56098995, - 13575233, - 21012731, - ), - u32x8::new( - 4265428, - 49627650, - 24960282, - 9425650, - 47883651, - 2797524, - 11853190, - 22877329, - ), - u32x8::new( - 25008173, - 64199503, - 380047, - 12107343, - 12329448, - 11914399, - 764281, - 29687002, - ), - ])), - CachedPoint(FieldElement2625x4([ - u32x8::new( - 35889734, - 23047226, - 4022841, - 7017445, - 7274086, - 53316179, - 25100176, - 15310676, - ), - u32x8::new( - 42409427, - 30270106, - 6823853, - 31551384, - 40645017, - 66489807, - 18021817, - 32669351, - ), - u32x8::new( - 39827134, - 43680850, - 28297996, - 20258133, - 26058742, - 52643238, - 22238331, - 21690533, - ), - u32x8::new( - 60808002, - 17499995, - 30042246, - 29310584, - 48219954, - 29389518, - 8680514, - 17844709, - ), - u32x8::new( - 6452896, - 50116553, - 9532047, - 26821214, - 44524351, - 50428429, - 21904953, - 12608048, - ), - ])), -]); diff --git a/src/backend/vector/mod.rs b/src/backend/vector/mod.rs deleted file mode 100644 index 29a6f6572..000000000 --- a/src/backend/vector/mod.rs +++ /dev/null @@ -1,43 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -// Conditionally include the notes if we're on nightly (so we can include docs at all). -#![cfg_attr( - feature = "nightly", - doc(include = "../../../docs/parallel-formulas.md") -)] - -#[cfg(not(any(target_feature = "avx2", target_feature = "avx512ifma", rustdoc)))] -compile_error!("simd_backend selected without target_feature=+avx2 or +avx512ifma"); - -#[cfg(any( - all(target_feature = "avx2", not(target_feature = "avx512ifma")), - rustdoc -))] -#[doc(cfg(all(target_feature = "avx2", not(target_feature = "avx512ifma"))))] -pub mod avx2; -#[cfg(any( - all(target_feature = "avx2", not(target_feature = "avx512ifma")), - rustdoc -))] -pub(crate) use self::avx2::{ - constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, -}; - -#[cfg(any(target_feature = "avx512ifma", rustdoc))] -#[doc(cfg(target_feature = "avx512ifma"))] -pub mod ifma; -#[cfg(target_feature = "avx512ifma")] -pub(crate) use self::ifma::{ - constants::BASEPOINT_ODD_LOOKUP_TABLE, edwards::CachedPoint, edwards::ExtendedPoint, -}; - -pub mod scalar_mul; diff --git a/src/backend/vector/scalar_mul/pippenger.rs b/src/backend/vector/scalar_mul/pippenger.rs deleted file mode 100644 index 7f9e24156..000000000 --- a/src/backend/vector/scalar_mul/pippenger.rs +++ /dev/null @@ -1,164 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2019 Oleg Andreev -// See LICENSE for licensing information. -// -// Authors: -// - Oleg Andreev - -#![allow(non_snake_case)] - -use core::borrow::Borrow; - -use backend::vector::{CachedPoint, ExtendedPoint}; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::{Identity, VartimeMultiscalarMul}; - -#[allow(unused_imports)] -use prelude::*; - -/// Implements a version of Pippenger's algorithm. -/// -/// See the documentation in the serial `scalar_mul::pippenger` module for details. -pub struct Pippenger; - -#[cfg(any(feature = "alloc", feature = "std"))] -impl VartimeMultiscalarMul for Pippenger { - type Point = EdwardsPoint; - - fn optional_multiscalar_mul(scalars: I, points: J) -> Option - where - I: IntoIterator, - I::Item: Borrow, - J: IntoIterator>, - { - let mut scalars = scalars.into_iter(); - let size = scalars.by_ref().size_hint().0; - let w = if size < 500 { - 6 - } else if size < 800 { - 7 - } else { - 8 - }; - - let max_digit: usize = 1 << w; - let digits_count: usize = Scalar::to_radix_2w_size_hint(w); - let buckets_count: usize = max_digit / 2; // digits are signed+centered hence 2^w/2, excluding 0-th bucket - - // Collect optimized scalars and points in a buffer for repeated access - // (scanning the whole collection per each digit position). - let scalars = scalars - .into_iter() - .map(|s| s.borrow().to_radix_2w(w)); - - let points = points - .into_iter() - .map(|p| p.map(|P| CachedPoint::from(ExtendedPoint::from(P)))); - - let scalars_points = scalars - .zip(points) - .map(|(s, maybe_p)| maybe_p.map(|p| (s, p))) - .collect::>>()?; - - // Prepare 2^w/2 buckets. - // buckets[i] corresponds to a multiplication factor (i+1). - let mut buckets: Vec = (0..buckets_count) - .map(|_| ExtendedPoint::identity()) - .collect(); - - let mut columns = (0..digits_count).rev().map(|digit_index| { - // Clear the buckets when processing another digit. - for i in 0..buckets_count { - buckets[i] = ExtendedPoint::identity(); - } - - // Iterate over pairs of (point, scalar) - // and add/sub the point to the corresponding bucket. - // Note: if we add support for precomputed lookup tables, - // we'll be adding/subtractiong point premultiplied by `digits[i]` to buckets[0]. - for (digits, pt) in scalars_points.iter() { - // Widen digit so that we don't run into edge cases when w=8. - let digit = digits[digit_index] as i16; - if digit > 0 { - let b = (digit - 1) as usize; - buckets[b] = &buckets[b] + pt; - } else if digit < 0 { - let b = (-digit - 1) as usize; - buckets[b] = &buckets[b] - pt; - } - } - - // Add the buckets applying the multiplication factor to each bucket. - // The most efficient way to do that is to have a single sum with two running sums: - // an intermediate sum from last bucket to the first, and a sum of intermediate sums. - // - // For example, to add buckets 1*A, 2*B, 3*C we need to add these points: - // C - // C B - // C B A Sum = C + (C+B) + (C+B+A) - let mut buckets_intermediate_sum = buckets[buckets_count - 1]; - let mut buckets_sum = buckets[buckets_count - 1]; - for i in (0..(buckets_count - 1)).rev() { - buckets_intermediate_sum = - &buckets_intermediate_sum + &CachedPoint::from(buckets[i]); - buckets_sum = &buckets_sum + &CachedPoint::from(buckets_intermediate_sum); - } - - buckets_sum - }); - - // Take the high column as an initial value to avoid wasting time doubling the identity element in `fold()`. - // `unwrap()` always succeeds because we know we have more than zero digits. - let hi_column = columns.next().unwrap(); - - Some( - columns - .fold(hi_column, |total, p| { - &total.mul_by_pow_2(w as u32) + &CachedPoint::from(p) - }) - .into(), - ) - } -} - -#[cfg(test)] -mod test { - use super::*; - use constants; - use scalar::Scalar; - - #[test] - fn test_vartime_pippenger() { - // Reuse points across different tests - let mut n = 512; - let x = Scalar::from(2128506u64).invert(); - let y = Scalar::from(4443282u64).invert(); - let points: Vec<_> = (0..n) - .map(|i| constants::ED25519_BASEPOINT_POINT * Scalar::from(1 + i as u64)) - .collect(); - let scalars: Vec<_> = (0..n) - .map(|i| x + (Scalar::from(i as u64) * y)) // fast way to make ~random but deterministic scalars - .collect(); - - let premultiplied: Vec = scalars - .iter() - .zip(points.iter()) - .map(|(sc, pt)| sc * pt) - .collect(); - - while n > 0 { - let scalars = &scalars[0..n].to_vec(); - let points = &points[0..n].to_vec(); - let control: EdwardsPoint = premultiplied[0..n].iter().sum(); - - let subject = Pippenger::vartime_multiscalar_mul(scalars.clone(), points.clone()); - - assert_eq!(subject.compress(), control.compress()); - - n = n / 2; - } - } -} diff --git a/src/backend/vector/scalar_mul/precomputed_straus.rs b/src/backend/vector/scalar_mul/precomputed_straus.rs deleted file mode 100644 index 2c6fdf5ed..000000000 --- a/src/backend/vector/scalar_mul/precomputed_straus.rs +++ /dev/null @@ -1,107 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2019 Henry de Valence. -// See LICENSE for licensing information. -// -// Authors: -// - Henry de Valence - -//! Precomputation for Straus's method. - -#![allow(non_snake_case)] - -use core::borrow::Borrow; - -use backend::vector::{CachedPoint, ExtendedPoint}; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::Identity; -use traits::VartimePrecomputedMultiscalarMul; -use window::{NafLookupTable5, NafLookupTable8}; - -#[allow(unused_imports)] -use prelude::*; - - -pub struct VartimePrecomputedStraus { - static_lookup_tables: Vec>, -} - -impl VartimePrecomputedMultiscalarMul for VartimePrecomputedStraus { - type Point = EdwardsPoint; - - fn new(static_points: I) -> Self - where - I: IntoIterator, - I::Item: Borrow, - { - Self { - static_lookup_tables: static_points - .into_iter() - .map(|P| NafLookupTable8::::from(P.borrow())) - .collect(), - } - } - - fn optional_mixed_multiscalar_mul( - &self, - static_scalars: I, - dynamic_scalars: J, - dynamic_points: K, - ) -> Option - where - I: IntoIterator, - I::Item: Borrow, - J: IntoIterator, - J::Item: Borrow, - K: IntoIterator>, - { - let static_nafs = static_scalars - .into_iter() - .map(|c| c.borrow().non_adjacent_form(5)) - .collect::>(); - let dynamic_nafs: Vec<_> = dynamic_scalars - .into_iter() - .map(|c| c.borrow().non_adjacent_form(5)) - .collect::>(); - - let dynamic_lookup_tables = dynamic_points - .into_iter() - .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) - .collect::>>()?; - - let sp = self.static_lookup_tables.len(); - let dp = dynamic_lookup_tables.len(); - assert_eq!(sp, static_nafs.len()); - assert_eq!(dp, dynamic_nafs.len()); - - // We could save some doublings by looking for the highest - // nonzero NAF coefficient, but since we might have a lot of - // them to search, it's not clear it's worthwhile to check. - let mut R = ExtendedPoint::identity(); - for j in (0..256).rev() { - R = R.double(); - - for i in 0..dp { - let t_ij = dynamic_nafs[i][j]; - if t_ij > 0 { - R = &R + &dynamic_lookup_tables[i].select(t_ij as usize); - } else if t_ij < 0 { - R = &R - &dynamic_lookup_tables[i].select(-t_ij as usize); - } - } - - for i in 0..sp { - let t_ij = static_nafs[i][j]; - if t_ij > 0 { - R = &R + &self.static_lookup_tables[i].select(t_ij as usize); - } else if t_ij < 0 { - R = &R - &self.static_lookup_tables[i].select(-t_ij as usize); - } - } - } - - Some(R.into()) - } -} diff --git a/src/backend/vector/scalar_mul/straus.rs b/src/backend/vector/scalar_mul/straus.rs deleted file mode 100644 index b6c02f976..000000000 --- a/src/backend/vector/scalar_mul/straus.rs +++ /dev/null @@ -1,108 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -#![allow(non_snake_case)] - -use core::borrow::Borrow; - -use zeroize::Zeroizing; - -use backend::vector::{CachedPoint, ExtendedPoint}; -use edwards::EdwardsPoint; -use scalar::Scalar; -use window::{LookupTable, NafLookupTable5}; -use traits::{Identity, MultiscalarMul, VartimeMultiscalarMul}; - -#[allow(unused_imports)] -use prelude::*; - -/// Multiscalar multiplication using interleaved window / Straus' -/// method. See the `Straus` struct in the serial backend for more -/// details. -/// -/// This exists as a seperate implementation from that one because the -/// AVX2 code uses different curve models (it does not pass between -/// multiple models during scalar mul), and it has to convert the -/// point representation on the fly. -pub struct Straus {} - -impl MultiscalarMul for Straus { - type Point = EdwardsPoint; - - fn multiscalar_mul(scalars: I, points: J) -> EdwardsPoint - where - I: IntoIterator, - I::Item: Borrow, - J: IntoIterator, - J::Item: Borrow, - { - // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] - // for each input point P - let lookup_tables: Vec<_> = points - .into_iter() - .map(|point| LookupTable::::from(point.borrow())) - .collect(); - - let scalar_digits_vec: Vec<_> = scalars - .into_iter() - .map(|s| s.borrow().to_radix_16()) - .collect(); - // Pass ownership to a `Zeroizing` wrapper - let scalar_digits = Zeroizing::new(scalar_digits_vec); - - let mut Q = ExtendedPoint::identity(); - for j in (0..64).rev() { - Q = Q.mul_by_pow_2(4); - let it = scalar_digits.iter().zip(lookup_tables.iter()); - for (s_i, lookup_table_i) in it { - // Q = Q + s_{i,j} * P_i - Q = &Q + &lookup_table_i.select(s_i[j]); - } - } - Q.into() - } -} - -impl VartimeMultiscalarMul for Straus { - type Point = EdwardsPoint; - - fn optional_multiscalar_mul(scalars: I, points: J) -> Option - where - I: IntoIterator, - I::Item: Borrow, - J: IntoIterator>, - { - let nafs: Vec<_> = scalars - .into_iter() - .map(|c| c.borrow().non_adjacent_form(5)) - .collect(); - let lookup_tables: Vec<_> = points - .into_iter() - .map(|P_opt| P_opt.map(|P| NafLookupTable5::::from(&P))) - .collect::>>()?; - - let mut Q = ExtendedPoint::identity(); - - for i in (0..256).rev() { - Q = Q.double(); - - for (naf, lookup_table) in nafs.iter().zip(lookup_tables.iter()) { - if naf[i] > 0 { - Q = &Q + &lookup_table.select(naf[i] as usize); - } else if naf[i] < 0 { - Q = &Q - &lookup_table.select(-naf[i] as usize); - } - } - } - - Some(Q.into()) - } -} diff --git a/src/backend/vector/scalar_mul/variable_base.rs b/src/backend/vector/scalar_mul/variable_base.rs deleted file mode 100644 index f53c4a0c9..000000000 --- a/src/backend/vector/scalar_mul/variable_base.rs +++ /dev/null @@ -1,32 +0,0 @@ -#![allow(non_snake_case)] - -use backend::vector::{CachedPoint, ExtendedPoint}; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::Identity; -use window::LookupTable; - -/// Perform constant-time, variable-base scalar multiplication. -pub fn mul(point: &EdwardsPoint, scalar: &Scalar) -> EdwardsPoint { - // Construct a lookup table of [P,2P,3P,4P,5P,6P,7P,8P] - let lookup_table = LookupTable::::from(point); - // Setting s = scalar, compute - // - // s = s_0 + s_1*16^1 + ... + s_63*16^63, - // - // with `-8 ≤ s_i < 8` for `0 ≤ i < 63` and `-8 ≤ s_63 ≤ 8`. - let scalar_digits = scalar.to_radix_16(); - // Compute s*P as - // - // s*P = P*(s_0 + s_1*16^1 + s_2*16^2 + ... + s_63*16^63) - // s*P = P*s_0 + P*s_1*16^1 + P*s_2*16^2 + ... + P*s_63*16^63 - // s*P = P*s_0 + 16*(P*s_1 + 16*(P*s_2 + 16*( ... + P*s_63)...)) - // - // We sum right-to-left. - let mut Q = ExtendedPoint::identity(); - for i in (0..64).rev() { - Q = Q.mul_by_pow_2(4); - Q = &Q + &lookup_table.select(scalar_digits[i]); - } - Q.into() -} diff --git a/src/backend/vector/scalar_mul/vartime_double_base.rs b/src/backend/vector/scalar_mul/vartime_double_base.rs deleted file mode 100644 index 3f7cc3eb6..000000000 --- a/src/backend/vector/scalar_mul/vartime_double_base.rs +++ /dev/null @@ -1,62 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -#![allow(non_snake_case)] - -use backend::vector::BASEPOINT_ODD_LOOKUP_TABLE; -use backend::vector::{CachedPoint, ExtendedPoint}; -use edwards::EdwardsPoint; -use scalar::Scalar; -use traits::Identity; -use window::NafLookupTable5; - -/// Compute \\(aA + bB\\) in variable time, where \\(B\\) is the Ed25519 basepoint. -pub fn mul(a: &Scalar, A: &EdwardsPoint, b: &Scalar) -> EdwardsPoint { - let a_naf = a.non_adjacent_form(5); - let b_naf = b.non_adjacent_form(8); - - // Find starting index - let mut i: usize = 255; - for j in (0..256).rev() { - i = j; - if a_naf[i] != 0 || b_naf[i] != 0 { - break; - } - } - - let table_A = NafLookupTable5::::from(A); - let table_B = &BASEPOINT_ODD_LOOKUP_TABLE; - - let mut Q = ExtendedPoint::identity(); - - loop { - Q = Q.double(); - - if a_naf[i] > 0 { - Q = &Q + &table_A.select(a_naf[i] as usize); - } else if a_naf[i] < 0 { - Q = &Q - &table_A.select(-a_naf[i] as usize); - } - - if b_naf[i] > 0 { - Q = &Q + &table_B.select(b_naf[i] as usize); - } else if b_naf[i] < 0 { - Q = &Q - &table_B.select(-b_naf[i] as usize); - } - - if i == 0 { - break; - } - i -= 1; - } - - Q.into() -} diff --git a/src/constants.rs b/src/constants.rs deleted file mode 100644 index 9b7e0bd41..000000000 --- a/src/constants.rs +++ /dev/null @@ -1,183 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! Various constants, such as the Ristretto and Ed25519 basepoints. -//! -//! Most of the constants are given with -//! `LONG_DESCRIPTIVE_UPPER_CASE_NAMES`, but they can be brought into -//! scope using a `let` binding: -//! -//! ``` -//! use curve25519_dalek::constants; -//! use curve25519_dalek::traits::IsIdentity; -//! -//! let B = &constants::RISTRETTO_BASEPOINT_TABLE; -//! let l = &constants::BASEPOINT_ORDER; -//! -//! let A = l * B; -//! assert!(A.is_identity()); -//! ``` - -#![allow(non_snake_case)] - -use edwards::CompressedEdwardsY; -use ristretto::RistrettoPoint; -use ristretto::CompressedRistretto; -use montgomery::MontgomeryPoint; -use scalar::Scalar; - -#[cfg(feature = "fiat_u32_backend")] -pub use backend::serial::fiat_u32::constants::*; -#[cfg(feature = "fiat_u64_backend")] -pub use backend::serial::fiat_u64::constants::*; -#[cfg(feature = "u64_backend")] -pub use backend::serial::u64::constants::*; -#[cfg(feature = "u32_backend")] -pub use backend::serial::u32::constants::*; -#[cfg(feature = "u32e_backend")] -pub use backend::serial::u32e::constants::*; - -/// The Ed25519 basepoint, in `CompressedEdwardsY` format. -/// -/// This is the little-endian byte encoding of \\( 4/5 \pmod p \\), -/// which is the \\(y\\)-coordinate of the Ed25519 basepoint. -/// -/// The sign bit is 0 since the basepoint has \\(x\\) chosen to be positive. -pub const ED25519_BASEPOINT_COMPRESSED: CompressedEdwardsY = - CompressedEdwardsY([0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, - 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66]); - -/// The X25519 basepoint, in `MontgomeryPoint` format. -pub const X25519_BASEPOINT: MontgomeryPoint = - MontgomeryPoint([0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]); - -/// The Ristretto basepoint, in `CompressedRistretto` format. -pub const RISTRETTO_BASEPOINT_COMPRESSED: CompressedRistretto = - CompressedRistretto([0xe2, 0xf2, 0xae, 0x0a, 0x6a, 0xbc, 0x4e, 0x71, - 0xa8, 0x84, 0xa9, 0x61, 0xc5, 0x00, 0x51, 0x5f, - 0x58, 0xe3, 0x0b, 0x6a, 0xa5, 0x82, 0xdd, 0x8d, - 0xb6, 0xa6, 0x59, 0x45, 0xe0, 0x8d, 0x2d, 0x76]); - -/// The Ristretto basepoint, as a `RistrettoPoint`. -/// -/// This is called `_POINT` to distinguish it from `_TABLE`, which -/// provides fast scalar multiplication. -pub const RISTRETTO_BASEPOINT_POINT: RistrettoPoint = RistrettoPoint(ED25519_BASEPOINT_POINT); - -/// `BASEPOINT_ORDER` is the order of the Ristretto group and of the Ed25519 basepoint, i.e., -/// $$ -/// \ell = 2^\{252\} + 27742317777372353535851937790883648493. -/// $$ -pub const BASEPOINT_ORDER: Scalar = Scalar{ - bytes: [ - 0xed, 0xd3, 0xf5, 0x5c, 0x1a, 0x63, 0x12, 0x58, - 0xd6, 0x9c, 0xf7, 0xa2, 0xde, 0xf9, 0xde, 0x14, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, - ], -}; - -use ristretto::RistrettoBasepointTable; -/// The Ristretto basepoint, as a `RistrettoBasepointTable` for scalar multiplication. -pub const RISTRETTO_BASEPOINT_TABLE: RistrettoBasepointTable - = RistrettoBasepointTable(ED25519_BASEPOINT_TABLE); - -#[cfg(test)] -mod test { - use field::FieldElement; - use traits::{IsIdentity, ValidityCheck}; - use constants; - - #[test] - fn test_eight_torsion() { - for i in 0..8 { - let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(3); - assert!(Q.is_valid()); - assert!(Q.is_identity()); - } - } - - #[test] - fn test_four_torsion() { - for i in (0..8).filter(|i| i % 2 == 0) { - let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(2); - assert!(Q.is_valid()); - assert!(Q.is_identity()); - } - } - - #[test] - fn test_two_torsion() { - for i in (0..8).filter(|i| i % 4 == 0) { - let Q = constants::EIGHT_TORSION[i].mul_by_pow_2(1); - assert!(Q.is_valid()); - assert!(Q.is_identity()); - } - } - - /// Test that SQRT_M1 is the positive square root of -1 - #[test] - fn test_sqrt_minus_one() { - let minus_one = FieldElement::minus_one(); - let sqrt_m1_sq = &constants::SQRT_M1 * &constants::SQRT_M1; - assert_eq!(minus_one, sqrt_m1_sq); - assert_eq!(constants::SQRT_M1.is_negative().unwrap_u8(), 0); - } - - #[test] - fn test_sqrt_constants_sign() { - let minus_one = FieldElement::minus_one(); - let (was_nonzero_square, invsqrt_m1) = minus_one.invsqrt(); - assert_eq!(was_nonzero_square.unwrap_u8(), 1u8); - let sign_test_sqrt = &invsqrt_m1 * &constants::SQRT_M1; - assert_eq!(sign_test_sqrt, minus_one); - } - - /// Test that d = -121665/121666 - #[test] - #[cfg(feature = "u32_backend")] - fn test_d_vs_ratio() { - use backend::serial::u32::field::FieldElement2625; - let a = -&FieldElement2625([121665,0,0,0,0,0,0,0,0,0]); - let b = FieldElement2625([121666,0,0,0,0,0,0,0,0,0]); - let d = &a * &b.invert(); - let d2 = &d + &d; - assert_eq!(d, constants::EDWARDS_D); - assert_eq!(d2, constants::EDWARDS_D2); - } - - /// Test that d = -121665/121666 - #[test] - #[cfg(feature = "u64_backend")] - fn test_d_vs_ratio() { - use backend::serial::u64::field::FieldElement51; - let a = -&FieldElement51([121665,0,0,0,0]); - let b = FieldElement51([121666,0,0,0,0]); - let d = &a * &b.invert(); - let d2 = &d + &d; - assert_eq!(d, constants::EDWARDS_D); - assert_eq!(d2, constants::EDWARDS_D2); - } - - #[test] - fn test_sqrt_ad_minus_one() { - let a = FieldElement::minus_one(); - let ad_minus_one = &(&a * &constants::EDWARDS_D) + &a; - let should_be_ad_minus_one = constants::SQRT_AD_MINUS_ONE.square(); - assert_eq!(should_be_ad_minus_one, ad_minus_one); - } - -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index d1fbbc30c..000000000 --- a/src/lib.rs +++ /dev/null @@ -1,334 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -#![no_std] -#![cfg_attr(feature = "nightly", feature(test))] -#![cfg_attr(feature = "nightly", feature(doc_cfg))] -#![cfg_attr(feature = "simd_backend", feature(stdsimd))] - -// Refuse to compile if documentation is missing. -#![deny(missing_docs)] - -#![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")] -#![doc(html_root_url = "https://docs.rs/curve25519-dalek/3.2.1")] - -//! # curve25519-dalek [![](https://img.shields.io/crates/v/curve25519-dalek.svg)](https://crates.io/crates/curve25519-dalek) [![](https://img.shields.io/badge/dynamic/json.svg?label=docs&uri=https%3A%2F%2Fcrates.io%2Fapi%2Fv1%2Fcrates%2Fcurve25519-dalek%2Fversions&query=%24.versions%5B0%5D.num&colorB=4F74A6)](https://doc.dalek.rs) [![](https://travis-ci.org/dalek-cryptography/curve25519-dalek.svg?branch=master)](https://travis-ci.org/dalek-cryptography/curve25519-dalek) -//! -//! -//! -//! **A pure-Rust implementation of group operations on Ristretto and Curve25519.** -//! -//! `curve25519-dalek` is a library providing group operations on the Edwards and -//! Montgomery forms of Curve25519, and on the prime-order Ristretto group. -//! -//! `curve25519-dalek` is not intended to provide implementations of any particular -//! crypto protocol. Rather, implementations of those protocols (such as -//! [`x25519-dalek`][x25519-dalek] and [`ed25519-dalek`][ed25519-dalek]) should use -//! `curve25519-dalek` as a library. -//! -//! `curve25519-dalek` is intended to provide a clean and safe _mid-level_ API for use -//! implementing a wide range of ECC-based crypto protocols, such as key agreement, -//! signatures, anonymous credentials, rangeproofs, and zero-knowledge proof -//! systems. -//! -//! In particular, `curve25519-dalek` implements Ristretto, which constructs a -//! prime-order group from a non-prime-order Edwards curve. This provides the -//! speed and safety benefits of Edwards curve arithmetic, without the pitfalls of -//! cofactor-related abstraction mismatches. -//! -//! # Documentation -//! -//! The semver-stable, public-facing `curve25519-dalek` API is documented -//! [here][docs-external]. In addition, the unstable internal implementation -//! details are documented [here][docs-internal]. -//! -//! The `curve25519-dalek` documentation requires a custom HTML header to include -//! KaTeX for math support. Unfortunately `cargo doc` does not currently support -//! this, but docs can be built using -//! ```sh -//! make doc -//! make doc-internal -//! ``` -//! -//! # Use -//! -//! To import `curve25519-dalek`, add the following to the dependencies section of -//! your project's `Cargo.toml`: -//! ```toml -//! curve25519-dalek = "3" -//! ``` -//! -//! The sole breaking change in the `3.x` series was an update to the `digest` -//! version, and in terms of non-breaking changes it includes: -//! -//! * support for using `alloc` instead of `std` on stable Rust, -//! * the Elligator2 encoding for Edwards points, -//! * a fix to use `packed_simd2`, -//! * various documentation fixes and improvements, -//! * support for configurably-sized, precomputed lookup tables for basepoint scalar -//! multiplication, -//! * two new formally-verified field arithmetic backends which use the Fiat Crypto -//! Rust code, which is generated from proofs of functional correctness checked by -//! the Coq theorem proving system, and -//! * support for explicitly calling the `zeroize` traits for all point types. -//! -//! The `2.x` series has API almost entirely unchanged from the `1.x` series, -//! except that: -//! -//! * an error in the data modeling for the (optional) `serde` feature was -//! corrected, so that when the `2.x`-series `serde` implementation is used -//! with `serde-bincode`, the derived serialization matches the usual X/Ed25519 -//! formats; -//! * the `rand` version was updated. -//! -//! See `CHANGELOG.md` for more details. -//! -//! # Backends and Features -//! -//! The `nightly` feature enables features available only when using a Rust nightly -//! compiler. In particular, it is required for rendering documentation and for -//! the SIMD backends. -//! -//! Curve arithmetic is implemented using one of the following backends: -//! -//! * a `u32` backend using serial formulas and `u64` products; -//! * a `u64` backend using serial formulas and `u128` products; -//! * an `avx2` backend using [parallel formulas][parallel_doc] and `avx2` instructions (sets speed records); -//! * an `ifma` backend using [parallel formulas][parallel_doc] and `ifma` instructions (sets speed records); -//! -//! By default the `u64` backend is selected. To select a specific backend, use: -//! ```sh -//! cargo build --no-default-features --features "std u32_backend" -//! cargo build --no-default-features --features "std u64_backend" -//! # Requires nightly, RUSTFLAGS="-C target_feature=+avx2" to use avx2 -//! cargo build --no-default-features --features "std simd_backend" -//! # Requires nightly, RUSTFLAGS="-C target_feature=+avx512ifma" to use ifma -//! cargo build --no-default-features --features "std simd_backend" -//! ``` -//! Crates using `curve25519-dalek` can either select a backend on behalf of their -//! users, or expose feature flags that control the `curve25519-dalek` backend. -//! -//! The `std` feature is enabled by default, but it can be disabled for no-`std` -//! builds using `--no-default-features`. Note that this requires explicitly -//! selecting an arithmetic backend using one of the `_backend` features. -//! If no backend is selected, compilation will fail. -//! -//! # Safety -//! -//! The `curve25519-dalek` types are designed to make illegal states -//! unrepresentable. For example, any instance of an `EdwardsPoint` is -//! guaranteed to hold a point on the Edwards curve, and any instance of a -//! `RistrettoPoint` is guaranteed to hold a valid point in the Ristretto -//! group. -//! -//! All operations are implemented using constant-time logic (no -//! secret-dependent branches, no secret-dependent memory accesses), -//! unless specifically marked as being variable-time code. -//! We believe that our constant-time logic is lowered to constant-time -//! assembly, at least on `x86_64` targets. -//! -//! As an additional guard against possible future compiler optimizations, -//! the `subtle` crate places an optimization barrier before every -//! conditional move or assignment. More details can be found in [the -//! documentation for the `subtle` crate][subtle_doc]. -//! -//! Some functionality (e.g., multiscalar multiplication or batch -//! inversion) requires heap allocation for temporary buffers. All -//! heap-allocated buffers of potentially secret data are explicitly -//! zeroed before release. -//! -//! However, we do not attempt to zero stack data, for two reasons. -//! First, it's not possible to do so correctly: we don't have control -//! over stack allocations, so there's no way to know how much data to -//! wipe. Second, because `curve25519-dalek` provides a mid-level API, -//! the correct place to start zeroing stack data is likely not at the -//! entrypoints of `curve25519-dalek` functions, but at the entrypoints of -//! functions in other crates. -//! -//! The implementation is memory-safe, and contains no significant -//! `unsafe` code. The SIMD backend uses `unsafe` internally to call SIMD -//! intrinsics. These are marked `unsafe` only because invoking them on an -//! inappropriate CPU would cause `SIGILL`, but the entire backend is only -//! compiled with appropriate `target_feature`s, so this cannot occur. -//! -//! # Performance -//! -//! Benchmarks are run using [`criterion.rs`][criterion]: -//! -//! ```sh -//! cargo bench --no-default-features --features "std u32_backend" -//! cargo bench --no-default-features --features "std u64_backend" -//! # Uses avx2 or ifma only if compiled for an appropriate target. -//! export RUSTFLAGS="-C target_cpu=native" -//! cargo bench --no-default-features --features "std simd_backend" -//! ``` -//! -//! Performance is a secondary goal behind correctness, safety, and -//! clarity, but we aim to be competitive with other implementations. -//! -//! # FFI -//! -//! Unfortunately, we have no plans to add FFI to `curve25519-dalek` directly. The -//! reason is that we use Rust features to provide an API that maintains safety -//! invariants, which are not possible to maintain across an FFI boundary. For -//! instance, as described in the _Safety_ section above, invalid points are -//! impossible to construct, and this would not be the case if we exposed point -//! operations over FFI. -//! -//! However, `curve25519-dalek` is designed as a *mid-level* API, aimed at -//! implementing other, higher-level primitives. Instead of providing FFI at the -//! mid-level, our suggestion is to implement the higher-level primitive (a -//! signature, PAKE, ZKP, etc) in Rust, using `curve25519-dalek` as a dependency, -//! and have that crate provide a minimal, byte-buffer-oriented FFI specific to -//! that primitive. -//! -//! # Contributing -//! -//! Please see [CONTRIBUTING.md][contributing]. -//! -//! Patches and pull requests should be make against the `develop` -//! branch, **not** `main`. -//! -//! # About -//! -//! **SPOILER ALERT:** *The Twelfth Doctor's first encounter with the Daleks is in -//! his second full episode, "Into the Dalek". A beleaguered ship of the "Combined -//! Galactic Resistance" has discovered a broken Dalek that has turned "good", -//! desiring to kill all other Daleks. The Doctor, Clara and a team of soldiers -//! are miniaturized and enter the Dalek, which the Doctor names Rusty. They -//! repair the damage, but accidentally restore it to its original nature, causing -//! it to go on the rampage and alert the Dalek fleet to the whereabouts of the -//! rebel ship. However, the Doctor manages to return Rusty to its previous state -//! by linking his mind with the Dalek's: Rusty shares the Doctor's view of the -//! universe's beauty, but also his deep hatred of the Daleks. Rusty destroys the -//! other Daleks and departs the ship, determined to track down and bring an end -//! to the Dalek race.* -//! -//! `curve25519-dalek` is authored by Isis Agora Lovecruft and Henry de Valence. -//! -//! Portions of this library were originally a port of [Adam Langley's -//! Golang ed25519 library](https://!github.com/agl/ed25519), which was in -//! turn a port of the reference `ref10` implementation. Most of this code, -//! including the 32-bit field arithmetic, has since been rewritten. -//! -//! The fast `u32` and `u64` scalar arithmetic was implemented by Andrew Moon, and -//! the addition chain for scalar inversion was provided by Brian Smith. The -//! optimised batch inversion was contributed by Sean Bowe and Daira Hopwood. -//! -//! The `no_std` and `zeroize` support was contributed by Tony Arcieri. -//! -//! The formally verified backends, `fiat_u32_backend` and `fiat_u64_backend`, which -//! integrate with the Rust generated by the -//! [Fiat Crypto project](https://github.com/mit-plv/fiat-crypto) were contributed -//! by François Garillot. -//! -//! Thanks also to Ashley Hauck, Lucas Salibian, Manish Goregaokar, Jack Grigg, -//! Pratyush Mishra, Michael Rosenberg, and countless others for their -//! contributions. -//! -//! [ed25519-dalek]: https://github.com/dalek-cryptography/ed25519-dalek -//! [x25519-dalek]: https://github.com/dalek-cryptography/x25519-dalek -//! [contributing]: https://github.com/dalek-cryptography/curve25519-dalek/blob/master/CONTRIBUTING.md -//! [docs-external]: https://doc.dalek.rs/curve25519_dalek/ -//! [docs-internal]: https://doc-internal.dalek.rs/curve25519_dalek/ -//! [criterion]: https://github.com/japaric/criterion.rs -//! [parallel_doc]: https://doc-internal.dalek.rs/curve25519_dalek/backend/vector/avx2/index.html -//! [subtle_doc]: https://doc.dalek.rs/subtle/ - -// needed for engine25519-as. Note vscode is still broken: -// https://github.com/rust-analyzer/rust-analyzer/issues/8640 -#![recursion_limit="512"] - -//------------------------------------------------------------------------ -// External dependencies: -//------------------------------------------------------------------------ - -#[cfg(all(feature = "alloc", not(feature = "std")))] -#[macro_use] -extern crate alloc; - -#[cfg(feature = "std")] -#[macro_use] -extern crate std; - -#[cfg(all(feature = "nightly", feature = "packed_simd"))] -extern crate packed_simd; - -extern crate byteorder; -pub extern crate digest; -extern crate rand_core; -extern crate zeroize; - -#[cfg(any(feature = "fiat_u64_backend", feature = "fiat_u32_backend"))] -extern crate fiat_crypto; - -// Used for traits related to constant-time code. -extern crate subtle; - -#[cfg(all(test, feature = "serde"))] -extern crate bincode; -#[cfg(feature = "serde")] -extern crate serde; - -// Internal macros. Must come first! -#[macro_use] -pub(crate) mod macros; - -#[allow(unused_imports)] -#[cfg(any(feature = "betrusted", test, feature = "u32e_backend"))] -#[macro_use] -extern crate engine25519_as; -#[cfg(feature = "betrusted")] -extern crate engine_25519; - -#[cfg(feature = "u32e_backend")] -extern crate utralib; - -//------------------------------------------------------------------------ -// curve25519-dalek public modules -//------------------------------------------------------------------------ - -// Scalar arithmetic mod l = 2^252 + ..., the order of the Ristretto group -pub mod scalar; - -// Point operations on the Montgomery form of Curve25519 -pub mod montgomery; - -// Point operations on the Edwards form of Curve25519 -pub mod edwards; - -// Group operations on the Ristretto group -pub mod ristretto; - -// Useful constants, like the Ed25519 basepoint -pub mod constants; - -// External (and internal) traits. -pub mod traits; - -//------------------------------------------------------------------------ -// curve25519-dalek internal modules -//------------------------------------------------------------------------ - -// Finite field arithmetic mod p = 2^255 - 19 -pub(crate) mod field; - -// Arithmetic backends (using u32, u64, etc) live here -pub(crate) mod backend; - -// Crate-local prelude (for alloc-dependent features like `Vec`) -pub(crate) mod prelude; - -// Generic code for window lookups -pub(crate) mod window; diff --git a/src/montgomery.rs b/src/montgomery.rs deleted file mode 100644 index 627695d5f..000000000 --- a/src/montgomery.rs +++ /dev/null @@ -1,1120 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! Scalar multiplication on the Montgomery form of Curve25519. -//! -//! To avoid notational confusion with the Edwards code, we use -//! variables \\( u, v \\) for the Montgomery curve, so that “Montgomery -//! \\(u\\)” here corresponds to “Montgomery \\(x\\)” elsewhere. -//! -//! Montgomery arithmetic works not on the curve itself, but on the -//! \\(u\\)-line, which discards sign information and unifies the curve -//! and its quadratic twist. See [_Montgomery curves and their -//! arithmetic_][costello-smith] by Costello and Smith for more details. -//! -//! The `MontgomeryPoint` struct contains the affine \\(u\\)-coordinate -//! \\(u\_0(P)\\) of a point \\(P\\) on either the curve or the twist. -//! Here the map \\(u\_0 : \mathcal M \rightarrow \mathbb F\_p \\) is -//! defined by \\(u\_0((u,v)) = u\\); \\(u\_0(\mathcal O) = 0\\). See -//! section 5.4 of Costello-Smith for more details. -//! -//! # Scalar Multiplication -//! -//! Scalar multiplication on `MontgomeryPoint`s is provided by the `*` -//! operator, which implements the Montgomery ladder. -//! -//! # Edwards Conversion -//! -//! The \\(2\\)-to-\\(1\\) map from the Edwards model to the Montgomery -//! \\(u\\)-line is provided by `EdwardsPoint::to_montgomery()`. -//! -//! To lift a `MontgomeryPoint` to an `EdwardsPoint`, use -//! `MontgomeryPoint::to_edwards()`, which takes a sign parameter. -//! This function rejects `MontgomeryPoints` which correspond to points -//! on the twist. -//! -//! [costello-smith]: https://eprint.iacr.org/2017/212.pdf - -// We allow non snake_case names because coordinates in projective space are -// traditionally denoted by the capitalisation of their respective -// counterparts in affine space. Yeah, you heard me, rustc, I'm gonna have my -// affine and projective cakes and eat both of them too. -#![allow(non_snake_case)] - -use core::ops::{Mul, MulAssign}; - -#[cfg(not(feature = "betrusted"))] -use constants::{APLUS2_OVER_FOUR, MONTGOMERY_A, MONTGOMERY_A_NEG}; -#[cfg(feature = "betrusted")] -use constants::{MONTGOMERY_A, MONTGOMERY_A_NEG}; // eliminate constants absorbed into the microcode engine - -use edwards::{CompressedEdwardsY, EdwardsPoint}; -use field::FieldElement; -use scalar::Scalar; - -use traits::Identity; - -use subtle::Choice; -use subtle::ConstantTimeEq; -use subtle::{ConditionallyNegatable, ConditionallySelectable}; - -use zeroize::Zeroize; - -/// Holds the \\(u\\)-coordinate of a point on the Montgomery form of -/// Curve25519 or its twist. -#[derive(Copy, Clone, Debug, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct MontgomeryPoint(pub [u8; 32]); - -/// Equality of `MontgomeryPoint`s is defined mod p. -impl ConstantTimeEq for MontgomeryPoint { - fn ct_eq(&self, other: &MontgomeryPoint) -> Choice { - let self_fe = FieldElement::from_bytes(&self.0); - let other_fe = FieldElement::from_bytes(&other.0); - - self_fe.ct_eq(&other_fe) - } -} - -impl Default for MontgomeryPoint { - fn default() -> MontgomeryPoint { - MontgomeryPoint([0u8; 32]) - } -} - -impl PartialEq for MontgomeryPoint { - fn eq(&self, other: &MontgomeryPoint) -> bool { - self.ct_eq(other).unwrap_u8() == 1u8 - } -} - -impl Eq for MontgomeryPoint {} - -impl Identity for MontgomeryPoint { - /// Return the group identity element, which has order 4. - fn identity() -> MontgomeryPoint { - MontgomeryPoint([0u8; 32]) - } -} - -impl Zeroize for MontgomeryPoint { - fn zeroize(&mut self) { - self.0.zeroize(); - } -} - -impl MontgomeryPoint { - /// View this `MontgomeryPoint` as an array of bytes. - pub fn as_bytes<'a>(&'a self) -> &'a [u8; 32] { - &self.0 - } - - /// Convert this `MontgomeryPoint` to an array of bytes. - pub fn to_bytes(&self) -> [u8; 32] { - self.0 - } - - /// Attempt to convert to an `EdwardsPoint`, using the supplied - /// choice of sign for the `EdwardsPoint`. - /// - /// # Inputs - /// - /// * `sign`: a `u8` donating the desired sign of the resulting - /// `EdwardsPoint`. `0` denotes positive and `1` negative. - /// - /// # Return - /// - /// * `Some(EdwardsPoint)` if `self` is the \\(u\\)-coordinate of a - /// point on (the Montgomery form of) Curve25519; - /// - /// * `None` if `self` is the \\(u\\)-coordinate of a point on the - /// twist of (the Montgomery form of) Curve25519; - /// - pub fn to_edwards(&self, sign: u8) -> Option { - // To decompress the Montgomery u coordinate to an - // `EdwardsPoint`, we apply the birational map to obtain the - // Edwards y coordinate, then do Edwards decompression. - // - // The birational map is y = (u-1)/(u+1). - // - // The exceptional points are the zeros of the denominator, - // i.e., u = -1. - // - // But when u = -1, v^2 = u*(u^2+486662*u+1) = 486660. - // - // Since this is nonsquare mod p, u = -1 corresponds to a point - // on the twist, not the curve, so we can reject it early. - - let u = FieldElement::from_bytes(&self.0); - - if u == FieldElement::minus_one() { return None; } - - let one = FieldElement::one(); - - let y = &(&u - &one) * &(&u + &one).invert(); - - let mut y_bytes = y.to_bytes(); - y_bytes[31] ^= sign << 7; - - CompressedEdwardsY(y_bytes).decompress() - } -} - -/// Perform the Elligator2 mapping to a Montgomery point. -/// -/// See -// -// TODO Determine how much of the hash-to-group API should be exposed after the CFRG -// draft gets into a more polished/accepted state. -#[allow(unused)] -pub(crate) fn elligator_encode(r_0: &FieldElement) -> MontgomeryPoint { - let one = FieldElement::one(); - let d_1 = &one + &r_0.square2(); /* 2r^2 */ - - let d = &MONTGOMERY_A_NEG * &(d_1.invert()); /* A/(1+2r^2) */ - - let d_sq = &d.square(); - let au = &MONTGOMERY_A * &d; - - let inner = &(d_sq + &au) + &one; - let eps = &d * &inner; /* eps = d^3 + Ad^2 + d */ - - let (eps_is_sq, _eps) = FieldElement::sqrt_ratio_i(&eps, &one); - - let zero = FieldElement::zero(); - let Atemp = FieldElement::conditional_select(&MONTGOMERY_A, &zero, eps_is_sq); /* 0, or A if nonsquare*/ - let mut u = &d + &Atemp; /* d, or d+A if nonsquare */ - u.conditional_negate(!eps_is_sq); /* d, or -d-A if nonsquare */ - - MontgomeryPoint(u.to_bytes()) -} - -/// A `ProjectivePoint` holds a point on the projective line -/// \\( \mathbb P(\mathbb F\_p) \\), which we identify with the Kummer -/// line of the Montgomery curve. -#[derive(Copy, Clone, Debug)] -pub(crate) struct ProjectivePoint { - pub U: FieldElement, - pub W: FieldElement, -} - -impl Identity for ProjectivePoint { - fn identity() -> ProjectivePoint { - ProjectivePoint { - U: FieldElement::one(), - W: FieldElement::zero(), - } - } -} - -impl Default for ProjectivePoint { - fn default() -> ProjectivePoint { - ProjectivePoint::identity() - } -} - -impl ConditionallySelectable for ProjectivePoint { - fn conditional_select( - a: &ProjectivePoint, - b: &ProjectivePoint, - choice: Choice, - ) -> ProjectivePoint { - ProjectivePoint { - U: FieldElement::conditional_select(&a.U, &b.U, choice), - W: FieldElement::conditional_select(&a.W, &b.W, choice), - } - } -} - -impl ProjectivePoint { - /// Dehomogenize this point to affine coordinates. - /// - /// # Return - /// - /// * \\( u = U / W \\) if \\( W \neq 0 \\); - /// * \\( 0 \\) if \\( W \eq 0 \\); - #[cfg(not(feature = "betrusted"))] - pub fn to_affine(&self) -> MontgomeryPoint { - #[cfg(all(not(test),feature="betrusted"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. - log::warn!("sw to_affine being used - check for build config errors!"); - - let u = &self.U * &self.W.invert(); - MontgomeryPoint(u.to_bytes()) - } - #[allow(dead_code)] - #[cfg(feature = "betrusted")] - pub fn to_affine(&self) -> MontgomeryPoint { - let mcode = assemble_engine25519!( - start: - // W.invert() in %21 - // U in %29 - // W in %30 - // result in %31 - // loop counter in %28 - - // from FieldElement.invert() - // let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0 - // let t0 = self.square(); // 1 e_0 = 2^1 - mul %0, %30, %30 // self is W, e.g. %30 - // let t1 = t0.square().square(); // 3 e_1 = 2^3 - mul %1, %0, %0 - mul %1, %1, %1 - // let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0 - mul %2, %30, %1 - // let t3 = &t0 * &t2; // 3,1,0 - mul %3, %0, %2 - // let t4 = t3.square(); // 4,2,1 - mul %4, %3, %3 - // let t5 = &t2 * &t4; // 4,3,2,1,0 - mul %5, %2, %4 - - // let t6 = t5.pow2k(5); // 9,8,7,6,5 - psa %28, #5 // coincidentally, constant #5 is the number 5 - mul %6, %5, %5 - pow2k_5: - sub %28, %28, #1 // %28 = %28 - 1 - brz pow2k_5_exit, %28 - mul %6, %6, %6 - brz pow2k_5, #0 - pow2k_5_exit: - // let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0 - mul %7, %6, %5 - - // let t8 = t7.pow2k(10); // 19..10 - psa %28, #6 // constant #6 is the number 10 - mul %8, %7, %7 - pow2k_10: - sub %28, %28, #1 - brz pow2k_10_exit, %28 - mul %8, %8, %8 - brz pow2k_10, #0 - pow2k_10_exit: - // let t9 = &t8 * &t7; // 19..0 - mul %9, %8, %7 - - // let t10 = t9.pow2k(20); // 39..20 - psa %28, #7 // constant #7 is the number 20 - mul %10, %9, %9 - pow2k_20: - sub %28, %28, #1 - brz pow2k_20_exit, %28 - mul %10, %10, %10 - brz pow2k_20, #0 - pow2k_20_exit: - // let t11 = &t10 * &t9; // 39..0 - mul %11, %10, %9 - - // let t12 = t11.pow2k(10); // 49..10 - psa %28, #6 // constant #6 is the number 10 - mul %12, %11, %11 - pow2k_10b: - sub %28, %28, #1 - brz pow2k_10b_exit, %28 - mul %12, %12, %12 - brz pow2k_10b, #0 - pow2k_10b_exit: - // let t13 = &t12 * &t7; // 49..0 - mul %13, %12, %7 - - // let t14 = t13.pow2k(50); // 99..50 - psa %28, #8 // constant #8 is the number 50 - mul %14, %13, %13 - pow2k_50a: - sub %28, %28, #1 - brz pow2k_50a_exit, %28 - mul %14, %14, %14 - brz pow2k_50a, #0 - pow2k_50a_exit: - // let t15 = &t14 * &t13; // 99..0 - mul %15, %14, %13 - - // let t16 = t15.pow2k(100); // 199..100 - psa %28, #9 // constant #9 is the number 100 - mul %16, %15, %15 - pow2k_100: - sub %28, %28, #1 - brz pow2k_100_exit, %28 - mul %16, %16, %16 - brz pow2k_100, #0 - pow2k_100_exit: - // let t17 = &t16 * &t15; // 199..0 - mul %17, %16, %15 - - // let t18 = t17.pow2k(50); // 249..50 - psa %28, #8 // constant #8 is the number 50 - mul %18, %17, %17 - pow2k_50b: - sub %28, %28, #1 - brz pow2k_50b_exit, %28 - mul %18, %18, %18 - brz pow2k_50b, #0 - pow2k_50b_exit: - // let t19 = &t18 * &t13; // 249..0 - mul %19, %18, %13 - //(t19, t3) // just a return value, values are already there, do nothing - - //let t20 = t19.pow2k(5); // 254..5 - psa %28, #5 - mul %20, %19, %19 - pow2k_5_last: - sub %28, %28, #1 - brz pow2k_5_last_exit, %28 - mul %20, %20, %20 - brz pow2k_5_last, #0 - pow2k_5_last_exit: - - //let t21 = &t20 * &t3; // 254..5,3,1,0 - mul %21, %20, %3 - - // u = &self.U * &self.W.invert() - mul %31, %29, %21 - fin // finish execution - ); - let mut engine = engine_25519::Engine25519::new(); - let mut job = engine_25519::Job { - id: None, - ucode: [0; 1024], - uc_len: mcode.len() as u32, - uc_start: 0, - window: Some(0), - rf: [0; engine_25519::RF_SIZE_IN_U32], - }; - for (&src, dst) in mcode.iter().zip(job.ucode.iter_mut()) { - *dst = src as u32; - } - copy_to_rf(self.U.to_bytes(), 29, &mut job.rf); - copy_to_rf(self.W.to_bytes(), 30, &mut job.rf); - - // start the run - let result_rf = engine.spawn_job(job).expect("couldn't run engine job"); - - MontgomeryPoint(copy_from_rf(31, &result_rf)) - } -} - -/// Perform the double-and-add step of the Montgomery ladder. -/// -/// Given projective points -/// \\( (U\_P : W\_P) = u(P) \\), -/// \\( (U\_Q : W\_Q) = u(Q) \\), -/// and the affine difference -/// \\( u\_{P-Q} = u(P-Q) \\), set -/// $$ -/// (U\_P : W\_P) \gets u([2]P) -/// $$ -/// and -/// $$ -/// (U\_Q : W\_Q) \gets u(P + Q). -/// $$ -#[cfg(not(feature = "betrusted"))] -pub(crate) fn differential_add_and_double( - P: &mut ProjectivePoint, - Q: &mut ProjectivePoint, - affine_PmQ: &FieldElement, -) { - let t0 = &P.U + &P.W; - let t1 = &P.U - &P.W; - let t2 = &Q.U + &Q.W; - let t3 = &Q.U - &Q.W; - - let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 - let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 - - let t6 = &t4 - &t5; // 4 U_P W_P - - let t7 = &t0 * &t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q - let t8 = &t1 * &t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q - - let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) - let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) - - let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 - let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 - - let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q - - let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 - let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P - - let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) - - let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 - let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 - - P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 - P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) - Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 - Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 -} - -#[cfg(feature = "betrusted")] -fn copy_to_rf(bytes: [u8; 32], register: usize, rf: &mut [u32; engine_25519::RF_SIZE_IN_U32]) { - use core::convert::TryInto; - for (byte, rf_dst) in bytes.chunks_exact(4).zip(rf[register * 8..(register+1)*8].iter_mut()) { - *rf_dst = u32::from_le_bytes(byte.try_into().expect("chunks_exact failed us")); - } -} - -#[cfg(feature = "betrusted")] -fn copy_from_rf(register: usize, rf: &[u32; engine_25519::RF_SIZE_IN_U32]) -> [u8; 32] { - let mut ret: [u8; 32] = [0; 32]; - - for (src, dst) in rf[register*8 .. (register+1)*8].iter().zip(ret.chunks_exact_mut(4).into_iter()) { - for (&src_byte, dst_byte) in src.to_le_bytes().iter().zip(dst.iter_mut()) { - *dst_byte = src_byte; - } - } - - ret -} - -#[allow(dead_code)] // absorbed into mul, but might be useful later on as a subroutine for something else -#[cfg(feature = "betrusted")] -pub(crate) fn differential_add_and_double_hw( - P: &mut ProjectivePoint, - Q: &mut ProjectivePoint, - affine_PmQ: &FieldElement, -) { - let mcode = assemble_engine25519!( - start: - // P.U in %20 - // P.W in %21 - // Q.U in %22 - // Q.W in %23 - // affine_PmQ in %24 - // %30 is the TRD scratch register - // %29 is the subtraction temporary value register - - // let t0 = &P.U + &P.W; - add %0, %20, %21 - trd %30, %0 - sub %0, %0, %30 - // let t1 = &P.U - &P.W; - sub %21, #3, %21 // negate &P.W using #FIELDPRIME (#3) - add %1, %20, %21 - trd %30, %1 - sub %1, %1, %30 - // let t2 = &Q.U + &Q.W; - add %2, %22, %23 - trd %30, %2 - sub %2, %2, %30 - // let t3 = &Q.U - &Q.W; - sub %23, #3, %23 - add %3, %22, %23 - trd %30, %3 - sub %3, %3, %30 - // let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 - mul %4, %0, %0 - // let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 - mul %5, %1, %1 - // let t6 = &t4 - &t5; // 4 U_P W_P - sub %29, #3, %5 - add %6, %4, %29 - trd %30, %6 - sub %6, %6, %30 - // let t7 = &t0 * &t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q - mul %7, %0, %3 - // let t8 = &t1 * &t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q - mul %8, %1, %2 - // let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) - add %9, %7, %8 - trd %30, %9 - sub %9, %9, %30 - // let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) - sub %29, #3, %8 - add %10, %7, %29 - trd %30, %10 - sub %10, %10, %30 - // let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 - mul %11, %9, %9 - // let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 - mul %12, %10, %10 - // let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q - mul %13, #4, %6 // #4 is A+2/4 - // let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 - mul %14, %4, %5 - // let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P - add %15, %13, %5 - trd %30, %15 - sub %15, %15, %30 - // let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) - mul %16, %6, %15 - // let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 - mul %17, %24, %12 // affine_PmQ loaded into %24 - - ///// these can be eliminated down the road, but included for 1:1 algorithm correspodence to reference in early testing - // let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 - psa %18, %11 - // P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 - psa %20, %14 - // P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) - psa %21, %16 - // Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 - psa %22, %18 - // Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 - psa %23, %17 - - fin // finish execution - ); - let mut engine = engine_25519::Engine25519::new(); - - let mut job = engine_25519::Job { - id: None, - ucode: [0; 1024], - uc_len: mcode.len() as u32, - uc_start: 0, - window: Some(0), - rf: [0; engine_25519::RF_SIZE_IN_U32], - }; - - for (&src, dst) in mcode.iter().zip(job.ucode.iter_mut()) { - *dst = src; - } - - // P.U in %20 - // P.W in %21 - // Q.U in %22 - // Q.W in %23 - // affine_PmQ in %24 - copy_to_rf(P.U.to_bytes(), 20, &mut job.rf); - copy_to_rf(P.W.to_bytes(), 21, &mut job.rf); - copy_to_rf(Q.U.to_bytes(), 22, &mut job.rf); - copy_to_rf(Q.W.to_bytes(), 23, &mut job.rf); - copy_to_rf(affine_PmQ.to_bytes(), 24, &mut job.rf); - - // start the run - let result_rf = engine.spawn_job(job).expect("couldn't run engine job"); - - P.U = FieldElement::from_bytes(©_from_rf(20, &result_rf)); - P.W = FieldElement::from_bytes(©_from_rf(21, &result_rf)); - Q.U = FieldElement::from_bytes(©_from_rf(22, &result_rf)); - Q.W = FieldElement::from_bytes(©_from_rf(23, &result_rf)); -} - -define_mul_assign_variants!(LHS = MontgomeryPoint, RHS = Scalar); - -define_mul_variants!(LHS = MontgomeryPoint, RHS = Scalar, Output = MontgomeryPoint); -define_mul_variants!(LHS = Scalar, RHS = MontgomeryPoint, Output = MontgomeryPoint); - -/// Multiply this `MontgomeryPoint` by a `Scalar`. -impl<'a, 'b> Mul<&'b Scalar> for &'a MontgomeryPoint { - type Output = MontgomeryPoint; - - /// Given `self` \\( = u\_0(P) \\), and a `Scalar` \\(n\\), return \\( u\_0([n]P) \\). - #[cfg(feature = "betrusted")] - fn mul(self, scalar: &'b Scalar) -> MontgomeryPoint { - log::debug!("hw mont"); - // Algorithm 8 of Costello-Smith 2017 - let affine_u = FieldElement::from_bytes(&self.0); - let mut x0 = ProjectivePoint::identity(); - let x1 = ProjectivePoint { - U: affine_u, - W: FieldElement::one(), - }; - - // for now, prefer to use the fully-accelerated version where this code is local to the server - // instead of transmitting it every call with the data...gives about a 2x performance speedup - if false { - #[cfg(not(test))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. - log::warn!("wrong multiply being used!"); - - let mcode = assemble_engine25519!( - start: - // P.U in %20 - // P.W in %21 - // Q.U in %22 - // Q.W in %23 - // affine_PmQ in %24 - // %30 is the TRD scratch register and cswap dummy - // %29 is the subtraction temporary value register and k_t - // x0.U in %25 - // x0.W in %26 - // x1.U in %27 - // x1.W in %28 - // %19 is the loop counter, starts with 254 (if 0, loop runs exactly once) - // %31 is the scalar - // %18 is the swap variable - psa %18, #0 - - // for i in (0..255).rev() - mainloop: - // let choice: u8 = (bits[i + 1] ^ bits[i]) as u8; - // ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into()); - xbt %29, %31 // orignally[k_t = (k>>t) & 1] now[k_t = k[254]] - shl %31, %31 // k = k<<1 - xor %18, %18, %29 // swap ^= k_t - - // cswap x0.U (%25), x1.U (%27) - xor %30, %25, %27 - msk %30, %18, %30 - xor %25, %30, %25 - xor %27, %30, %27 - // cswap x0.W (%26), x1.W (%28) - xor %30, %26, %28 - msk %30, %18, %30 - xor %26, %30, %26 - xor %28, %30, %28 - - psa %18, %29 // swap = k_t - - // differential_add_and_double(&mut x0, &mut x1, &affine_u); - psa %20, %25 - psa %21, %26 - psa %22, %27 - psa %23, %28 - // affine_u is already in %24 - - // let t0 = &P.U + &P.W; - add %0, %20, %21 - trd %30, %0 - sub %0, %0, %30 - // let t1 = &P.U - &P.W; - sub %21, #3, %21 // negate &P.W using #FIELDPRIME (#3) - add %1, %20, %21 - trd %30, %1 - sub %1, %1, %30 - // let t2 = &Q.U + &Q.W; - add %2, %22, %23 - trd %30, %2 - sub %2, %2, %30 - // let t3 = &Q.U - &Q.W; - sub %23, #3, %23 - add %3, %22, %23 - trd %30, %3 - sub %3, %3, %30 - // let t4 = t0.square(); // (U_P + W_P)^2 = U_P^2 + 2 U_P W_P + W_P^2 - mul %4, %0, %0 - // let t5 = t1.square(); // (U_P - W_P)^2 = U_P^2 - 2 U_P W_P + W_P^2 - mul %5, %1, %1 - // let t6 = &t4 - &t5; // 4 U_P W_P - sub %29, #3, %5 - add %6, %4, %29 - trd %30, %6 - sub %6, %6, %30 - // let t7 = &t0 * &t3; // (U_P + W_P) (U_Q - W_Q) = U_P U_Q + W_P U_Q - U_P W_Q - W_P W_Q - mul %7, %0, %3 - // let t8 = &t1 * &t2; // (U_P - W_P) (U_Q + W_Q) = U_P U_Q - W_P U_Q + U_P W_Q - W_P W_Q - mul %8, %1, %2 - // let t9 = &t7 + &t8; // 2 (U_P U_Q - W_P W_Q) - add %9, %7, %8 - trd %30, %9 - sub %9, %9, %30 - // let t10 = &t7 - &t8; // 2 (W_P U_Q - U_P W_Q) - sub %29, #3, %8 - add %10, %7, %29 - trd %30, %10 - sub %10, %10, %30 - // let t11 = t9.square(); // 4 (U_P U_Q - W_P W_Q)^2 - mul %11, %9, %9 - // let t12 = t10.square(); // 4 (W_P U_Q - U_P W_Q)^2 - mul %12, %10, %10 - // let t13 = &APLUS2_OVER_FOUR * &t6; // (A + 2) U_P U_Q - mul %13, #4, %6 // #4 is A+2/4 - // let t14 = &t4 * &t5; // ((U_P + W_P)(U_P - W_P))^2 = (U_P^2 - W_P^2)^2 - mul %14, %4, %5 - // let t15 = &t13 + &t5; // (U_P - W_P)^2 + (A + 2) U_P W_P - add %15, %13, %5 - trd %30, %15 - sub %15, %15, %30 - // let t16 = &t6 * &t15; // 4 (U_P W_P) ((U_P - W_P)^2 + (A + 2) U_P W_P) - mul %16, %6, %15 - // let t17 = affine_PmQ * &t12; // U_D * 4 (W_P U_Q - U_P W_Q)^2 - mul %17, %24, %12 // affine_PmQ loaded into %24 - - ///// these can be eliminated down the road, but included for 1:1 algorithm correspodence to reference in early testing - // P.U = t14; // U_{P'} = (U_P + W_P)^2 (U_P - W_P)^2 - psa %20, %14 - // P.W = t16; // W_{P'} = (4 U_P W_P) ((U_P - W_P)^2 + ((A + 2)/4) 4 U_P W_P) - psa %21, %16 - // let t18 = t11; // W_D * 4 (U_P U_Q - W_P W_Q)^2 - // Q.U = t18; // U_{Q'} = W_D * 4 (U_P U_Q - W_P W_Q)^2 - psa %22, %11 // collapsed two to save a register - // Q.W = t17; // W_{Q'} = U_D * 4 (W_P U_Q - U_P W_Q)^2 - psa %23, %17 - - ///// 'return' arguments for next iteration, can be optimized out later - psa %25, %20 - psa %26, %21 - psa %27, %22 - psa %28, %23 - - brz end, %19 // if loop counter is 0, quit - sub %19, %19, #1 // subtract one from the loop counter and run again - brz mainloop, #0 // go back to the top - end: - // ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8)); - // cswap x0.U (%25), x1.U (%27) - xor %30, %25, %27 - msk %30, %18, %30 - xor %25, %30, %25 - xor %27, %30, %27 - // cswap x0.W (%26), x1.W (%28) - xor %30, %26, %28 - msk %30, %18, %30 - xor %26, %30, %26 - xor %28, %30, %28 - - // AFFINE SPLICE -- pass arguments to the affine block - psa %29, %25 - psa %30, %26 - // W.invert() in %21 - // U in %29 - // W in %30 - // result in %31 - // loop counter in %28 - - // from FieldElement.invert() - // let (t19, t3) = self.pow22501(); // t19: 249..0 ; t3: 3,1,0 - // let t0 = self.square(); // 1 e_0 = 2^1 - mul %0, %30, %30 // self is W, e.g. %30 - // let t1 = t0.square().square(); // 3 e_1 = 2^3 - mul %1, %0, %0 - mul %1, %1, %1 - // let t2 = self * &t1; // 3,0 e_2 = 2^3 + 2^0 - mul %2, %30, %1 - // let t3 = &t0 * &t2; // 3,1,0 - mul %3, %0, %2 - // let t4 = t3.square(); // 4,2,1 - mul %4, %3, %3 - // let t5 = &t2 * &t4; // 4,3,2,1,0 - mul %5, %2, %4 - - // let t6 = t5.pow2k(5); // 9,8,7,6,5 - psa %28, #5 // coincidentally, constant #5 is the number 5 - mul %6, %5, %5 - pow2k_5: - sub %28, %28, #1 // %28 = %28 - 1 - brz pow2k_5_exit, %28 - mul %6, %6, %6 - brz pow2k_5, #0 - pow2k_5_exit: - // let t7 = &t6 * &t5; // 9,8,7,6,5,4,3,2,1,0 - mul %7, %6, %5 - - // let t8 = t7.pow2k(10); // 19..10 - psa %28, #6 // constant #6 is the number 10 - mul %8, %7, %7 - pow2k_10: - sub %28, %28, #1 - brz pow2k_10_exit, %28 - mul %8, %8, %8 - brz pow2k_10, #0 - pow2k_10_exit: - // let t9 = &t8 * &t7; // 19..0 - mul %9, %8, %7 - - // let t10 = t9.pow2k(20); // 39..20 - psa %28, #7 // constant #7 is the number 20 - mul %10, %9, %9 - pow2k_20: - sub %28, %28, #1 - brz pow2k_20_exit, %28 - mul %10, %10, %10 - brz pow2k_20, #0 - pow2k_20_exit: - // let t11 = &t10 * &t9; // 39..0 - mul %11, %10, %9 - - // let t12 = t11.pow2k(10); // 49..10 - psa %28, #6 // constant #6 is the number 10 - mul %12, %11, %11 - pow2k_10b: - sub %28, %28, #1 - brz pow2k_10b_exit, %28 - mul %12, %12, %12 - brz pow2k_10b, #0 - pow2k_10b_exit: - // let t13 = &t12 * &t7; // 49..0 - mul %13, %12, %7 - - // let t14 = t13.pow2k(50); // 99..50 - psa %28, #8 // constant #8 is the number 50 - mul %14, %13, %13 - pow2k_50a: - sub %28, %28, #1 - brz pow2k_50a_exit, %28 - mul %14, %14, %14 - brz pow2k_50a, #0 - pow2k_50a_exit: - // let t15 = &t14 * &t13; // 99..0 - mul %15, %14, %13 - - // let t16 = t15.pow2k(100); // 199..100 - psa %28, #9 // constant #9 is the number 100 - mul %16, %15, %15 - pow2k_100: - sub %28, %28, #1 - brz pow2k_100_exit, %28 - mul %16, %16, %16 - brz pow2k_100, #0 - pow2k_100_exit: - // let t17 = &t16 * &t15; // 199..0 - mul %17, %16, %15 - - // let t18 = t17.pow2k(50); // 249..50 - psa %28, #8 // constant #8 is the number 50 - mul %18, %17, %17 - pow2k_50b: - sub %28, %28, #1 - brz pow2k_50b_exit, %28 - mul %18, %18, %18 - brz pow2k_50b, #0 - pow2k_50b_exit: - // let t19 = &t18 * &t13; // 249..0 - mul %19, %18, %13 - //(t19, t3) // just a return value, values are already there, do nothing - - //let t20 = t19.pow2k(5); // 254..5 - psa %28, #5 - mul %20, %19, %19 - pow2k_5_last: - sub %28, %28, #1 - brz pow2k_5_last_exit, %28 - mul %20, %20, %20 - brz pow2k_5_last, #0 - pow2k_5_last_exit: - - //let t21 = &t20 * &t3; // 254..5,3,1,0 - mul %21, %20, %3 - - // u = &self.U * &self.W.invert() - mul %31, %29, %21 - fin // finish execution - ); - let mut engine = engine_25519::Engine25519::new(); - let mut job = engine_25519::Job { - id: None, - ucode: [0; 1024], - uc_len: mcode.len() as u32, - uc_start: 0, - window: Some(0), - rf: [0; engine_25519::RF_SIZE_IN_U32], - }; - - for (&src, dst) in mcode.iter().zip(job.ucode.iter_mut()) { - *dst = src as u32; - } - - copy_to_rf(x0.U.to_bytes(), 25, &mut job.rf); - copy_to_rf(x0.W.to_bytes(), 26, &mut job.rf); - copy_to_rf(x1.U.to_bytes(), 27, &mut job.rf); - copy_to_rf(x1.W.to_bytes(), 28, &mut job.rf); - copy_to_rf(affine_u.to_bytes(), 24, &mut job.rf); - copy_to_rf(scalar.bytes, 31, &mut job.rf); - // load the number 254 into the loop index register - copy_to_rf([ - 254, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - ], 19, &mut job.rf); - - // start the run - let result_rf = engine.spawn_job(job).expect("couldn't run engine job"); - - if false { // unmerged affine path - x0.U = FieldElement::from_bytes(©_from_rf(25, &result_rf)); - x0.W = FieldElement::from_bytes(©_from_rf(26, &result_rf)); - - // TODO: optimize this relatively innocuous looking call. - // this consumes about 100ms runtime -- need to implement this using - // curve25519 acceleration! - x0.to_affine() - } else { - MontgomeryPoint(copy_from_rf(31, &result_rf)) - } - } else { - let mut engine = engine_25519::Engine25519::new(); - let job = engine_25519::MontgomeryJob { - x0_u: x0.U.to_bytes(), - x0_w: x0.W.to_bytes(), - x1_u: x1.U.to_bytes(), - x1_w: x1.W.to_bytes(), - affine_u: affine_u.to_bytes(), - scalar: scalar.bytes, - }; - - MontgomeryPoint(engine.montgomery_job(job).expect("couldn't run montgomery multiply job")) - } - } - #[cfg(not(feature = "betrusted"))] - fn mul(self, scalar: &'b Scalar) -> MontgomeryPoint { - // Algorithm 8 of Costello-Smith 2017 - #[cfg(all(not(test),feature="betrusted"))] // due to issue https://github.com/rust-lang/rust/issues/59168, you will have to manually comment this out when running a test on the full system and not just this crate. - log::warn!("sw montgomery multiply being used - check for build config errors!"); - let affine_u = FieldElement::from_bytes(&self.0); - let mut x0 = ProjectivePoint::identity(); - let mut x1 = ProjectivePoint { - U: affine_u, - W: FieldElement::one(), - }; - - let bits: [i8; 256] = scalar.bits(); - - for i in (0..255).rev() { - let choice: u8 = (bits[i + 1] ^ bits[i]) as u8; - - debug_assert!(choice == 0 || choice == 1); - - ProjectivePoint::conditional_swap(&mut x0, &mut x1, choice.into()); - differential_add_and_double(&mut x0, &mut x1, &affine_u); - } - ProjectivePoint::conditional_swap(&mut x0, &mut x1, Choice::from(bits[0] as u8)); - - x0.to_affine() - } -} - -impl<'b> MulAssign<&'b Scalar> for MontgomeryPoint { - fn mul_assign(&mut self, scalar: &'b Scalar) { - *self = (self as &MontgomeryPoint) * scalar; - } -} - -impl<'a, 'b> Mul<&'b MontgomeryPoint> for &'a Scalar { - type Output = MontgomeryPoint; - - fn mul(self, point: &'b MontgomeryPoint) -> MontgomeryPoint { - point * self - } -} - -// ------------------------------------------------------------------------ -// Tests -// ------------------------------------------------------------------------ - -#[cfg(test)] -mod test { - use super::*; - use constants; - use core::convert::TryInto; - - use rand_core::OsRng; - - #[test] - fn identity_in_different_coordinates() { - let id_projective = ProjectivePoint::identity(); - let id_montgomery = id_projective.to_affine(); - - assert!(id_montgomery == MontgomeryPoint::identity()); - } - - #[test] - fn identity_in_different_models() { - assert!(EdwardsPoint::identity().to_montgomery() == MontgomeryPoint::identity()); - } - - #[test] - #[cfg(feature = "serde")] - fn serde_bincode_basepoint_roundtrip() { - use bincode; - - let encoded = bincode::serialize(&constants::X25519_BASEPOINT).unwrap(); - let decoded: MontgomeryPoint = bincode::deserialize(&encoded).unwrap(); - - assert_eq!(encoded.len(), 32); - assert_eq!(decoded, constants::X25519_BASEPOINT); - - let raw_bytes = constants::X25519_BASEPOINT.as_bytes(); - let bp: MontgomeryPoint = bincode::deserialize(raw_bytes).unwrap(); - assert_eq!(bp, constants::X25519_BASEPOINT); - } - - /// Test Montgomery -> Edwards on the X/Ed25519 basepoint - #[test] - fn basepoint_montgomery_to_edwards() { - // sign bit = 0 => basepoint - assert_eq!( - constants::ED25519_BASEPOINT_POINT, - constants::X25519_BASEPOINT.to_edwards(0).unwrap() - ); - // sign bit = 1 => minus basepoint - assert_eq!( - - constants::ED25519_BASEPOINT_POINT, - constants::X25519_BASEPOINT.to_edwards(1).unwrap() - ); - } - - /// Test Edwards -> Montgomery on the X/Ed25519 basepoint - #[test] - fn basepoint_edwards_to_montgomery() { - assert_eq!( - constants::ED25519_BASEPOINT_POINT.to_montgomery(), - constants::X25519_BASEPOINT - ); - } - - /// Check that Montgomery -> Edwards fails for points on the twist. - #[test] - fn montgomery_to_edwards_rejects_twist() { - let one = FieldElement::one(); - - // u = 2 corresponds to a point on the twist. - let two = MontgomeryPoint((&one+&one).to_bytes()); - - assert!(two.to_edwards(0).is_none()); - - // u = -1 corresponds to a point on the twist, but should be - // checked explicitly because it's an exceptional point for the - // birational map. For instance, libsignal will accept it. - let minus_one = MontgomeryPoint((-&one).to_bytes()); - - assert!(minus_one.to_edwards(0).is_none()); - } - - #[test] - fn eq_defined_mod_p() { - let mut u18_bytes = [0u8; 32]; u18_bytes[0] = 18; - let u18 = MontgomeryPoint(u18_bytes); - let u18_unred = MontgomeryPoint([255; 32]); - - assert_eq!(u18, u18_unred); - } - - #[test] - fn montgomery_ladder_matches_edwards_scalarmult() { - let mut csprng: OsRng = OsRng; - - let s: Scalar = Scalar::random(&mut csprng); - let p_edwards: EdwardsPoint = &constants::ED25519_BASEPOINT_TABLE * &s; - let p_montgomery: MontgomeryPoint = p_edwards.to_montgomery(); - - let expected = s * p_edwards; - let result = s * p_montgomery; - - assert_eq!(result, expected.to_montgomery()) - } - - const ELLIGATOR_CORRECT_OUTPUT: [u8; 32] = [ - 0x5f, 0x35, 0x20, 0x00, 0x1c, 0x6c, 0x99, 0x36, 0xa3, 0x12, 0x06, 0xaf, 0xe7, 0xc7, 0xac, - 0x22, 0x4e, 0x88, 0x61, 0x61, 0x9b, 0xf9, 0x88, 0x72, 0x44, 0x49, 0x15, 0x89, 0x9d, 0x95, - 0xf4, 0x6e, - ]; - - #[test] - #[cfg(feature = "std")] // Vec - fn montgomery_elligator_correct() { - let bytes: std::vec::Vec = (0u8..32u8).collect(); - let bits_in: [u8; 32] = (&bytes[..]).try_into().expect("Range invariant broken"); - - let fe = FieldElement::from_bytes(&bits_in); - let eg = elligator_encode(&fe); - assert_eq!(eg.to_bytes(), ELLIGATOR_CORRECT_OUTPUT); - } - - #[test] - fn montgomery_elligator_zero_zero() { - let zero = [0u8; 32]; - let fe = FieldElement::from_bytes(&zero); - let eg = elligator_encode(&fe); - assert_eq!(eg.to_bytes(), zero); - } -} diff --git a/src/window.rs b/src/window.rs deleted file mode 100644 index 2cf1fbe7e..000000000 --- a/src/window.rs +++ /dev/null @@ -1,228 +0,0 @@ -// -*- mode: rust; -*- -// -// This file is part of curve25519-dalek. -// Copyright (c) 2016-2021 isis lovecruft -// Copyright (c) 2016-2019 Henry de Valence -// See LICENSE for licensing information. -// -// Authors: -// - isis agora lovecruft -// - Henry de Valence - -//! Code for fixed- and sliding-window functionality - -#![allow(non_snake_case)] - -use core::fmt::Debug; - -use subtle::ConditionallyNegatable; -use subtle::ConditionallySelectable; -use subtle::ConstantTimeEq; -use subtle::Choice; - -use traits::Identity; - -use edwards::EdwardsPoint; -use backend::serial::curve_models::ProjectiveNielsPoint; -use backend::serial::curve_models::AffineNielsPoint; - -use zeroize::Zeroize; - -macro_rules! impl_lookup_table { - (Name = $name:ident, Size = $size:expr, SizeNeg = $neg:expr, SizeRange = $range:expr, ConversionRange = $conv_range:expr) => { - -/// A lookup table of precomputed multiples of a point \\(P\\), used to -/// compute \\( xP \\) for \\( -8 \leq x \leq 8 \\). -/// -/// The computation of \\( xP \\) is done in constant time by the `select` function. -/// -/// Since `LookupTable` does not implement `Index`, it's more difficult -/// to accidentally use the table directly. Unfortunately the table is -/// only `pub(crate)` so that we can write hardcoded constants, so it's -/// still technically possible. It would be nice to prevent direct -/// access to the table. -#[derive(Copy, Clone)] -pub struct $name(pub(crate) [T; $size]); - -impl $name -where - T: Identity + ConditionallySelectable + ConditionallyNegatable, -{ - /// Given \\(-8 \leq x \leq 8\\), return \\(xP\\) in constant time. - pub fn select(&self, x: i8) -> T { - debug_assert!(x >= $neg); - debug_assert!(x as i16 <= $size as i16); // XXX We have to convert to i16s here for the radix-256 case.. this is wrong. - - // Compute xabs = |x| - let xmask = x as i16 >> 7; - let xabs = (x as i16 + xmask) ^ xmask; - - // Set t = 0 * P = identity - let mut t = T::identity(); - for j in $range { - // Copy `points[j-1] == j*P` onto `t` in constant time if `|x| == j`. - let c = (xabs as u16).ct_eq(&(j as u16)); - t.conditional_assign(&self.0[j - 1], c); - } - // Now t == |x| * P. - - let neg_mask = Choice::from((xmask & 1) as u8); - t.conditional_negate(neg_mask); - // Now t == x * P. - - t - } -} - -impl Default for $name { - fn default() -> $name { - $name([T::default(); $size]) - } -} - -impl Debug for $name { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "{:?}(", stringify!($name))?; - - for x in self.0.iter() { - write!(f, "{:?}", x)?; - } - - write!(f, ")") - } -} - -impl<'a> From<&'a EdwardsPoint> for $name { - fn from(P: &'a EdwardsPoint) -> Self { - let mut points = [P.to_projective_niels(); $size]; - for j in $conv_range { - points[j + 1] = (P + &points[j]).to_extended().to_projective_niels(); - } - $name(points) - } -} - -impl<'a> From<&'a EdwardsPoint> for $name { - fn from(P: &'a EdwardsPoint) -> Self { - let mut points = [P.to_affine_niels(); $size]; - // XXX batch inversion would be good if perf mattered here - for j in $conv_range { - points[j + 1] = (P + &points[j]).to_extended().to_affine_niels() - } - $name(points) - } -} - -impl Zeroize for $name -where - T: Copy + Default + Zeroize -{ - fn zeroize(&mut self) { - for x in self.0.iter_mut() { - x.zeroize(); - } - } -} - -}} // End macro_rules! impl_lookup_table - -// The first one has to be named "LookupTable" because it's used as a constructor for consts. -impl_lookup_table! {Name = LookupTable, Size = 8, SizeNeg = -8, SizeRange = 1 .. 9, ConversionRange = 0 .. 7} // radix-16 -impl_lookup_table! {Name = LookupTableRadix32, Size = 16, SizeNeg = -16, SizeRange = 1 .. 17, ConversionRange = 0 .. 15} // radix-32 -impl_lookup_table! {Name = LookupTableRadix64, Size = 32, SizeNeg = -32, SizeRange = 1 .. 33, ConversionRange = 0 .. 31} // radix-64 -impl_lookup_table! {Name = LookupTableRadix128, Size = 64, SizeNeg = -64, SizeRange = 1 .. 65, ConversionRange = 0 .. 63} // radix-128 -impl_lookup_table! {Name = LookupTableRadix256, Size = 128, SizeNeg = -128, SizeRange = 1 .. 129, ConversionRange = 0 .. 127} // radix-256 - -// For homogeneity we then alias it to "LookupTableRadix16". -pub type LookupTableRadix16 = LookupTable; - -/// Holds odd multiples 1A, 3A, ..., 15A of a point A. -#[derive(Copy, Clone)] -pub(crate) struct NafLookupTable5(pub(crate) [T; 8]); - -impl NafLookupTable5 { - /// Given public, odd \\( x \\) with \\( 0 < x < 2^4 \\), return \\(xA\\). - pub fn select(&self, x: usize) -> T { - debug_assert_eq!(x & 1, 1); - debug_assert!(x < 16); - - self.0[x / 2] - } -} - -impl Debug for NafLookupTable5 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "NafLookupTable5({:?})", self.0) - } -} - -impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { - fn from(A: &'a EdwardsPoint) -> Self { - let mut Ai = [A.to_projective_niels(); 8]; - let A2 = A.double(); - for i in 0..7 { - Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); - } - // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] - NafLookupTable5(Ai) - } -} - -impl<'a> From<&'a EdwardsPoint> for NafLookupTable5 { - fn from(A: &'a EdwardsPoint) -> Self { - let mut Ai = [A.to_affine_niels(); 8]; - let A2 = A.double(); - for i in 0..7 { - Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); - } - // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A] - NafLookupTable5(Ai) - } -} - -/// Holds stuff up to 8. -#[derive(Copy, Clone)] -pub(crate) struct NafLookupTable8(pub(crate) [T; 64]); - -impl NafLookupTable8 { - pub fn select(&self, x: usize) -> T { - debug_assert_eq!(x & 1, 1); - debug_assert!(x < 128); - - self.0[x / 2] - } -} - -impl Debug for NafLookupTable8 { - fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result { - write!(f, "NafLookupTable8([\n")?; - for i in 0..64 { - write!(f, "\t{:?},\n", &self.0[i])?; - } - write!(f, "])") - } -} - -impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { - fn from(A: &'a EdwardsPoint) -> Self { - let mut Ai = [A.to_projective_niels(); 64]; - let A2 = A.double(); - for i in 0..63 { - Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_projective_niels(); - } - // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] - NafLookupTable8(Ai) - } -} - -impl<'a> From<&'a EdwardsPoint> for NafLookupTable8 { - fn from(A: &'a EdwardsPoint) -> Self { - let mut Ai = [A.to_affine_niels(); 64]; - let A2 = A.double(); - for i in 0..63 { - Ai[i + 1] = (&A2 + &Ai[i]).to_extended().to_affine_niels(); - } - // Now Ai = [A, 3A, 5A, 7A, 9A, 11A, 13A, 15A, ..., 127A] - NafLookupTable8(Ai) - } -} diff --git a/x25519-dalek/.gitignore b/x25519-dalek/.gitignore new file mode 100644 index 000000000..da57a4b2a --- /dev/null +++ b/x25519-dalek/.gitignore @@ -0,0 +1,13 @@ +target/ +**/*.rs.bk + +.cargo + +*~ +\#* +.\#* +*.swp +*.orig +*.bak + +*.s diff --git a/x25519-dalek/.travis.yml b/x25519-dalek/.travis.yml new file mode 100644 index 000000000..eceb10e85 --- /dev/null +++ b/x25519-dalek/.travis.yml @@ -0,0 +1,26 @@ +language: rust + +rust: + - nightly + +env: + - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='default' + - TEST_COMMAND=test EXTRA_FLAGS='' FEATURES='nightly' + - TEST_COMMAND=bench EXTRA_FLAGS='' FEATURES='default' + - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u32_backend nightly' + - TEST_COMMAND=build EXTRA_FLAGS='--no-default-features' FEATURES='u64_backend nightly' + +matrix: + include: + - rust: stable + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' + - rust: beta + env: TEST_COMMAND=test EXTRA_FLAGS='--no-default-features' FEATURES='std u64_backend' + +script: + - cargo $TEST_COMMAND --features="$FEATURES" $EXTRA_FLAGS + +notifications: + slack: + rooms: + - dalek-cryptography:Xxv9WotKYWdSoKlgKNqXiHoD#dalek-bots diff --git a/x25519-dalek/CHANGELOG.md b/x25519-dalek/CHANGELOG.md new file mode 100644 index 000000000..10e1a5454 --- /dev/null +++ b/x25519-dalek/CHANGELOG.md @@ -0,0 +1,102 @@ +# Changelog + +Entries are listed in reverse chronological order. + +# 2.x Series + +* Note: All `x255919-dalek` 2.x releases are in sync with the underlying `curve25519-dalek` 4.x releases. + +## 2.0.1 + +* Fix nightly SIMD build + +## 2.0.0-rc.3 + +* `StaticSecret` serialization and `to_bytes()` no longer returns clamped integers. Clamping is still always done during scalar-point multiplication. +* Update underlying `curve25519_dalek` library to `4.0.0-rc.3`. Notable changes: + * [curve25519-dalek backend] now by default auto selects `simd` backend over `serial` where supported. + + +## 2.0.0-rc.2 + +* Update MSRV to 1.60. +* Update edition to 2021 +* Add `.as_bytes()` and `AsRef<[u8]>` for `Shared/StaticSecret` +* Add `getrandom` feature to provide `random_from_rng` constructors +* Make `StaticSecrets` optional via feature `static_secrets` +* Update underlying `curve25519_dalek` library to `4.0.0-rc.2`. Notable changes: + * [curve25519-dalek backend] additive features have been removed in favor of cfg based selection. + * [curve25519-dalek backend] now by default auto selects the appropriate word size over the previous default `32`. + +## 2.0.0-pre.1 + +* Loosen restriction on zeroize dependency version from =1.3 to 1. +* Update MSRV to 1.51. + +## 2.0.0-pre.0 + +* Update `rand_core` dependency to `0.6`. + +# 1.x Series + +## 1.2 + +* Add module documentation for using the bytes-oriented `x25519()` API. +* Add implementation of `zeroize::Zeroize` for `PublicKey`. +* Move unittests to a separate directory. +* Add cargo feature flags `"fiat_u32_backend"` and `"fiat_u64_backend"` for + activating the Fiat crypto field element implementations. +* Fix issue with removed `feature(external_doc)` on nightly compilers. +* Pin `zeroize` to version 1.3 to support a wider range of MSRVs. +* Add CI via Github actions. +* Fix breakage in the serde unittests. +* MSRV is now 1.41 for production and 1.48 for development. +* Add an optional check to `SharedSecret` for contibutory behaviour. +* Add implementation of `ReusableSecret` keys which are non-ephemeral, but which + cannot be serialised to discourage long-term use. + +## 1.1.1 + +* Fix a typo in the README. + +## 1.1.0 + +* Add impls of `PartialEq`, `Eq`, and `Hash` for `PublicKey` (by @jack-michaud) + +## 1.0.1 + +* Update underlying `curve25519_dalek` library to `3.0`. + +## 1.0.0 + +* Widen generic bound on `EphemeralSecret::new` and `StaticSecret::new` to + allow owned as well as borrowed RNGs. +* Add `PublicKey::to_bytes` and `SharedSecret::to_bytes`, returning owned byte + arrays, complementing the existing `as_bytes` methods returning references. +* Remove mention of deprecated `rand_os` crate from examples. +* Clarify `EphemeralSecret`/`StaticSecret` distinction in documentation. + +# Pre-1.0.0 + +## 0.6.0 + +* Updates `rand_core` version to `0.5`. +* Adds `serde` support. +* Replaces `clear_on_drop` with `zeroize`. +* Use Rust 2018. + +## 0.5.2 + +* Implement `Clone` for `StaticSecret`. + +## 0.5.1 + +* Implement `Copy, Clone, Debug` for `PublicKey`. +* Remove doctests. + +## 0.5.0 + +* Adds support for static and ephemeral keys. + +[curve25519-dalek backend]: https://github.com/dalek-cryptography/curve25519-dalek/#backends + diff --git a/x25519-dalek/Cargo.toml b/x25519-dalek/Cargo.toml new file mode 100644 index 000000000..4169c55a4 --- /dev/null +++ b/x25519-dalek/Cargo.toml @@ -0,0 +1,63 @@ +[package] +name = "x25519-dalek" +edition = "2021" +# Before changing this: +# - update version in README.md +# - update html_root_url +# - update CHANGELOG +# - if any changes were made to README.md, mirror them in src/lib.rs docs +version = "2.0.1" +authors = [ + "Isis Lovecruft ", + "DebugSteven ", + "Henry de Valence ", +] +readme = "README.md" +license = "BSD-3-Clause" +repository = "https://github.com/dalek-cryptography/curve25519-dalek/tree/main/x25519-dalek" +homepage = "https://github.com/dalek-cryptography/curve25519-dalek" +documentation = "https://docs.rs/x25519-dalek" +categories = ["cryptography", "no-std"] +keywords = ["cryptography", "curve25519", "key-exchange", "x25519", "diffie-hellman"] +description = "X25519 elliptic curve Diffie-Hellman key exchange in pure-Rust, using curve25519-dalek." +exclude = [ + ".gitignore", + ".travis.yml", + "CONTRIBUTING.md", +] +rust-version = "1.60" + +[badges] +travis-ci = { repository = "dalek-cryptography/x25519-dalek", branch = "master"} + +[package.metadata.docs.rs] +rustdoc-args = [ + "--html-in-header", "docs/assets/rustdoc-include-katex-header.html", + "--cfg", "docsrs", +] +features = ["getrandom", "reusable_secrets", "serde", "static_secrets"] + +[dependencies] +curve25519-dalek = { version = "4", path = "../curve25519-dalek", default-features = false } +rand_core = { version = "0.6", default-features = false } +serde = { version = "1", default-features = false, optional = true, features = ["derive"] } +zeroize = { version = "1", default-features = false, optional = true, features = ["zeroize_derive"] } + +[dev-dependencies] +bincode = "1" +criterion = "0.5" +rand_core = { version = "0.6", default-features = false, features = ["getrandom"] } + +[[bench]] +name = "x25519" +harness = false + +[features] +default = ["alloc", "precomputed-tables", "zeroize"] +getrandom = ["rand_core/getrandom"] +zeroize = ["dep:zeroize", "curve25519-dalek/zeroize"] +serde = ["dep:serde", "curve25519-dalek/serde"] +alloc = ["curve25519-dalek/alloc", "serde?/alloc", "zeroize?/alloc"] +precomputed-tables = ["curve25519-dalek/precomputed-tables"] +reusable_secrets = [] +static_secrets = [] diff --git a/x25519-dalek/LICENSE b/x25519-dalek/LICENSE new file mode 100644 index 000000000..6577d97c2 --- /dev/null +++ b/x25519-dalek/LICENSE @@ -0,0 +1,29 @@ +Copyright (c) 2017-2021 isis agora lovecruft. All rights reserved. +Copyright (c) 2019-2021 DebugSteven. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/x25519-dalek/README.md b/x25519-dalek/README.md new file mode 100644 index 000000000..c1604dac8 --- /dev/null +++ b/x25519-dalek/README.md @@ -0,0 +1,139 @@ +# x25519-dalek [![](https://img.shields.io/crates/v/x25519-dalek.svg)](https://crates.io/crates/x25519-dalek) [![](https://docs.rs/x25519-dalek/badge.svg)](https://docs.rs/x25519-dalek) [![CI](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml/badge.svg?branch=main)](https://github.com/dalek-cryptography/curve25519-dalek/actions/workflows/x25519-dalek.yml) + +A pure-Rust implementation of x25519 elliptic curve Diffie-Hellman key exchange, +with curve operations provided by +[curve25519-dalek](https://github.com/dalek-cryptography/curve25519-dalek). + +This crate provides two levels of API: a bare byte-oriented `x25519` +function which matches the function specified in [RFC7748][rfc7748], as +well as a higher-level Rust API for static and ephemeral Diffie-Hellman. + +## Examples + + + + + +Alice and Bob are two adorable kittens who have lost their mittens, and they +wish to be able to send secret messages to each other to coordinate finding +them, otherwise—if their caretaker cat finds out—they will surely be called +naughty kittens and be given no pie! + +But the two kittens are quite clever. Even though their paws are still too big +and the rest of them is 90% fuzziness, these clever kittens have been studying +up on modern public key cryptography and have learned a nifty trick called +*elliptic curve Diffie-Hellman key exchange*. With the right incantations, the +kittens will be able to secretly organise to find their mittens, and then spend +the rest of the afternoon nomming some yummy pie! + +First, Alice uses `EphemeralSecret::random()` and then +`PublicKey::from()` to produce her secret and public keys: + +```ignore +use x25519_dalek::{EphemeralSecret, PublicKey}; + +let alice_secret = EphemeralSecret::random(); +let alice_public = PublicKey::from(&alice_secret); +``` + +Bob does the same: + +```ignore +# use x25519_dalek::{EphemeralSecret, PublicKey}; +let bob_secret = EphemeralSecret::random(); +let bob_public = PublicKey::from(&bob_secret); +``` + +Alice meows across the room, telling `alice_public` to Bob, and Bob +loudly meows `bob_public` back to Alice. Alice now computes her +shared secret with Bob by doing: + +```rust +# use rand_core::OsRng; +# use x25519_dalek::{EphemeralSecret, PublicKey}; +# let alice_secret = EphemeralSecret::random_from_rng(OsRng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::random_from_rng(OsRng); +# let bob_public = PublicKey::from(&bob_secret); +let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); +``` + +Similarly, Bob computes a shared secret by doing: + +```rust +# use rand_core::OsRng; +# use x25519_dalek::{EphemeralSecret, PublicKey}; +# let alice_secret = EphemeralSecret::random_from_rng(OsRng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::random_from_rng(OsRng); +# let bob_public = PublicKey::from(&bob_secret); +let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); +``` + +These secrets are the same: + +```rust +# use rand_core::OsRng; +# use x25519_dalek::{EphemeralSecret, PublicKey}; +# let alice_secret = EphemeralSecret::random_from_rng(OsRng); +# let alice_public = PublicKey::from(&alice_secret); +# let bob_secret = EphemeralSecret::random_from_rng(OsRng); +# let bob_public = PublicKey::from(&bob_secret); +# let alice_shared_secret = alice_secret.diffie_hellman(&bob_public); +# let bob_shared_secret = bob_secret.diffie_hellman(&alice_public); +assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes()); +``` + +Voilà! Alice and Bob can now use their shared secret to encrypt their +meows, for example, by using it to generate a key and nonce for an +authenticated-encryption cipher. + +This example used the ephemeral DH API, which ensures that secret keys +cannot be reused; Alice and Bob could instead use the static DH API +and load a long-term secret key. + +# Installation + +To install, add the following to your project's `Cargo.toml`: + +```toml +[dependencies] +x25519-dalek = "2" +``` + +# MSRV + +Current MSRV is 1.60. + +# Documentation + +Documentation is available [here](https://docs.rs/x25519-dalek). + +# Performance and backend selection + +Performance is a secondary goal behind correctness, safety, and clarity, but we aim to be competitive with other implementations. To this end, we allow users to choose their _backend_, i.e., the underlying implementation of elliptic curve and scalar arithmetic. Different backends have different use cases. For example, if you demand formally verified code, you want to use the `fiat` backend (as it was generated from [Fiat Crypto][fiat]). + +Further instructions and details regarding backends can be found in the [curve25519-dalek docs](https://github.com/dalek-cryptography/curve25519-dalek#backends). + +# Note + +This code matches the [RFC7748][rfc7748] test vectors. +The elliptic curve +operations are provided by `curve25519-dalek`, which makes a best-effort +attempt to prevent software side-channels. + +"Secret Messages" cover image and [zine](https://shop.bubblesort.io/products/secret-messages-zine) +copyright © Amy Wibowo ([@sailorhg](https://twitter.com/sailorhg)) + +[rfc7748]: https://tools.ietf.org/html/rfc7748 + +# See also + +- [crypto_box]: pure Rust public-key authenticated encryption compatible with + the NaCl family of encryption libraries (libsodium, TweetNaCl) which uses + `x25519-dalek` for key agreement + +[fiat]: https://github.com/mit-plv/fiat-crypto +[crypto_box]: https://github.com/RustCrypto/nacl-compat/tree/master/crypto_box diff --git a/x25519-dalek/benches/x25519.rs b/x25519-dalek/benches/x25519.rs new file mode 100644 index 000000000..77c832db0 --- /dev/null +++ b/x25519-dalek/benches/x25519.rs @@ -0,0 +1,41 @@ +// -*- mode: rust; -*- +// +// This file is part of x25519-dalek. +// Copyright (c) 2017-2019 isis agora lovecruft +// Copyright (c) 2019 DebugSteven +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - DebugSteven + +//! Benchmark the Diffie-Hellman operation. + +use criterion::{criterion_group, criterion_main, Criterion}; + +use rand_core::OsRng; + +use x25519_dalek::EphemeralSecret; +use x25519_dalek::PublicKey; + +fn bench_diffie_hellman(c: &mut Criterion) { + let bob_secret = EphemeralSecret::random_from_rng(OsRng); + let bob_public = PublicKey::from(&bob_secret); + + c.bench_function("diffie_hellman", move |b| { + b.iter_with_setup( + || EphemeralSecret::random_from_rng(OsRng), + |alice_secret| alice_secret.diffie_hellman(&bob_public), + ) + }); +} + +criterion_group! { + name = x25519_benches; + config = Criterion::default(); + targets = + bench_diffie_hellman, +} +criterion_main! { + x25519_benches, +} diff --git a/x25519-dalek/docs/assets/rustdoc-include-katex-header.html b/x25519-dalek/docs/assets/rustdoc-include-katex-header.html new file mode 100644 index 000000000..d240432aa --- /dev/null +++ b/x25519-dalek/docs/assets/rustdoc-include-katex-header.html @@ -0,0 +1,12 @@ + + + + + + + + + diff --git a/x25519-dalek/res/bubblesort-zines-secret-messages-cover.jpeg b/x25519-dalek/res/bubblesort-zines-secret-messages-cover.jpeg new file mode 100644 index 000000000..ca3329832 Binary files /dev/null and b/x25519-dalek/res/bubblesort-zines-secret-messages-cover.jpeg differ diff --git a/x25519-dalek/src/lib.rs b/x25519-dalek/src/lib.rs new file mode 100644 index 000000000..9a5fc1938 --- /dev/null +++ b/x25519-dalek/src/lib.rs @@ -0,0 +1,33 @@ +// -*- mode: rust; -*- +// +// This file is part of x25519-dalek. +// Copyright (c) 2017-2021 isis lovecruft +// Copyright (c) 2019-2021 DebugSteven +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - DebugSteven + +// Refuse to compile if documentation is missing, but only on nightly. +// +// This means that missing docs will still fail CI, but means we can use +// README.md as the crate documentation. + +#![no_std] +#![cfg_attr(feature = "bench", feature(test))] +#![cfg_attr(docsrs, feature(doc_auto_cfg, doc_cfg, doc_cfg_hide))] +#![cfg_attr(docsrs, doc(cfg_hide(docsrs)))] +#![deny(missing_docs)] +#![doc( + html_logo_url = "https://cdn.jsdelivr.net/gh/dalek-cryptography/curve25519-dalek/docs/assets/dalek-logo-clear.png" +)] +#![doc = include_str!("../README.md")] + +//------------------------------------------------------------------------ +// x25519-dalek public API +//------------------------------------------------------------------------ + +mod x25519; + +pub use crate::x25519::*; diff --git a/x25519-dalek/src/x25519.rs b/x25519-dalek/src/x25519.rs new file mode 100644 index 000000000..3b96f9cf0 --- /dev/null +++ b/x25519-dalek/src/x25519.rs @@ -0,0 +1,377 @@ +// -*- mode: rust; -*- +// +// This file is part of x25519-dalek. +// Copyright (c) 2017-2021 isis lovecruft +// Copyright (c) 2019-2021 DebugSteven +// See LICENSE for licensing information. +// +// Authors: +// - isis agora lovecruft +// - DebugSteven + +//! x25519 Diffie-Hellman key exchange +//! +//! This implements x25519 key exchange as specified by Mike Hamburg +//! and Adam Langley in [RFC7748](https://tools.ietf.org/html/rfc7748). + +use curve25519_dalek::{edwards::EdwardsPoint, montgomery::MontgomeryPoint, traits::IsIdentity}; + +use rand_core::CryptoRng; +use rand_core::RngCore; + +#[cfg(feature = "zeroize")] +use zeroize::Zeroize; + +/// A Diffie-Hellman public key +/// +/// We implement `Zeroize` so that downstream consumers may derive it for `Drop` +/// should they wish to erase public keys from memory. Note that this erasure +/// (in this crate) does *not* automatically happen, but either must be derived +/// for Drop or explicitly called. +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[derive(PartialEq, Eq, Hash, Copy, Clone, Debug)] +pub struct PublicKey(pub(crate) MontgomeryPoint); + +impl From<[u8; 32]> for PublicKey { + /// Given a byte array, construct a x25519 `PublicKey`. + fn from(bytes: [u8; 32]) -> PublicKey { + PublicKey(MontgomeryPoint(bytes)) + } +} + +impl PublicKey { + /// Convert this public key to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } + + /// View this public key as a byte array. + #[inline] + pub fn as_bytes(&self) -> &[u8; 32] { + self.0.as_bytes() + } +} + +impl AsRef<[u8]> for PublicKey { + /// View this public key as a byte array. + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +/// A short-lived Diffie-Hellman secret key that can only be used to compute a single +/// [`SharedSecret`]. +/// +/// This type is identical to the `StaticSecret` type, except that the +/// [`EphemeralSecret::diffie_hellman`] method consumes and then wipes the secret key, and there +/// are no serialization methods defined. This means that [`EphemeralSecret`]s can only be +/// generated from fresh randomness where the compiler statically checks that the resulting +/// secret is used at most once. +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[cfg_attr(feature = "zeroize", zeroize(drop))] +pub struct EphemeralSecret(pub(crate) [u8; 32]); + +impl EphemeralSecret { + /// Perform a Diffie-Hellman key agreement between `self` and + /// `their_public` key to produce a [`SharedSecret`]. + pub fn diffie_hellman(self, their_public: &PublicKey) -> SharedSecret { + SharedSecret(their_public.0.mul_clamped(self.0)) + } + + /// Generate a new [`EphemeralSecret`] with the supplied RNG. + #[deprecated( + since = "2.0.0", + note = "Renamed to `random_from_rng`. This will be removed in 2.1.0" + )] + pub fn new(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`EphemeralSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { + // The secret key is random bytes. Clamping is done later. + let mut bytes = [0u8; 32]; + csprng.fill_bytes(&mut bytes); + EphemeralSecret(bytes) + } + + /// Generate a new [`EphemeralSecret`]. + #[cfg(feature = "getrandom")] + pub fn random() -> Self { + Self::random_from_rng(rand_core::OsRng) + } +} + +impl<'a> From<&'a EphemeralSecret> for PublicKey { + /// Given an x25519 [`EphemeralSecret`] key, compute its corresponding [`PublicKey`]. + fn from(secret: &'a EphemeralSecret) -> PublicKey { + PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery()) + } +} + +/// A Diffie-Hellman secret key which may be used more than once, but is +/// purposefully not serialiseable in order to discourage key-reuse. This is +/// implemented to facilitate protocols such as Noise (e.g. Noise IK key usage, +/// etc.) and X3DH which require an "ephemeral" key to conduct the +/// Diffie-Hellman operation multiple times throughout the protocol, while the +/// protocol run at a higher level is only conducted once per key. +/// +/// Similarly to [`EphemeralSecret`], this type does _not_ have serialisation +/// methods, in order to discourage long-term usage of secret key material. (For +/// long-term secret keys, see `StaticSecret`.) +/// +/// # Warning +/// +/// If you're uncertain about whether you should use this, then you likely +/// should not be using this. Our strongly recommended advice is to use +/// [`EphemeralSecret`] at all times, as that type enforces at compile-time that +/// secret keys are never reused, which can have very serious security +/// implications for many protocols. +#[cfg(feature = "reusable_secrets")] +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[cfg_attr(feature = "zeroize", zeroize(drop))] +#[derive(Clone)] +pub struct ReusableSecret(pub(crate) [u8; 32]); + +#[cfg(feature = "reusable_secrets")] +impl ReusableSecret { + /// Perform a Diffie-Hellman key agreement between `self` and + /// `their_public` key to produce a [`SharedSecret`]. + pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { + SharedSecret(their_public.0.mul_clamped(self.0)) + } + + /// Generate a new [`ReusableSecret`] with the supplied RNG. + #[deprecated( + since = "2.0.0", + note = "Renamed to `random_from_rng`. This will be removed in 2.1.0." + )] + pub fn new(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`ReusableSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { + // The secret key is random bytes. Clamping is done later. + let mut bytes = [0u8; 32]; + csprng.fill_bytes(&mut bytes); + ReusableSecret(bytes) + } + + /// Generate a new [`ReusableSecret`]. + #[cfg(feature = "getrandom")] + pub fn random() -> Self { + Self::random_from_rng(rand_core::OsRng) + } +} + +#[cfg(feature = "reusable_secrets")] +impl<'a> From<&'a ReusableSecret> for PublicKey { + /// Given an x25519 [`ReusableSecret`] key, compute its corresponding [`PublicKey`]. + fn from(secret: &'a ReusableSecret) -> PublicKey { + PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery()) + } +} + +/// A Diffie-Hellman secret key that can be used to compute multiple [`SharedSecret`]s. +/// +/// This type is identical to the [`EphemeralSecret`] type, except that the +/// [`StaticSecret::diffie_hellman`] method does not consume the secret key, and the type provides +/// serialization methods to save and load key material. This means that the secret may be used +/// multiple times (but does not *have to be*). +/// +/// # Warning +/// +/// If you're uncertain about whether you should use this, then you likely +/// should not be using this. Our strongly recommended advice is to use +/// [`EphemeralSecret`] at all times, as that type enforces at compile-time that +/// secret keys are never reused, which can have very serious security +/// implications for many protocols. +#[cfg(feature = "static_secrets")] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[cfg_attr(feature = "zeroize", zeroize(drop))] +#[derive(Clone)] +pub struct StaticSecret([u8; 32]); + +#[cfg(feature = "static_secrets")] +impl StaticSecret { + /// Perform a Diffie-Hellman key agreement between `self` and + /// `their_public` key to produce a `SharedSecret`. + pub fn diffie_hellman(&self, their_public: &PublicKey) -> SharedSecret { + SharedSecret(their_public.0.mul_clamped(self.0)) + } + + /// Generate a new [`StaticSecret`] with the supplied RNG. + #[deprecated( + since = "2.0.0", + note = "Renamed to `random_from_rng`. This will be removed in 2.1.0" + )] + pub fn new(mut csprng: T) -> Self { + Self::random_from_rng(&mut csprng) + } + + /// Generate a new [`StaticSecret`] with the supplied RNG. + pub fn random_from_rng(mut csprng: T) -> Self { + // The secret key is random bytes. Clamping is done later. + let mut bytes = [0u8; 32]; + csprng.fill_bytes(&mut bytes); + StaticSecret(bytes) + } + + /// Generate a new [`StaticSecret`]. + #[cfg(feature = "getrandom")] + pub fn random() -> Self { + Self::random_from_rng(rand_core::OsRng) + } + + /// Extract this key's bytes for serialization. + #[inline] + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// View this key as a byte array. + #[inline] + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } +} + +#[cfg(feature = "static_secrets")] +impl From<[u8; 32]> for StaticSecret { + /// Load a secret key from a byte array. + fn from(bytes: [u8; 32]) -> StaticSecret { + StaticSecret(bytes) + } +} + +#[cfg(feature = "static_secrets")] +impl<'a> From<&'a StaticSecret> for PublicKey { + /// Given an x25519 [`StaticSecret`] key, compute its corresponding [`PublicKey`]. + fn from(secret: &'a StaticSecret) -> PublicKey { + PublicKey(EdwardsPoint::mul_base_clamped(secret.0).to_montgomery()) + } +} + +#[cfg(feature = "static_secrets")] +impl AsRef<[u8]> for StaticSecret { + /// View this key as a byte array. + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +/// The result of a Diffie-Hellman key exchange. +/// +/// Each party computes this using their [`EphemeralSecret`] or [`StaticSecret`] and their +/// counterparty's [`PublicKey`]. +#[cfg_attr(feature = "zeroize", derive(Zeroize))] +#[cfg_attr(feature = "zeroize", zeroize(drop))] +pub struct SharedSecret(pub(crate) MontgomeryPoint); + +impl SharedSecret { + /// Convert this shared secret to a byte array. + #[inline] + pub fn to_bytes(&self) -> [u8; 32] { + self.0.to_bytes() + } + + /// View this shared secret key as a byte array. + #[inline] + pub fn as_bytes(&self) -> &[u8; 32] { + self.0.as_bytes() + } + + /// Ensure in constant-time that this shared secret did not result from a + /// key exchange with non-contributory behaviour. + /// + /// In some more exotic protocols which need to guarantee "contributory" + /// behaviour for both parties, that is, that each party contributed a public + /// value which increased the security of the resulting shared secret. + /// To take an example protocol attack where this could lead to undesirable + /// results [from Thái "thaidn" Dương](https://vnhacker.blogspot.com/2015/09/why-not-validating-curve25519-public.html): + /// + /// > If Mallory replaces Alice's and Bob's public keys with zero, which is + /// > a valid Curve25519 public key, he would be able to force the ECDH + /// > shared value to be zero, which is the encoding of the point at infinity, + /// > and thus get to dictate some publicly known values as the shared + /// > keys. It still requires an active man-in-the-middle attack to pull the + /// > trick, after which, however, not only Mallory can decode Alice's data, + /// > but everyone too! It is also impossible for Alice and Bob to detect the + /// > intrusion, as they still share the same keys, and can communicate with + /// > each other as normal. + /// + /// The original Curve25519 specification argues that checks for + /// non-contributory behaviour are "unnecessary for Diffie-Hellman". + /// Whether this check is necessary for any particular given protocol is + /// often a matter of debate, which we will not re-hash here, but simply + /// cite some of the [relevant] [public] [discussions]. + /// + /// # Returns + /// + /// Returns `true` if the key exchange was contributory (good), and `false` + /// otherwise (can be bad for some protocols). + /// + /// [relevant]: https://tools.ietf.org/html/rfc7748#page-15 + /// [public]: https://vnhacker.blogspot.com/2015/09/why-not-validating-curve25519-public.html + /// [discussions]: https://vnhacker.blogspot.com/2016/08/the-internet-of-broken-protocols.html + #[must_use] + pub fn was_contributory(&self) -> bool { + !self.0.is_identity() + } +} + +impl AsRef<[u8]> for SharedSecret { + /// View this shared secret key as a byte array. + #[inline] + fn as_ref(&self) -> &[u8] { + self.as_bytes() + } +} + +/// The bare, byte-oriented x25519 function, exactly as specified in RFC7748. +/// +/// This can be used with [`X25519_BASEPOINT_BYTES`] for people who +/// cannot use the better, safer, and faster ephemeral DH API. +/// +/// # Example +#[cfg_attr(feature = "static_secrets", doc = "```")] +#[cfg_attr(not(feature = "static_secrets"), doc = "```ignore")] +/// use rand_core::OsRng; +/// use rand_core::RngCore; +/// +/// use x25519_dalek::x25519; +/// use x25519_dalek::StaticSecret; +/// use x25519_dalek::PublicKey; +/// +/// // Generate Alice's key pair. +/// let alice_secret = StaticSecret::random_from_rng(&mut OsRng); +/// let alice_public = PublicKey::from(&alice_secret); +/// +/// // Generate Bob's key pair. +/// let bob_secret = StaticSecret::random_from_rng(&mut OsRng); +/// let bob_public = PublicKey::from(&bob_secret); +/// +/// // Alice and Bob should now exchange their public keys. +/// +/// // Once they've done so, they may generate a shared secret. +/// let alice_shared = x25519(alice_secret.to_bytes(), bob_public.to_bytes()); +/// let bob_shared = x25519(bob_secret.to_bytes(), alice_public.to_bytes()); +/// +/// assert_eq!(alice_shared, bob_shared); +/// ``` +pub fn x25519(k: [u8; 32], u: [u8; 32]) -> [u8; 32] { + MontgomeryPoint(u).mul_clamped(k).to_bytes() +} + +/// The X25519 basepoint, for use with the bare, byte-oriented x25519 +/// function. This is provided for people who cannot use the typed +/// DH API for some reason. +pub const X25519_BASEPOINT_BYTES: [u8; 32] = [ + 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +]; diff --git a/x25519-dalek/tests/x25519_tests.rs b/x25519-dalek/tests/x25519_tests.rs new file mode 100644 index 000000000..d589b3e44 --- /dev/null +++ b/x25519-dalek/tests/x25519_tests.rs @@ -0,0 +1,231 @@ +use curve25519_dalek::edwards::EdwardsPoint; + +use x25519_dalek::*; + +#[test] +fn byte_basepoint_matches_edwards_scalar_mul() { + let mut scalar_bytes = [0x37; 32]; + + for i in 0..32 { + scalar_bytes[i] += 2; + + let result = x25519(scalar_bytes, X25519_BASEPOINT_BYTES); + let expected = EdwardsPoint::mul_base_clamped(scalar_bytes) + .to_montgomery() + .to_bytes(); + + assert_eq!(result, expected); + } +} + +#[test] +#[cfg(feature = "serde")] +fn serde_bincode_public_key_roundtrip() { + use bincode; + + let public_key = PublicKey::from(X25519_BASEPOINT_BYTES); + + let encoded = bincode::serialize(&public_key).unwrap(); + let decoded: PublicKey = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded.as_bytes(), public_key.as_bytes()); +} + +#[test] +#[cfg(feature = "serde")] +fn serde_bincode_public_key_matches_from_bytes() { + use bincode; + + let expected = PublicKey::from(X25519_BASEPOINT_BYTES); + let decoded: PublicKey = bincode::deserialize(&X25519_BASEPOINT_BYTES).unwrap(); + + assert_eq!(decoded.as_bytes(), expected.as_bytes()); +} + +#[test] +#[cfg(feature = "serde")] +fn serde_bincode_static_secret_roundtrip() { + use bincode; + + let static_secret = StaticSecret::from([0x24; 32]); + let encoded = bincode::serialize(&static_secret).unwrap(); + let decoded: StaticSecret = bincode::deserialize(&encoded).unwrap(); + + assert_eq!(encoded.len(), 32); + assert_eq!(decoded.to_bytes(), static_secret.to_bytes()); +} + +#[test] +#[cfg(feature = "serde")] +fn serde_bincode_static_secret_matches_from_bytes() { + use bincode; + + let expected = StaticSecret::from([0x24; 32]); + let decoded: StaticSecret = bincode::deserialize(&[0x24; 32]).unwrap(); + + assert_eq!(decoded.to_bytes(), expected.to_bytes()); +} + +fn do_rfc7748_ladder_test1(input_scalar: [u8; 32], input_point: [u8; 32], expected: [u8; 32]) { + let result = x25519(input_scalar, input_point); + + assert_eq!(result, expected); +} + +#[test] +fn rfc7748_ladder_test1_vectorset1() { + let input_scalar: [u8; 32] = [ + 0xa5, 0x46, 0xe3, 0x6b, 0xf0, 0x52, 0x7c, 0x9d, 0x3b, 0x16, 0x15, 0x4b, 0x82, 0x46, 0x5e, + 0xdd, 0x62, 0x14, 0x4c, 0x0a, 0xc1, 0xfc, 0x5a, 0x18, 0x50, 0x6a, 0x22, 0x44, 0xba, 0x44, + 0x9a, 0xc4, + ]; + let input_point: [u8; 32] = [ + 0xe6, 0xdb, 0x68, 0x67, 0x58, 0x30, 0x30, 0xdb, 0x35, 0x94, 0xc1, 0xa4, 0x24, 0xb1, 0x5f, + 0x7c, 0x72, 0x66, 0x24, 0xec, 0x26, 0xb3, 0x35, 0x3b, 0x10, 0xa9, 0x03, 0xa6, 0xd0, 0xab, + 0x1c, 0x4c, + ]; + let expected: [u8; 32] = [ + 0xc3, 0xda, 0x55, 0x37, 0x9d, 0xe9, 0xc6, 0x90, 0x8e, 0x94, 0xea, 0x4d, 0xf2, 0x8d, 0x08, + 0x4f, 0x32, 0xec, 0xcf, 0x03, 0x49, 0x1c, 0x71, 0xf7, 0x54, 0xb4, 0x07, 0x55, 0x77, 0xa2, + 0x85, 0x52, + ]; + + do_rfc7748_ladder_test1(input_scalar, input_point, expected); +} + +#[test] +fn rfc7748_ladder_test1_vectorset2() { + let input_scalar: [u8; 32] = [ + 0x4b, 0x66, 0xe9, 0xd4, 0xd1, 0xb4, 0x67, 0x3c, 0x5a, 0xd2, 0x26, 0x91, 0x95, 0x7d, 0x6a, + 0xf5, 0xc1, 0x1b, 0x64, 0x21, 0xe0, 0xea, 0x01, 0xd4, 0x2c, 0xa4, 0x16, 0x9e, 0x79, 0x18, + 0xba, 0x0d, + ]; + let input_point: [u8; 32] = [ + 0xe5, 0x21, 0x0f, 0x12, 0x78, 0x68, 0x11, 0xd3, 0xf4, 0xb7, 0x95, 0x9d, 0x05, 0x38, 0xae, + 0x2c, 0x31, 0xdb, 0xe7, 0x10, 0x6f, 0xc0, 0x3c, 0x3e, 0xfc, 0x4c, 0xd5, 0x49, 0xc7, 0x15, + 0xa4, 0x93, + ]; + let expected: [u8; 32] = [ + 0x95, 0xcb, 0xde, 0x94, 0x76, 0xe8, 0x90, 0x7d, 0x7a, 0xad, 0xe4, 0x5c, 0xb4, 0xb8, 0x73, + 0xf8, 0x8b, 0x59, 0x5a, 0x68, 0x79, 0x9f, 0xa1, 0x52, 0xe6, 0xf8, 0xf7, 0x64, 0x7a, 0xac, + 0x79, 0x57, + ]; + + do_rfc7748_ladder_test1(input_scalar, input_point, expected); +} + +#[test] +#[ignore] // Run only if you want to burn a lot of CPU doing 1,000,000 DH operations +fn rfc7748_ladder_test2() { + use curve25519_dalek::constants::X25519_BASEPOINT; + + let mut k: [u8; 32] = X25519_BASEPOINT.0; + let mut u: [u8; 32] = X25519_BASEPOINT.0; + let mut result: [u8; 32]; + + macro_rules! do_iterations { + ($n:expr) => { + for _ in 0..$n { + result = x25519(k, u); + // OBVIOUS THING THAT I'M GOING TO NOTE ANYWAY BECAUSE I'VE + // SEEN PEOPLE DO THIS WITH GOLANG'S STDLIB AND YOU SURE AS + // HELL SHOULDN'T DO HORRIBLY STUPID THINGS LIKE THIS WITH + // MY LIBRARY: + // + // NEVER EVER TREAT SCALARS AS POINTS AND/OR VICE VERSA. + // + // ↓↓ DON'T DO THIS ↓↓ + u = k.clone(); + k = result; + } + }; + } + + // After one iteration: + // 422c8e7a6227d7bca1350b3e2bb7279f7897b87bb6854b783c60e80311ae3079 + // After 1,000 iterations: + // 684cf59ba83309552800ef566f2f4d3c1c3887c49360e3875f2eb94d99532c51 + // After 1,000,000 iterations: + // 7c3911e0ab2586fd864497297e575e6f3bc601c0883c30df5f4dd2d24f665424 + + do_iterations!(1); + assert_eq!( + k, + [ + 0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc, 0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, + 0x27, 0x9f, 0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78, 0x3c, 0x60, 0xe8, 0x03, + 0x11, 0xae, 0x30, 0x79, + ] + ); + do_iterations!(999); + assert_eq!( + k, + [ + 0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55, 0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, + 0x4d, 0x3c, 0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87, 0x5f, 0x2e, 0xb9, 0x4d, + 0x99, 0x53, 0x2c, 0x51, + ] + ); + do_iterations!(999_000); + assert_eq!( + k, + [ + 0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd, 0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, + 0x5e, 0x6f, 0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf, 0x5f, 0x4d, 0xd2, 0xd2, + 0x4f, 0x66, 0x54, 0x24, + ] + ); +} + +mod rand_core { + + use super::*; + use ::rand_core::OsRng; + + #[test] + fn ephemeral_from_rng() { + #[allow(deprecated)] + EphemeralSecret::new(OsRng); + EphemeralSecret::random_from_rng(OsRng); + } + + #[test] + #[cfg(feature = "reusable_secrets")] + fn reusable_from_rng() { + #[allow(deprecated)] + ReusableSecret::new(OsRng); + ReusableSecret::random_from_rng(OsRng); + } + + #[test] + #[cfg(feature = "static_secrets")] + fn static_from_rng() { + #[allow(deprecated)] + StaticSecret::new(OsRng); + StaticSecret::random_from_rng(OsRng); + } +} + +#[cfg(feature = "getrandom")] +mod getrandom { + + use super::*; + + #[test] + fn ephemeral_random() { + EphemeralSecret::random(); + } + + #[test] + #[cfg(feature = "reusable_secrets")] + fn reusable_random() { + ReusableSecret::random(); + } + + #[test] + #[cfg(feature = "static_secrets")] + fn static_random() { + StaticSecret::random(); + } +}