├── .github └── workflows │ ├── bench.yml │ ├── build.yml │ ├── coverage.yml │ ├── ctgrind.yml │ ├── fuzz.yml │ └── lints.yml ├── .gitignore ├── .gitmodules ├── .rustfmt.toml ├── .rustfmt.unstable.toml ├── Cargo.lock ├── Cargo.toml ├── LICENSE ├── README.md ├── admin ├── bench-golang.py ├── bench-on-arm ├── coverage ├── ctgrind ├── parse-asm │ ├── .gitignore │ ├── all.sh │ ├── driver.p256.py │ ├── driver.p384.py │ ├── driver.py │ ├── driver.rsa.py │ ├── driver.x25519.py │ └── parse.py ├── picture.png ├── scan-license └── structure ├── fuzz ├── .gitignore ├── Cargo.toml └── fuzzer │ ├── aead.rs │ ├── kx.rs │ └── sha2.rs ├── graviola-bench ├── Cargo.toml └── benches │ ├── aes_gcm.rs │ ├── chacha20poly1305.rs │ ├── criterion.rs │ ├── hmac.rs │ ├── p256.rs │ ├── p384.rs │ ├── rsa_gen.rs │ ├── rsa_priv.rs │ ├── rsa_pub.rs │ ├── sha2.rs │ ├── x25519.rs │ └── xchacha20poly1305.rs ├── graviola ├── Cargo.toml ├── README.md ├── src │ ├── error.rs │ ├── high │ │ ├── asn1.rs │ │ ├── asn1 │ │ │ ├── oid.rs │ │ │ ├── pkix.rs │ │ │ └── testdata │ │ │ │ ├── nistp256-p8.bin │ │ │ │ ├── nistp256-sec1.bin │ │ │ │ ├── rsaprivatekey-1k.bin │ │ │ │ ├── rsapublickey-1k.bin │ │ │ │ ├── spki-ec-nistp256.bin │ │ │ │ └── spki-rsa-2k.bin │ │ ├── curve.rs │ │ ├── ecdsa.rs │ │ ├── ecdsa │ │ │ ├── secp256r1.der │ │ │ ├── secp256r1.pkcs8.der │ │ │ ├── secp256r1.wrong-public-key.der │ │ │ ├── secp256r1.wrong-version.der │ │ │ ├── secp384r1.der │ │ │ └── secp384r1.pkcs8.der │ │ ├── hash.rs │ │ ├── hmac.rs │ │ ├── hmac_drbg.rs │ │ ├── mod.rs │ │ ├── pkcs1.rs │ │ ├── pkcs8.rs │ │ ├── rsa.rs │ │ └── rsa │ │ │ ├── rsa2048.der │ │ │ ├── rsa2048.pkcs8.der │ │ │ ├── rsa3072.der │ │ │ ├── rsa3072.pkcs8.der │ │ │ ├── rsa4096.der │ │ │ ├── rsa4096.pkcs8.der │ │ │ ├── rsa6144.der │ │ │ ├── rsa6144.pkcs8.der │ │ │ ├── rsa8192.der │ │ │ └── rsa8192.pkcs8.der │ ├── lib.rs │ ├── low │ │ ├── aarch64 │ │ │ ├── aes.rs │ │ │ ├── aes_gcm.rs │ │ │ ├── bignum_add.rs │ │ │ ├── bignum_add_p256.rs │ │ │ ├── bignum_add_p384.rs │ │ │ ├── bignum_bitsize.rs │ │ │ ├── bignum_cmp_lt.rs │ │ │ ├── bignum_coprime.rs │ │ │ ├── bignum_copy_row_from_table.rs │ │ │ ├── bignum_copy_row_from_table_16.rs │ │ │ ├── bignum_copy_row_from_table_32.rs │ │ │ ├── bignum_copy_row_from_table_8n.rs │ │ │ ├── bignum_copy_row_from_table_mux.rs │ │ │ ├── bignum_ctz.rs │ │ │ ├── bignum_demont.rs │ │ │ ├── bignum_demont_p256.rs │ │ │ ├── bignum_demont_p384.rs │ │ │ ├── bignum_digitsize.rs │ │ │ ├── bignum_emontredc_8n.rs │ │ │ ├── bignum_eq.rs │ │ │ ├── bignum_inv_p256.rs │ │ │ ├── bignum_inv_p384.rs │ │ │ ├── bignum_kmul_16_32.rs │ │ │ ├── bignum_kmul_32_64.rs │ │ │ ├── bignum_ksqr_16_32.rs │ │ │ ├── bignum_ksqr_32_64.rs │ │ │ ├── bignum_mod_n256.rs │ │ │ ├── bignum_mod_n384.rs │ │ │ ├── bignum_modadd.rs │ │ │ ├── bignum_modinv.rs │ │ │ ├── bignum_modsub.rs │ │ │ ├── bignum_montifier.rs │ │ │ ├── bignum_montmul.rs │ │ │ ├── bignum_montmul_p256.rs │ │ │ ├── bignum_montmul_p384.rs │ │ │ ├── bignum_montredc.rs │ │ │ ├── bignum_montsqr.rs │ │ │ ├── bignum_montsqr_p256.rs │ │ │ ├── bignum_montsqr_p384.rs │ │ │ ├── bignum_mul.rs │ │ │ ├── bignum_mux.rs │ │ │ ├── bignum_neg_p256.rs │ │ │ ├── bignum_neg_p384.rs │ │ │ ├── bignum_negmodinv.rs │ │ │ ├── bignum_optsub.rs │ │ │ ├── bignum_point_select_p256.rs │ │ │ ├── bignum_point_select_p384.rs │ │ │ ├── bignum_shr_small.rs │ │ │ ├── bignum_tomont_p256.rs │ │ │ ├── bignum_tomont_p384.rs │ │ │ ├── cpu.rs │ │ │ ├── curve25519_x25519.rs │ │ │ ├── curve25519_x25519base.rs │ │ │ ├── ghash.rs │ │ │ ├── mod.rs │ │ │ ├── p256_montjadd.rs │ │ │ ├── p256_montjdouble.rs │ │ │ ├── p256_montjmixadd.rs │ │ │ ├── p384_montjadd.rs │ │ │ ├── p384_montjdouble.rs │ │ │ └── sha256.rs │ │ ├── ct.rs │ │ ├── entry.rs │ │ ├── generic │ │ │ ├── blockwise.rs │ │ │ ├── chacha20.rs │ │ │ ├── ct_equal.rs │ │ │ ├── ghash.rs │ │ │ ├── poly1305.rs │ │ │ ├── sha256.rs │ │ │ ├── sha512.rs │ │ │ └── zeroise.rs │ │ ├── inline_assembly_safety.rs │ │ ├── macros.rs │ │ ├── mod.rs │ │ ├── posint.rs │ │ ├── tests.rs │ │ └── x86_64 │ │ │ ├── aes.rs │ │ │ ├── aes_gcm.rs │ │ │ ├── bignum_add.rs │ │ │ ├── bignum_add_p256.rs │ │ │ ├── bignum_add_p384.rs │ │ │ ├── bignum_bitsize.rs │ │ │ ├── bignum_cmp_lt.rs │ │ │ ├── bignum_coprime.rs │ │ │ ├── bignum_copy_row_from_table.rs │ │ │ ├── bignum_copy_row_from_table_16_avx2.rs │ │ │ ├── bignum_copy_row_from_table_8n_avx2.rs │ │ │ ├── bignum_copy_row_from_table_mux.rs │ │ │ ├── bignum_ctz.rs │ │ │ ├── bignum_demont.rs │ │ │ ├── bignum_demont_p256.rs │ │ │ ├── bignum_demont_p384.rs │ │ │ ├── bignum_digitsize.rs │ │ │ ├── bignum_emontredc_8n.rs │ │ │ ├── bignum_eq.rs │ │ │ ├── bignum_inv_p256.rs │ │ │ ├── bignum_inv_p384.rs │ │ │ ├── bignum_kmul_16_32.rs │ │ │ ├── bignum_kmul_32_64.rs │ │ │ ├── bignum_ksqr_16_32.rs │ │ │ ├── bignum_ksqr_32_64.rs │ │ │ ├── bignum_mod_n256.rs │ │ │ ├── bignum_mod_n384.rs │ │ │ ├── bignum_modadd.rs │ │ │ ├── bignum_modinv.rs │ │ │ ├── bignum_modsub.rs │ │ │ ├── bignum_montifier.rs │ │ │ ├── bignum_montmul.rs │ │ │ ├── bignum_montmul_p256.rs │ │ │ ├── bignum_montmul_p384.rs │ │ │ ├── bignum_montredc.rs │ │ │ ├── bignum_montsqr.rs │ │ │ ├── bignum_montsqr_p256.rs │ │ │ ├── bignum_montsqr_p384.rs │ │ │ ├── bignum_mul.rs │ │ │ ├── bignum_mux.rs │ │ │ ├── bignum_neg_p256.rs │ │ │ ├── bignum_neg_p384.rs │ │ │ ├── bignum_negmodinv.rs │ │ │ ├── bignum_optsub.rs │ │ │ ├── bignum_point_select_p256.rs │ │ │ ├── bignum_point_select_p384.rs │ │ │ ├── bignum_shr_small.rs │ │ │ ├── bignum_tomont_p256.rs │ │ │ ├── bignum_tomont_p384.rs │ │ │ ├── chacha20.rs │ │ │ ├── cpu.rs │ │ │ ├── curve25519_x25519.rs │ │ │ ├── curve25519_x25519base.rs │ │ │ ├── ghash.rs │ │ │ ├── mod.rs │ │ │ ├── p256_montjadd.rs │ │ │ ├── p256_montjdouble.rs │ │ │ ├── p256_montjmixadd.rs │ │ │ ├── p384_montjadd.rs │ │ │ ├── p384_montjdouble.rs │ │ │ ├── sha256.rs │ │ │ ├── sha256_mux.rs │ │ │ ├── sha512.rs │ │ │ └── sha512_mux.rs │ ├── mid │ │ ├── aes_gcm.rs │ │ ├── chacha20poly1305.rs │ │ ├── mod.rs │ │ ├── p256.rs │ │ ├── p256 │ │ │ └── precomp.rs │ │ ├── p384.rs │ │ ├── p384 │ │ │ └── precomp.rs │ │ ├── rng.rs │ │ ├── rsa_priv.rs │ │ ├── rsa_priv │ │ │ └── generate.rs │ │ ├── rsa_pub.rs │ │ ├── sha2.rs │ │ ├── util.rs │ │ ├── x25519.rs │ │ └── xchacha20poly1305.rs │ ├── test.rs │ └── testdata │ │ ├── aes-gcm-ciphertext.bin │ │ ├── invalid-primes.txt │ │ ├── rsa.bench.2048.txt │ │ ├── rsa.phi-not-coprime-e.2048.txt │ │ └── valid-primes.txt └── tests │ ├── crosschecks.rs │ ├── wycheproof.rs │ └── zeroing.rs └── rustls-graviola ├── Cargo.toml ├── README.md ├── examples ├── client.rs └── server.rs ├── src ├── aead.rs ├── hash.rs ├── hmac.rs ├── kx.rs ├── lib.rs ├── sign.rs ├── suites.rs ├── ticketer.rs └── verify.rs └── tests ├── keys ├── ecdsa-p256 │ ├── ca.cert │ ├── end.fullchain │ └── end.key ├── ecdsa-p384 │ ├── ca.cert │ ├── end.fullchain │ └── end.key ├── rsa-2048 │ ├── ca.cert │ ├── end.chain │ ├── end.fullchain │ └── end.key ├── rsa-3072 │ ├── ca.cert │ ├── end.fullchain │ └── end.key └── rsa-4096 │ ├── ca.cert │ ├── end.fullchain │ └── end.key └── pair.rs /.github/workflows/bench.yml: -------------------------------------------------------------------------------- 1 | name: bench 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | VALGRIND_BUG_494162: 1 12 | 13 | jobs: 14 | bench: 15 | runs-on: ubuntu-24.04 16 | steps: 17 | - uses: actions/checkout@v4 18 | with: 19 | submodules: true 20 | persist-credentials: false 21 | 22 | - name: Install stable toolchain 23 | uses: dtolnay/rust-toolchain@master 24 | with: 25 | toolchain: stable 26 | 27 | - name: Install cargo-binstall 28 | uses: cargo-bins/cargo-binstall@main 29 | 30 | - name: Install cargo-codspeed 31 | run: cargo binstall -y cargo-codspeed 32 | 33 | - name: Build benchmarks 34 | run: cargo codspeed build -p graviola-bench --features __bench_codspeed 35 | 36 | - name: Run benchmarks 37 | uses: CodSpeedHQ/action@v3 38 | with: 39 | run: cargo codspeed run 40 | token: ${{ secrets.CODSPEED_TOKEN }} 41 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: "0 18 * * *" 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | strategy: 15 | matrix: 16 | include: 17 | - os: ubuntu-latest 18 | - os: macos-latest 19 | - os: windows-latest 20 | - os: ubuntu-latest 21 | cross: aarch64-unknown-linux-gnu 22 | 23 | runs-on: ${{ matrix.os }} 24 | steps: 25 | - uses: actions/checkout@v4 26 | with: 27 | submodules: true 28 | persist-credentials: false 29 | 30 | - name: Install stable toolchain 31 | uses: dtolnay/rust-toolchain@master 32 | with: 33 | toolchain: stable 34 | 35 | - name: Install NASM for aws-lc-rs on Windows 36 | if: runner.os == 'Windows' 37 | uses: ilammy/setup-nasm@v1 38 | 39 | - name: Install valgrind on Linux 40 | if: runner.os == 'Linux' 41 | run: sudo apt-get update && sudo apt-get install -y valgrind 42 | 43 | - name: Install cross 44 | if: matrix.cross != '' 45 | uses: taiki-e/setup-cross-toolchain-action@v1 46 | with: 47 | target: ${{ matrix.cross }} 48 | 49 | - name: Build (debug) 50 | run: cargo build -p graviola 51 | - name: Run tests (debug) 52 | run: cargo test 53 | 54 | - name: Build (release) 55 | run: cargo build -p graviola --release 56 | - name: Run tests (release) 57 | run: env SLOW_TESTS=1 cargo test --release 58 | 59 | - name: Artificial CPU feature tests (x86_64) 60 | if: runner.arch == 'X64' 61 | run: | 62 | # test software fallbacks for sha256 and sha512 63 | env GRAVIOLA_CPU_DISABLE_sha=1 GRAVIOLA_CPU_DISABLE_bmi2=1 cargo test 64 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: coverage 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | schedule: 9 | - cron: "0 18 * * *" 10 | 11 | env: 12 | CARGO_TERM_COLOR: always 13 | 14 | jobs: 15 | build: 16 | strategy: 17 | matrix: 18 | include: 19 | - os: ubuntu-latest 20 | - os: macos-latest 21 | 22 | runs-on: ${{ matrix.os }} 23 | steps: 24 | - uses: actions/checkout@v4 25 | with: 26 | submodules: true 27 | persist-credentials: false 28 | 29 | - name: Install stable toolchain 30 | uses: dtolnay/rust-toolchain@master 31 | with: 32 | toolchain: stable 33 | components: llvm-tools 34 | 35 | - name: Install valgrind on Linux 36 | if: runner.os == 'Linux' 37 | run: sudo apt-get update && sudo apt-get install -y valgrind 38 | 39 | - name: Install cargo-llvm-cov 40 | uses: taiki-e/install-action@cargo-llvm-cov 41 | 42 | - name: Measure coverage 43 | run: ./admin/coverage --lcov --output-path final.info 44 | 45 | - name: Report to codecov.io 46 | uses: codecov/codecov-action@v5 47 | with: 48 | files: final.info 49 | token: ${{ secrets.CODECOV_TOKEN }} 50 | -------------------------------------------------------------------------------- /.github/workflows/ctgrind.yml: -------------------------------------------------------------------------------- 1 | name: ctgrind 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: "0 18 * * *" 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | VALGRIND_BUG_494162: 1 12 | 13 | jobs: 14 | build: 15 | strategy: 16 | matrix: 17 | include: 18 | - os: ubuntu-latest 19 | build: "" 20 | - os: ubuntu-latest 21 | build: --release 22 | 23 | runs-on: ${{ matrix.os }} 24 | steps: 25 | - uses: actions/checkout@v4 26 | with: 27 | submodules: true 28 | persist-credentials: false 29 | 30 | - name: Install stable toolchain 31 | uses: dtolnay/rust-toolchain@master 32 | with: 33 | toolchain: stable 34 | 35 | - name: Install valgrind 36 | run: sudo apt-get update && sudo apt-get install -y valgrind 37 | 38 | - name: ctgrind tests 39 | run: admin/ctgrind ${{ matrix.build }} 40 | -------------------------------------------------------------------------------- /.github/workflows/fuzz.yml: -------------------------------------------------------------------------------- 1 | name: fuzz 2 | 3 | on: 4 | push: 5 | pull_request: 6 | 7 | env: 8 | CARGO_TERM_COLOR: always 9 | 10 | jobs: 11 | fuzz: 12 | name: Smoke-test fuzzing targets 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout sources 16 | uses: actions/checkout@v4 17 | with: 18 | persist-credentials: false 19 | 20 | - name: Install nightly toolchain 21 | uses: dtolnay/rust-toolchain@nightly 22 | 23 | - name: Install cargo fuzz 24 | run: cargo install cargo-fuzz 25 | 26 | - name: Smoke-test fuzz targets 27 | run: | 28 | cargo fuzz build 29 | for target in $(cargo fuzz list) ; do 30 | cargo fuzz run $target -- -max_total_time=30 31 | done 32 | -------------------------------------------------------------------------------- /.github/workflows/lints.yml: -------------------------------------------------------------------------------- 1 | name: quality lints 2 | 3 | on: 4 | push: 5 | pull_request: 6 | schedule: 7 | - cron: "0 18 * * *" 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | msrv: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@v4 17 | with: 18 | submodules: true 19 | persist-credentials: false 20 | 21 | - name: Install MSRV toolchain 22 | uses: dtolnay/rust-toolchain@master 23 | with: 24 | toolchain: "1.72" 25 | 26 | - name: Check MSRV 27 | run: cargo build --lib --all-features 28 | 29 | lints: 30 | runs-on: ubuntu-latest 31 | steps: 32 | - uses: actions/checkout@v4 33 | with: 34 | submodules: true 35 | persist-credentials: false 36 | 37 | - uses: actions/setup-python@v5 38 | with: 39 | python-version: "3.12" 40 | 41 | - name: install codegen deps 42 | run: | 43 | sudo apt-get update 44 | sudo apt-get install -y cpp-aarch64-linux-gnu binutils-aarch64-linux-gnu 45 | sudo apt-get install -y valgrind 46 | sudo apt-get install -y graphviz 47 | 48 | - name: Install stable toolchain 49 | uses: dtolnay/rust-toolchain@master 50 | with: 51 | toolchain: stable 52 | components: rustfmt 53 | 54 | - name: Install cargo-modules 55 | uses: taiki-e/cache-cargo-install-action@v2 56 | with: 57 | tool: cargo-modules 58 | 59 | - name: Install nightly toolchain 60 | uses: dtolnay/rust-toolchain@master 61 | with: 62 | toolchain: nightly-2025-02-14 63 | components: rustfmt 64 | 65 | - name: clippy 66 | run: cargo +stable clippy --all-features --all-targets -- --deny warnings 67 | 68 | - name: rustfmt 69 | run: cargo +stable fmt --check 70 | 71 | - name: rustfmt (nightly) 72 | run: cargo +nightly-2025-02-14 fmt --check -- --config-path=.rustfmt.unstable.toml 73 | 74 | - name: check codegen 75 | working-directory: admin/parse-asm 76 | run: | 77 | ./all.sh 78 | git diff --exit-code 79 | 80 | - name: check license headers 81 | run: ./admin/scan-license 82 | 83 | - name: check module structure 84 | run: ./admin/structure 85 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "thirdparty/s2n-bignum"] 2 | path = thirdparty/s2n-bignum 3 | url = https://github.com/awslabs/s2n-bignum.git 4 | [submodule "thirdparty/wycheproof"] 5 | path = thirdparty/wycheproof 6 | url = https://github.com/C2SP/wycheproof.git 7 | [submodule "thirdparty/cavp"] 8 | path = thirdparty/cavp 9 | url = https://github.com/ctz/cavp.git 10 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | style_edition = "2024" 2 | -------------------------------------------------------------------------------- /.rustfmt.unstable.toml: -------------------------------------------------------------------------------- 1 | style_edition = "2024" 2 | group_imports = "StdExternalCrate" 3 | format_code_in_doc_comments = true 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = [ 4 | "graviola", 5 | "graviola-bench", 6 | "rustls-graviola", 7 | "fuzz", 8 | ] 9 | 10 | [profile.bench] 11 | lto = "thin" 12 | -------------------------------------------------------------------------------- /admin/bench-golang.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | import subprocess 4 | import os 5 | import json 6 | from os import path 7 | 8 | OUTPUT_PATH = "target/criterion" 9 | 10 | extra = ["-benchtime", "5s"] 11 | 12 | version = subprocess.check_output(["go", "version"], encoding="utf-8").strip() 13 | 14 | print(version) 15 | 16 | 17 | def measure(module, suite): 18 | print(f"MEASURE: {module} {suite}") 19 | cmd = ["go", "test", module, "-bench", suite] + extra 20 | lines = subprocess.check_output( 21 | cmd, 22 | encoding="utf-8", 23 | ).splitlines() 24 | 25 | transcript = "$ {}\n{}\n".format(" ".join(cmd), "\n".join(lines)) 26 | 27 | for line in lines: 28 | if line.startswith(suite): 29 | parts = line.split() 30 | assert "ns/op" in parts[3] 31 | value = float(parts[2]) 32 | secs = value * 1e-9 33 | print("=> {:g} ops/sec".format(1 / secs)) 34 | return value, transcript 35 | 36 | 37 | def insert_criterion_result(result, slug): 38 | p = path.join(OUTPUT_PATH, slug, "new") 39 | os.makedirs(p, exist_ok=True) 40 | 41 | obj = dict(median=dict(point_estimate=result)) 42 | json.dump(obj, open(path.join(p, "estimates.json"), "w")) 43 | 44 | 45 | # only measure "headlines" (see headlines.py on gh-pages branch) 46 | rsa_pkcs_sign, rsa_sign_transcript = measure("crypto/rsa", "BenchmarkSignPKCS1v15/2048") 47 | rsa_pkcs_verify, rsa_verify_transcript = measure( 48 | "crypto/rsa", "BenchmarkVerifyPKCS1v15/2048" 49 | ) 50 | 51 | aead_aesgcm256, aes_transcript = measure( 52 | "crypto/cipher", "BenchmarkAESGCM/Seal-256-8192" 53 | ) 54 | 55 | x25519_ecdh, x25519_transcript = measure("crypto/ecdh", "BenchmarkECDH/X25519") 56 | p256_ecdh, p256_transcript = measure("crypto/ecdh", "BenchmarkECDH/P256") 57 | p384_ecdh, p384_transcript = measure("crypto/ecdh", "BenchmarkECDH/P384") 58 | 59 | p256_sign, p256_sign_transcript = measure("crypto/ecdsa", "BenchmarkSign/P256") 60 | p384_sign, p384_sign_transcript = measure("crypto/ecdsa", "BenchmarkSign/P384") 61 | 62 | p256_verify, p256_verify_transcript = measure("crypto/ecdsa", "BenchmarkVerify/P256") 63 | p384_verify, p384_verify_transcript = measure("crypto/ecdsa", "BenchmarkVerify/P384") 64 | 65 | insert_criterion_result(rsa_pkcs_sign, "rsa2048-pkcs1-sha256-sign/golang") 66 | insert_criterion_result(rsa_pkcs_verify, "rsa2048-pkcs1-sha256-verify/golang") 67 | 68 | insert_criterion_result(aead_aesgcm256, "aes256-gcm/golang/8KB") 69 | 70 | insert_criterion_result(x25519_ecdh, "x25519-ecdh/golang") 71 | insert_criterion_result(p256_ecdh, "p256-ecdh/golang") 72 | insert_criterion_result(p384_ecdh, "p384-ecdh/golang") 73 | 74 | insert_criterion_result(p256_sign, "p256-ecdsa-sign/golang") 75 | insert_criterion_result(p384_sign, "p384-ecdsa-sign/golang") 76 | insert_criterion_result(p256_verify, "p256-ecdsa-verify/golang") 77 | insert_criterion_result(p384_verify, "p384-ecdsa-verify/golang") 78 | 79 | os.makedirs(path.join(OUTPUT_PATH, "report"), exist_ok=True) 80 | with open(path.join(OUTPUT_PATH, "report", "golang.txt"), "w") as f: 81 | print( 82 | f"""$ go version 83 | {version} 84 | 85 | {rsa_sign_transcript} 86 | 87 | {rsa_verify_transcript} 88 | 89 | {aes_transcript} 90 | 91 | {x25519_transcript} 92 | 93 | {p256_transcript} 94 | 95 | {p384_transcript} 96 | 97 | {p256_sign_transcript} 98 | 99 | {p384_sign_transcript} 100 | 101 | {p256_verify_transcript} 102 | 103 | {p384_verify_transcript} 104 | """, 105 | file=f, 106 | ) 107 | -------------------------------------------------------------------------------- /admin/bench-on-arm: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -ex 4 | 5 | HOST=arm-perf 6 | 7 | executables=$(cross bench --target aarch64-unknown-linux-gnu --no-run 2>&1 | grep Executable | grep -oE 'target/aarch64-unknown-linux-gnu/[^)]+') 8 | 9 | mkdir -p target/criterion/$HOST/criterion 10 | rsync --compress --progress $executables $HOST:~ 11 | for e in $executables ; do 12 | ee=$(basename $e) 13 | ssh $HOST "set -e ; ./$ee --bench $@" 14 | done 15 | -------------------------------------------------------------------------------- /admin/coverage: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -e 4 | 5 | cargo llvm-cov show-env --export-prefix "$@" > envsh 6 | source ./envsh 7 | cargo llvm-cov clean --workspace 8 | 9 | env SLOW_TESTS=1 cargo test --locked --all-features 10 | 11 | if [ `uname -p` == "x86_64" ] ; then 12 | env GRAVIOLA_CPU_DISABLE_sha=1 GRAVIOLA_CPU_DISABLE_bmi2=1 cargo test --locked 13 | fi 14 | cargo run --example client https://jbp.io >/dev/null 15 | 16 | cargo llvm-cov report "$@" 17 | -------------------------------------------------------------------------------- /admin/ctgrind: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | 4 | # ensure tests are built: cargo and rustc are not valgrind-friendly 5 | cargo test --no-run "$@" 6 | 7 | # nb. do not run zeroing test, it is extremely valgrind-unfriendly 8 | valgrind --trace-children=yes --track-origins=yes \ 9 | cargo test --lib --test wycheproof "$@" 10 | -------------------------------------------------------------------------------- /admin/parse-asm/.gitignore: -------------------------------------------------------------------------------- 1 | assembled.o 2 | preprocessed.S 3 | __pycache__/ 4 | -------------------------------------------------------------------------------- /admin/parse-asm/all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | for d in driver.*.py ; do 4 | python $d 5 | done 6 | -------------------------------------------------------------------------------- /admin/parse-asm/driver.x25519.py: -------------------------------------------------------------------------------- 1 | from parse import parse_file 2 | from driver import ( 3 | Architecture_aarch64, 4 | Architecture_amd64, 5 | RustDriver, 6 | ) 7 | 8 | if __name__ == "__main__": 9 | with open( 10 | "../../thirdparty/s2n-bignum/x86/curve25519/curve25519_x25519.S" 11 | ) as input, open( 12 | "../../graviola/src/low/x86_64/curve25519_x25519.rs", "w" 13 | ) as output: 14 | d = RustDriver(output, Architecture_amd64) 15 | d.emit_rust_function( 16 | "curve25519_x25519", 17 | parameter_map=[ 18 | ("inout", "res.as_mut_ptr() => _"), 19 | ("inout", "scalar.as_ptr() => _"), 20 | ("inout", "point.as_ptr() => _"), 21 | ], 22 | rust_decl="fn curve25519_x25519(res: &mut [u64; 4], scalar: &[u64; 4], point: &[u64; 4])", 23 | ) 24 | parse_file(input, d) 25 | 26 | with open( 27 | "../../thirdparty/s2n-bignum/x86/curve25519/curve25519_x25519base.S" 28 | ) as input, open( 29 | "../../graviola/src/low/x86_64/curve25519_x25519base.rs", "w" 30 | ) as output: 31 | d = RustDriver(output, Architecture_amd64) 32 | d.add_const_symbol("curve25519_x25519base_edwards25519_0g") 33 | d.add_const_symbol("curve25519_x25519base_edwards25519_8g") 34 | d.add_const_symbol("curve25519_x25519base_edwards25519_gtable") 35 | d.emit_rust_function( 36 | "curve25519_x25519base", 37 | parameter_map=[ 38 | ("inout", "res.as_mut_ptr() => _"), 39 | ("inout", "scalar.as_ptr() => _"), 40 | ], 41 | rust_decl="fn curve25519_x25519base(res: &mut [u64; 4], scalar: &[u64; 4])", 42 | ) 43 | parse_file(input, d) 44 | 45 | with open( 46 | "../../thirdparty/s2n-bignum/arm/curve25519/curve25519_x25519_alt.S" 47 | ) as input, open( 48 | "../../graviola/src/low/aarch64/curve25519_x25519.rs", "w" 49 | ) as output: 50 | d = RustDriver(output, Architecture_aarch64) 51 | d.emit_rust_function( 52 | "curve25519_x25519_alt", 53 | parameter_map=[ 54 | ("inout", "res.as_mut_ptr() => _"), 55 | ("inout", "scalar.as_ptr() => _"), 56 | ("inout", "point.as_ptr() => _"), 57 | ], 58 | rust_decl="fn curve25519_x25519(res: &mut [u64; 4], scalar: &[u64; 4], point: &[u64; 4])", 59 | ) 60 | parse_file(input, d) 61 | 62 | with open( 63 | "../../thirdparty/s2n-bignum/arm/curve25519/curve25519_x25519base_alt.S" 64 | ) as input, open( 65 | "../../graviola/src/low/aarch64/curve25519_x25519base.rs", "w" 66 | ) as output: 67 | d = RustDriver(output, Architecture_aarch64) 68 | d.add_const_symbol("curve25519_x25519base_alt_edwards25519_0g") 69 | d.add_const_symbol("curve25519_x25519base_alt_edwards25519_8g") 70 | d.add_const_symbol("curve25519_x25519base_alt_edwards25519_gtable") 71 | d.emit_rust_function( 72 | "curve25519_x25519base_alt", 73 | parameter_map=[ 74 | ("inout", "res.as_mut_ptr() => _"), 75 | ("inout", "scalar.as_ptr() => _"), 76 | ], 77 | rust_decl="fn curve25519_x25519base(res: &mut [u64; 4], scalar: &[u64; 4])", 78 | ) 79 | parse_file(input, d) 80 | -------------------------------------------------------------------------------- /admin/picture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/admin/picture.png -------------------------------------------------------------------------------- /admin/scan-license: -------------------------------------------------------------------------------- 1 | #!/usr/bin/bash 2 | 3 | set -e 4 | 5 | bad=0 6 | for f in $(find graviola/src/ -name *.rs -exec grep -L "SPDX-License-Identifier:" {} +) ; do 7 | echo "$f requires a SPDX-License-Identifier" 8 | bad=1 9 | done 10 | 11 | exit $bad 12 | -------------------------------------------------------------------------------- /admin/structure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This script analyses the structure of graviola to ensure there are no references 4 | # from graviola::low to graviola::mid, or graviola::mid to graviola::high. 5 | set -e 6 | 7 | cat >structure.gvpr <mid\n", name); 14 | rc = 1; 15 | errors += 1; 16 | } 17 | E [match(tail.name, "graviola::low::") == 0 && match(head.name, "graviola::high::") == 0] { 18 | printf(2, "ERROR: edge %s is a dependency low->high\n", name); 19 | rc = 1; 20 | errors += 1; 21 | } 22 | E [match(tail.name, "graviola::mid::") == 0 && match(head.name, "graviola::high::") == 0] { 23 | printf(2, "ERROR: edge %s is a dependency mid->high\n", name); 24 | rc = 1; 25 | errors += 1; 26 | } 27 | END { 28 | printf(2, "%d errors\n", errors); 29 | exit(rc); 30 | } 31 | END 32 | 33 | cargo modules dependencies \ 34 | --no-externs \ 35 | --no-sysroot \ 36 | -p graviola | gvpr -f structure.gvpr 37 | -------------------------------------------------------------------------------- /fuzz/.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | corpus 3 | artifacts 4 | coverage 5 | -------------------------------------------------------------------------------- /fuzz/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "graviola-fuzz" 3 | version = "0.0.0" 4 | publish = false 5 | edition = "2021" 6 | 7 | [package.metadata] 8 | cargo-fuzz = true 9 | 10 | [dependencies] 11 | libfuzzer-sys = { version = "0.4", features = ["arbitrary-derive"] } 12 | aws-lc-rs = { version = "1", features = ["non-fips"], default-features = false } 13 | 14 | [dependencies.graviola] 15 | path = "../graviola" 16 | 17 | [[bin]] 18 | name = "sha2" 19 | path = "fuzzer/sha2.rs" 20 | test = false 21 | doc = false 22 | bench = false 23 | 24 | [[bin]] 25 | name = "aead" 26 | path = "fuzzer/aead.rs" 27 | test = false 28 | doc = false 29 | bench = false 30 | 31 | [[bin]] 32 | name = "kx" 33 | path = "fuzzer/kx.rs" 34 | test = false 35 | doc = false 36 | bench = false 37 | -------------------------------------------------------------------------------- /fuzz/fuzzer/aead.rs: -------------------------------------------------------------------------------- 1 | #![no_main] 2 | 3 | use libfuzzer_sys::{arbitrary, arbitrary::Arbitrary, fuzz_target}; 4 | 5 | fuzz_target!(|op: Operation| { 6 | match op { 7 | Operation::ChaCha20Poly1305 { 8 | key, 9 | nonce, 10 | aad, 11 | plain, 12 | } => { 13 | let right = baseline_encrypt( 14 | &aws_lc_rs::aead::CHACHA20_POLY1305, 15 | &key, 16 | &nonce, 17 | &aad, 18 | &plain, 19 | ); 20 | let left = { 21 | let k = graviola::aead::ChaCha20Poly1305::new(key); 22 | let mut cipher = plain.clone(); 23 | let mut tag = [0u8; 16]; 24 | k.encrypt(&nonce, &aad, &mut cipher, &mut tag); 25 | 26 | let mut roundtrip = cipher.clone(); 27 | k.decrypt(&nonce, &aad, &mut roundtrip, &tag).unwrap(); 28 | assert_eq!(roundtrip, plain); 29 | (cipher, tag) 30 | }; 31 | 32 | assert_eq!(left, right); 33 | } 34 | Operation::Aes128Gcm { 35 | key, 36 | nonce, 37 | aad, 38 | plain, 39 | } => { 40 | let right = baseline_encrypt(&aws_lc_rs::aead::AES_128_GCM, &key, &nonce, &aad, &plain); 41 | let left = { 42 | let k = graviola::aead::AesGcm::new(&key); 43 | let mut cipher = plain.clone(); 44 | let mut tag = [0u8; 16]; 45 | k.encrypt(&nonce, &aad, &mut cipher, &mut tag); 46 | 47 | let mut roundtrip = cipher.clone(); 48 | k.decrypt(&nonce, &aad, &mut roundtrip, &tag).unwrap(); 49 | assert_eq!(roundtrip, plain); 50 | (cipher, tag) 51 | }; 52 | 53 | assert_eq!(left, right); 54 | } 55 | Operation::Aes256Gcm { 56 | key, 57 | nonce, 58 | aad, 59 | plain, 60 | } => { 61 | let right = baseline_encrypt(&aws_lc_rs::aead::AES_256_GCM, &key, &nonce, &aad, &plain); 62 | let left = { 63 | let k = graviola::aead::AesGcm::new(&key); 64 | let mut cipher = plain.clone(); 65 | let mut tag = [0u8; 16]; 66 | k.encrypt(&nonce, &aad, &mut cipher, &mut tag); 67 | 68 | let mut roundtrip = cipher.clone(); 69 | k.decrypt(&nonce, &aad, &mut roundtrip, &tag).unwrap(); 70 | assert_eq!(roundtrip, plain); 71 | (cipher, tag) 72 | }; 73 | 74 | assert_eq!(left, right); 75 | } 76 | } 77 | }); 78 | 79 | fn baseline_encrypt( 80 | alg: &'static aws_lc_rs::aead::Algorithm, 81 | key: &[u8], 82 | nonce: &[u8; 12], 83 | aad: &[u8], 84 | plain: &[u8], 85 | ) -> (Vec, [u8; 16]) { 86 | let k = aws_lc_rs::aead::LessSafeKey::new(aws_lc_rs::aead::UnboundKey::new(alg, key).unwrap()); 87 | let mut cipher = plain.to_vec(); 88 | let tag = k 89 | .seal_in_place_separate_tag( 90 | aws_lc_rs::aead::Nonce::assume_unique_for_key(*nonce), 91 | aws_lc_rs::aead::Aad::from(aad), 92 | &mut cipher, 93 | ) 94 | .unwrap(); 95 | 96 | let mut tag_array = [0u8; 16]; 97 | tag_array.copy_from_slice(tag.as_ref()); 98 | (cipher, tag_array) 99 | } 100 | 101 | #[derive(Arbitrary, Debug)] 102 | enum Operation { 103 | ChaCha20Poly1305 { 104 | key: [u8; 32], 105 | nonce: [u8; 12], 106 | aad: Vec, 107 | plain: Vec, 108 | }, 109 | Aes128Gcm { 110 | key: [u8; 16], 111 | nonce: [u8; 12], 112 | aad: Vec, 113 | plain: Vec, 114 | }, 115 | Aes256Gcm { 116 | key: [u8; 32], 117 | nonce: [u8; 12], 118 | aad: Vec, 119 | plain: Vec, 120 | }, 121 | } 122 | -------------------------------------------------------------------------------- /graviola-bench/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "graviola-bench" 3 | version = "0.1.0" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | graviola = { path = "../graviola" } 8 | codspeed-criterion-compat = { optional = true, version = "2" } 9 | 10 | [dev-dependencies] 11 | aes-gcm = "0.10" 12 | aws-lc-rs = { version = "1", features = ["non-fips"], default-features = false } 13 | chacha20poly1305 = "0.10" 14 | criterion = "0.5" 15 | hex = { version = "0.4", features = ["serde"] } 16 | hmac = "0.12" 17 | p256 = { version = "0.13.2", features = ["ecdh"] } 18 | p384 = { version = "0.13", features = ["ecdh"] } 19 | proptest = "1.5.0" 20 | rand_core = { version = "0.6", features = ["getrandom"] } 21 | ring = "0.17" 22 | rsa = { version = "0.9", features = ["sha2"] } 23 | serde = { version = "1", features = ["derive"] } 24 | serde_json = "1" 25 | sha2 = "0.10.8" 26 | x25519-dalek = "2" 27 | 28 | [target.'cfg(all(target_arch = "x86_64", target_os = "linux"))'.dev-dependencies] 29 | openssl = "0.10" 30 | 31 | [features] 32 | __bench_openssl = [] 33 | __bench_codspeed = ["dep:codspeed-criterion-compat"] 34 | 35 | [[bench]] 36 | name = "x25519" 37 | harness = false 38 | 39 | [[bench]] 40 | name = "p256" 41 | harness = false 42 | 43 | [[bench]] 44 | name = "p384" 45 | harness = false 46 | 47 | [[bench]] 48 | name = "sha2" 49 | harness = false 50 | 51 | [[bench]] 52 | name = "aes_gcm" 53 | harness = false 54 | 55 | [[bench]] 56 | name = "rsa_pub" 57 | harness = false 58 | 59 | [[bench]] 60 | name = "rsa_priv" 61 | harness = false 62 | 63 | [[bench]] 64 | name = "rsa_gen" 65 | harness = false 66 | 67 | [[bench]] 68 | name = "chacha20poly1305" 69 | harness = false 70 | 71 | [[bench]] 72 | name = "xchacha20poly1305" 73 | harness = false 74 | 75 | [[bench]] 76 | name = "hmac" 77 | harness = false 78 | -------------------------------------------------------------------------------- /graviola-bench/benches/chacha20poly1305.rs: -------------------------------------------------------------------------------- 1 | mod criterion; 2 | use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main}; 3 | 4 | fn test_ring_chacha(key: &ring::aead::LessSafeKey, nonce: &[u8; 12], aad: &[u8], plain: &[u8]) { 5 | let mut ct = plain.to_vec(); 6 | let _tag = key 7 | .seal_in_place_separate_tag( 8 | ring::aead::Nonce::assume_unique_for_key(*nonce), 9 | ring::aead::Aad::from(aad), 10 | &mut ct, 11 | ) 12 | .unwrap(); 13 | } 14 | 15 | fn test_aws_chacha(key: &aws_lc_rs::aead::LessSafeKey, nonce: &[u8; 12], aad: &[u8], plain: &[u8]) { 16 | let mut ct = plain.to_vec(); 17 | let _tag = key 18 | .seal_in_place_separate_tag(nonce.into(), aws_lc_rs::aead::Aad::from(aad), &mut ct) 19 | .unwrap(); 20 | } 21 | 22 | fn test_rc_chacha( 23 | key: &chacha20poly1305::ChaCha20Poly1305, 24 | nonce: &[u8; 12], 25 | aad: &[u8], 26 | plain: &[u8], 27 | ) { 28 | use chacha20poly1305::AeadInPlace; 29 | let mut ct = plain.to_vec(); 30 | let _tag = key 31 | .encrypt_in_place_detached(nonce.into(), aad, &mut ct) 32 | .unwrap(); 33 | } 34 | 35 | fn test_graviola_chacha( 36 | key: &graviola::aead::ChaCha20Poly1305, 37 | nonce: &[u8; 12], 38 | aad: &[u8], 39 | plain: &[u8], 40 | ) { 41 | let mut ct = plain.to_vec(); 42 | let mut tag = [0u8; 16]; 43 | key.encrypt(nonce, aad, &mut ct, &mut tag); 44 | } 45 | 46 | fn bench_chacha20poly1305(c: &mut Criterion) { 47 | let key = [0u8; 32]; 48 | let nonce = [0u8; 12]; 49 | let aad = [0u8; 32]; 50 | 51 | let mut group = c.benchmark_group("chacha20poly1305"); 52 | for (size, size_name) in [(32, "32B"), (2048, "2KB"), (16384, "16KB")] { 53 | let input = vec![0u8; size]; 54 | group.throughput(Throughput::Bytes(size as u64)); 55 | 56 | group.bench_with_input(BenchmarkId::new("ring", size_name), &input, |b, input| { 57 | use ring::aead::{CHACHA20_POLY1305, LessSafeKey, UnboundKey}; 58 | let key = UnboundKey::new(&CHACHA20_POLY1305, &key).unwrap(); 59 | let key = LessSafeKey::new(key); 60 | b.iter(|| test_ring_chacha(&key, &nonce, &aad, input)); 61 | }); 62 | group.bench_with_input( 63 | BenchmarkId::new("aws-lc-rs", size_name), 64 | &input, 65 | |b, input| { 66 | use aws_lc_rs::aead::{CHACHA20_POLY1305, LessSafeKey, UnboundKey}; 67 | let key = UnboundKey::new(&CHACHA20_POLY1305, &key).unwrap(); 68 | let key = LessSafeKey::new(key); 69 | b.iter(|| test_aws_chacha(&key, &nonce, &aad, input)); 70 | }, 71 | ); 72 | group.bench_with_input( 73 | BenchmarkId::new("rustcrypto", size_name), 74 | &input, 75 | |b, input| { 76 | use chacha20poly1305::KeyInit; 77 | let key = chacha20poly1305::ChaCha20Poly1305::new_from_slice(&key).unwrap(); 78 | b.iter(|| test_rc_chacha(&key, &nonce, &aad, input)); 79 | }, 80 | ); 81 | group.bench_with_input( 82 | BenchmarkId::new("graviola", size_name), 83 | &input, 84 | |b, input| { 85 | let key = graviola::aead::ChaCha20Poly1305::new(key); 86 | b.iter(|| test_graviola_chacha(&key, &nonce, &aad, input)); 87 | }, 88 | ); 89 | } 90 | } 91 | 92 | criterion_group!(benches, bench_chacha20poly1305); 93 | criterion_main!(benches); 94 | -------------------------------------------------------------------------------- /graviola-bench/benches/criterion.rs: -------------------------------------------------------------------------------- 1 | #[cfg(feature = "__bench_codspeed")] 2 | pub use codspeed_criterion_compat::*; 3 | #[cfg(not(feature = "__bench_codspeed"))] 4 | pub use criterion::*; 5 | -------------------------------------------------------------------------------- /graviola-bench/benches/hmac.rs: -------------------------------------------------------------------------------- 1 | mod criterion; 2 | use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main}; 3 | use hmac::Mac; 4 | 5 | fn test_ring_sha256(key: &[u8], data: &[u8]) { 6 | let mut ctx = 7 | ring::hmac::Context::with_key(&ring::hmac::Key::new(ring::hmac::HMAC_SHA256, key)); 8 | ctx.update(data); 9 | black_box(ctx.sign()); 10 | } 11 | 12 | fn test_ring_sha384(key: &[u8], data: &[u8]) { 13 | let mut ctx = 14 | ring::hmac::Context::with_key(&ring::hmac::Key::new(ring::hmac::HMAC_SHA384, key)); 15 | ctx.update(data); 16 | black_box(ctx.sign()); 17 | } 18 | 19 | fn test_aws_sha256(key: &[u8], data: &[u8]) { 20 | let mut ctx = aws_lc_rs::hmac::Context::with_key(&aws_lc_rs::hmac::Key::new( 21 | aws_lc_rs::hmac::HMAC_SHA256, 22 | key, 23 | )); 24 | ctx.update(data); 25 | black_box(ctx.sign()); 26 | } 27 | 28 | fn test_aws_sha384(key: &[u8], data: &[u8]) { 29 | let mut ctx = aws_lc_rs::hmac::Context::with_key(&aws_lc_rs::hmac::Key::new( 30 | aws_lc_rs::hmac::HMAC_SHA384, 31 | key, 32 | )); 33 | ctx.update(data); 34 | black_box(ctx.sign()); 35 | } 36 | 37 | fn test_rc_sha256(key: &[u8], data: &[u8]) { 38 | let mut ctx = hmac::Hmac::::new_from_slice(key).unwrap(); 39 | ctx.update(data); 40 | black_box(ctx.finalize()); 41 | } 42 | 43 | fn test_rc_sha384(key: &[u8], data: &[u8]) { 44 | let mut ctx = hmac::Hmac::::new_from_slice(key).unwrap(); 45 | ctx.update(data); 46 | black_box(ctx.finalize()); 47 | } 48 | 49 | fn test_graviola_sha256(key: &[u8], data: &[u8]) { 50 | let mut ctx = graviola::hashing::hmac::Hmac::::new(key); 51 | ctx.update(data); 52 | black_box(ctx.finish()); 53 | } 54 | 55 | fn test_graviola_sha384(key: &[u8], data: &[u8]) { 56 | let mut ctx = graviola::hashing::hmac::Hmac::::new(key); 57 | ctx.update(data); 58 | black_box(ctx.finish()); 59 | } 60 | 61 | fn sha256(c: &mut Criterion) { 62 | let mut group = c.benchmark_group("hmac-sha256"); 63 | let key = [0xff; 48]; 64 | 65 | for (size, size_name) in [(32, "32B"), (2048, "2KB")] { 66 | let input = vec![0u8; size]; 67 | group.throughput(Throughput::Elements(1)); 68 | 69 | group.bench_with_input(BenchmarkId::new("ring", size_name), &input, |b, input| { 70 | b.iter(|| test_ring_sha256(&key, input)) 71 | }); 72 | group.bench_with_input( 73 | BenchmarkId::new("aws-lc-rs", size_name), 74 | &input, 75 | |b, input| b.iter(|| test_aws_sha256(&key, input)), 76 | ); 77 | group.bench_with_input( 78 | BenchmarkId::new("rustcrypto", size_name), 79 | &input, 80 | |b, input| b.iter(|| test_rc_sha256(&key, input)), 81 | ); 82 | group.bench_with_input( 83 | BenchmarkId::new("graviola", size_name), 84 | &input, 85 | |b, input| b.iter(|| test_graviola_sha256(&key, input)), 86 | ); 87 | } 88 | } 89 | 90 | fn sha384(c: &mut Criterion) { 91 | let mut group = c.benchmark_group("hmac-sha384"); 92 | let key = [0xff; 48]; 93 | 94 | for (size, size_name) in [(32, "32B"), (2048, "2KB")] { 95 | let input = vec![0u8; size]; 96 | group.throughput(Throughput::Elements(1)); 97 | 98 | group.bench_with_input(BenchmarkId::new("ring", size_name), &input, |b, input| { 99 | b.iter(|| test_ring_sha384(&key, input)) 100 | }); 101 | group.bench_with_input( 102 | BenchmarkId::new("aws-lc-rs", size_name), 103 | &input, 104 | |b, input| b.iter(|| test_aws_sha384(&key, input)), 105 | ); 106 | group.bench_with_input( 107 | BenchmarkId::new("rustcrypto", size_name), 108 | &input, 109 | |b, input| b.iter(|| test_rc_sha384(&key, input)), 110 | ); 111 | group.bench_with_input( 112 | BenchmarkId::new("graviola", size_name), 113 | &input, 114 | |b, input| b.iter(|| test_graviola_sha384(&key, input)), 115 | ); 116 | } 117 | } 118 | 119 | criterion_group!(benches, sha256, sha384); 120 | criterion_main!(benches); 121 | -------------------------------------------------------------------------------- /graviola-bench/benches/rsa_gen.rs: -------------------------------------------------------------------------------- 1 | mod criterion; 2 | use criterion::{Criterion, Throughput, black_box, criterion_group, criterion_main}; 3 | 4 | fn rsa_key_generation(c: &mut Criterion) { 5 | // All these are gated under `NOISY_BENCHMARKS` for the benefit of codspeed, 6 | // which runs each test once and expects deterministic results. RSA key generation 7 | // certainly is not that. 8 | if option_env!("NOISY_BENCHMARKS").is_none() { 9 | return; 10 | } 11 | 12 | let mut group = c.benchmark_group("rsa2048-key-generation"); 13 | group.throughput(Throughput::Elements(1)); 14 | 15 | group.bench_function("aws-lc-rs", |b| { 16 | use aws_lc_rs::rsa; 17 | 18 | b.iter(|| { 19 | black_box(rsa::KeyPair::generate(rsa::KeySize::Rsa2048).unwrap()); 20 | }) 21 | }); 22 | 23 | group.bench_function("graviola", |b| { 24 | use graviola::signing::rsa; 25 | 26 | b.iter(|| { 27 | black_box(rsa::SigningKey::generate(rsa::KeySize::Rsa2048).unwrap()); 28 | }) 29 | }); 30 | 31 | group.bench_function("rustcrypto", |b| { 32 | use rsa::RsaPrivateKey; 33 | 34 | b.iter(|| { 35 | black_box(RsaPrivateKey::new(&mut rand_core::OsRng, 2048).unwrap()); 36 | }) 37 | }); 38 | } 39 | 40 | criterion_group!(benches, rsa_key_generation); 41 | criterion_main!(benches); 42 | -------------------------------------------------------------------------------- /graviola-bench/benches/rsa_priv.rs: -------------------------------------------------------------------------------- 1 | mod criterion; 2 | use criterion::{Criterion, Throughput, black_box, criterion_group, criterion_main}; 3 | 4 | fn rsa2048_pkcs1_sha256_sign(c: &mut Criterion) { 5 | let private_key = include_bytes!("../../graviola/src/high/rsa/rsa2048.der"); 6 | let message = 7 | b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; 8 | 9 | let mut group = c.benchmark_group("rsa2048-pkcs1-sha256-sign"); 10 | group.throughput(Throughput::Elements(1)); 11 | 12 | group.bench_function("ring", |b| { 13 | use ring::{rand, rsa, signature}; 14 | 15 | let key = rsa::KeyPair::from_der(private_key).unwrap(); 16 | let rng = rand::SystemRandom::new(); 17 | 18 | b.iter(|| { 19 | let mut signature = [0u8; 256]; 20 | black_box(key.sign(&signature::RSA_PKCS1_SHA256, &rng, message, &mut signature)) 21 | .unwrap(); 22 | }) 23 | }); 24 | 25 | group.bench_function("aws-lc-rs", |b| { 26 | use aws_lc_rs::{rand, rsa, signature}; 27 | 28 | let key = rsa::KeyPair::from_der(private_key).unwrap(); 29 | let rng = rand::SystemRandom::new(); 30 | 31 | b.iter(|| { 32 | let mut signature = [0u8; 256]; 33 | black_box(key.sign(&signature::RSA_PKCS1_SHA256, &rng, message, &mut signature)) 34 | .unwrap(); 35 | }) 36 | }); 37 | 38 | group.bench_function("rustcrypto", |b| { 39 | use rsa::pkcs1::DecodeRsaPrivateKey; 40 | use rsa::signature::Signer; 41 | let key = rsa::pkcs1v15::SigningKey::::new( 42 | rsa::RsaPrivateKey::from_pkcs1_der(private_key).unwrap(), 43 | ); 44 | 45 | b.iter(|| { 46 | black_box(key.sign(message)); 47 | }); 48 | }); 49 | 50 | group.bench_function("graviola", |b| { 51 | let key = graviola::signing::rsa::SigningKey::from_pkcs1_der(private_key).unwrap(); 52 | 53 | b.iter(|| { 54 | black_box(key.sign_pkcs1_sha256(&mut [0u8; 256], message).unwrap()); 55 | }) 56 | }); 57 | } 58 | 59 | criterion_group!(benches, rsa2048_pkcs1_sha256_sign); 60 | criterion_main!(benches); 61 | -------------------------------------------------------------------------------- /graviola-bench/benches/rsa_pub.rs: -------------------------------------------------------------------------------- 1 | mod criterion; 2 | use criterion::{Criterion, Throughput, black_box, criterion_group, criterion_main}; 3 | 4 | fn rsa2048_pkcs1_sha256_verify(c: &mut Criterion) { 5 | let public_key = b"\x30\x82\x01\x0a\x02\x82\x01\x01\x00\xa2\xb4\x51\xa0\x7d\x0a\xa5\xf9\x6e\x45\x56\x71\x51\x35\x50\x51\x4a\x8a\x5b\x46\x2e\xbe\xf7\x17\x09\x4f\xa1\xfe\xe8\x22\x24\xe6\x37\xf9\x74\x6d\x3f\x7c\xaf\xd3\x18\x78\xd8\x03\x25\xb6\xef\x5a\x17\x00\xf6\x59\x03\xb4\x69\x42\x9e\x89\xd6\xea\xc8\x84\x50\x97\xb5\xab\x39\x31\x89\xdb\x92\x51\x2e\xd8\xa7\x71\x1a\x12\x53\xfa\xcd\x20\xf7\x9c\x15\xe8\x24\x7f\x3d\x3e\x42\xe4\x6e\x48\xc9\x8e\x25\x4a\x2f\xe9\x76\x53\x13\xa0\x3e\xff\x8f\x17\xe1\xa0\x29\x39\x7a\x1f\xa2\x6a\x8d\xce\x26\xf4\x90\xed\x81\x29\x96\x15\xd9\x81\x4c\x22\xda\x61\x04\x28\xe0\x9c\x7d\x96\x58\x59\x42\x66\xf5\xc0\x21\xd0\xfc\xec\xa0\x8d\x94\x5a\x12\xbe\x82\xde\x4d\x1e\xce\x6b\x4c\x03\x14\x5b\x5d\x34\x95\xd4\xed\x54\x11\xeb\x87\x8d\xaf\x05\xfd\x7a\xfc\x3e\x09\xad\xa0\xf1\x12\x64\x22\xf5\x90\x97\x5a\x19\x69\x81\x6f\x48\x69\x8b\xcb\xba\x1b\x4d\x9c\xae\x79\xd4\x60\xd8\xf9\xf8\x5e\x79\x75\x00\x5d\x9b\xc2\x2c\x4e\x5a\xc0\xf7\xc1\xa4\x5d\x12\x56\x9a\x62\x80\x7d\x3b\x9a\x02\xe5\xa5\x30\xe7\x73\x06\x6f\x45\x3d\x1f\x5b\x4c\x2e\x9c\xf7\x82\x02\x83\xf7\x42\xb9\xd5\x02\x03\x01\x00\x01"; 6 | let signature = b"\x8a\x1b\x22\x0c\xb2\xab\x41\x5d\xc7\x60\xeb\x7f\x5b\xb1\x03\x35\xa3\xcc\xa2\x69\xd7\xdb\xbf\x7d\x09\x62\xba\x79\xf9\xcf\x7b\x43\xa5\xfc\x09\xc9\x9a\x15\x84\xf0\x74\x03\x47\x3d\x6c\x18\x9a\x83\x68\x97\xa5\xb6\xf8\xea\x9f\xa2\x2d\x60\x1e\x6b\xa5\xf7\x41\x1f\xe2\x7c\x63\x8b\x81\xb1\xa2\x23\x63\x58\x3a\x80\xfc\xe8\xc7\xdf\x3e\x40\xfb\x51\xbd\x0e\x60\xd0\xa6\x65\x3f\x79\xf3\xbc\xb7\xec\x3e\x9d\xc1\x4c\xfb\x5b\x31\xab\x17\x35\xbc\xa6\x92\xd5\x0a\xc0\x3f\x97\x9d\xda\x92\x74\x7c\x64\x30\xf8\x04\x5e\xfa\x35\x13\xba\x6e\x0c\xe3\xe9\xe3\x55\x70\xe1\xc3\x0c\x8e\xbe\x58\x9b\x44\x19\x2e\x13\x44\xca\x83\xdf\xa5\x76\xfc\x6f\xdc\x7b\xf1\xcd\x7c\xee\x87\x5b\x00\x1c\x8c\x02\xce\x8d\x60\x27\x69\xe4\xbd\x9d\x24\x1c\x48\x57\x18\x2a\x00\x89\xa8\xb6\x76\x44\xe7\x3e\xef\x10\x5c\x55\x0e\xfa\x47\xa4\x08\x74\x28\x93\x95\xac\x0c\x4e\x02\xfd\x4b\xa9\x8e\x13\x0a\x4c\x2d\x1b\x95\x52\x1c\x6a\xf4\xa0\x02\xac\x3b\xdc\x6e\x52\x12\x2a\xe4\xc0\x8c\xc3\xda\x1c\x89\x6e\x05\x9a\xcb\xdd\xec\x57\x4a\xc0\x43\x2f\x61\x03\xdd\x97\x27\x3d\x88\x03\xc1\x02"; 7 | let message = 8 | b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; 9 | 10 | let mut group = c.benchmark_group("rsa2048-pkcs1-sha256-verify"); 11 | group.throughput(Throughput::Elements(1)); 12 | 13 | group.bench_function("ring", |b| { 14 | use ring::signature; 15 | let peer_public_key = 16 | signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, public_key); 17 | 18 | b.iter(|| { 19 | black_box(peer_public_key.verify(message, signature)).unwrap(); 20 | }) 21 | }); 22 | 23 | group.bench_function("aws-lc-rs", |b| { 24 | use aws_lc_rs::signature; 25 | let peer_public_key = 26 | signature::UnparsedPublicKey::new(&signature::RSA_PKCS1_2048_8192_SHA256, public_key); 27 | 28 | b.iter(|| { 29 | black_box(peer_public_key.verify(message, signature)).unwrap(); 30 | }) 31 | }); 32 | 33 | group.bench_function("rustcrypto", |b| { 34 | use rsa::pkcs1::DecodeRsaPublicKey; 35 | use rsa::signature::Verifier; 36 | let peer_public_key = rsa::pkcs1v15::VerifyingKey::::new( 37 | rsa::RsaPublicKey::from_pkcs1_der(public_key).unwrap(), 38 | ); 39 | 40 | b.iter(|| { 41 | let signature = rsa::pkcs1v15::Signature::try_from(&signature[..]).unwrap(); 42 | black_box(peer_public_key.verify(message, &signature)).unwrap(); 43 | }); 44 | }); 45 | 46 | group.bench_function("graviola", |b| { 47 | let peer_public_key = 48 | graviola::signing::rsa::VerifyingKey::from_pkcs1_der(public_key).unwrap(); 49 | 50 | b.iter(|| { 51 | black_box(peer_public_key.verify_pkcs1_sha256(signature, message)).unwrap(); 52 | }) 53 | }); 54 | } 55 | 56 | criterion_group!(benches, rsa2048_pkcs1_sha256_verify); 57 | criterion_main!(benches); 58 | -------------------------------------------------------------------------------- /graviola-bench/benches/sha2.rs: -------------------------------------------------------------------------------- 1 | mod criterion; 2 | use criterion::{BenchmarkId, Criterion, Throughput, black_box, criterion_group, criterion_main}; 3 | use sha2::Digest; 4 | 5 | fn test_ring_sha256(data: &[u8]) { 6 | let mut ctx = ring::digest::Context::new(&ring::digest::SHA256); 7 | ctx.update(data); 8 | black_box(ctx.finish()); 9 | } 10 | 11 | fn test_ring_sha512(data: &[u8]) { 12 | let mut ctx = ring::digest::Context::new(&ring::digest::SHA512); 13 | ctx.update(data); 14 | black_box(ctx.finish()); 15 | } 16 | 17 | fn test_aws_sha256(data: &[u8]) { 18 | let mut ctx = aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA256); 19 | ctx.update(data); 20 | black_box(ctx.finish()); 21 | } 22 | 23 | fn test_aws_sha512(data: &[u8]) { 24 | let mut ctx = aws_lc_rs::digest::Context::new(&aws_lc_rs::digest::SHA512); 25 | ctx.update(data); 26 | black_box(ctx.finish()); 27 | } 28 | 29 | fn test_rc_sha256(data: &[u8]) { 30 | let mut ctx = sha2::Sha256::new(); 31 | ctx.update(data); 32 | black_box(ctx.finalize()); 33 | } 34 | 35 | fn test_rc_sha512(data: &[u8]) { 36 | let mut ctx = sha2::Sha512::new(); 37 | ctx.update(data); 38 | black_box(ctx.finalize()); 39 | } 40 | 41 | fn test_graviola_sha256(data: &[u8]) { 42 | let mut ctx = graviola::hashing::sha2::Sha256Context::new(); 43 | ctx.update(data); 44 | black_box(ctx.finish()); 45 | } 46 | 47 | fn test_graviola_sha512(data: &[u8]) { 48 | let mut ctx = graviola::hashing::sha2::Sha512Context::new(); 49 | ctx.update(data); 50 | black_box(ctx.finish()); 51 | } 52 | 53 | fn sha256(c: &mut Criterion) { 54 | let mut group = c.benchmark_group("sha256"); 55 | for (size, size_name) in [(32, "32B"), (8192, "8KB"), (65536, "64KB")] { 56 | let input = vec![0u8; size]; 57 | group.throughput(Throughput::Bytes(size as u64)); 58 | 59 | group.bench_with_input(BenchmarkId::new("ring", size_name), &input, |b, input| { 60 | b.iter(|| test_ring_sha256(input)) 61 | }); 62 | group.bench_with_input( 63 | BenchmarkId::new("aws-lc-rs", size_name), 64 | &input, 65 | |b, input| b.iter(|| test_aws_sha256(input)), 66 | ); 67 | group.bench_with_input( 68 | BenchmarkId::new("rustcrypto", size_name), 69 | &input, 70 | |b, input| b.iter(|| test_rc_sha256(input)), 71 | ); 72 | group.bench_with_input( 73 | BenchmarkId::new("graviola", size_name), 74 | &input, 75 | |b, input| b.iter(|| test_graviola_sha256(input)), 76 | ); 77 | } 78 | } 79 | 80 | fn sha512(c: &mut Criterion) { 81 | let mut group = c.benchmark_group("sha512"); 82 | for (size, size_name) in [(32, "32B"), (8192, "8KB"), (65536, "64KB")] { 83 | let input = vec![0u8; size]; 84 | group.throughput(Throughput::Bytes(size as u64)); 85 | 86 | group.bench_with_input(BenchmarkId::new("ring", size_name), &input, |b, input| { 87 | b.iter(|| test_ring_sha512(input)) 88 | }); 89 | group.bench_with_input( 90 | BenchmarkId::new("aws-lc-rs", size_name), 91 | &input, 92 | |b, input| b.iter(|| test_aws_sha512(input)), 93 | ); 94 | group.bench_with_input( 95 | BenchmarkId::new("rustcrypto", size_name), 96 | &input, 97 | |b, input| b.iter(|| test_rc_sha512(input)), 98 | ); 99 | group.bench_with_input( 100 | BenchmarkId::new("graviola", size_name), 101 | &input, 102 | |b, input| b.iter(|| test_graviola_sha512(input)), 103 | ); 104 | } 105 | } 106 | 107 | criterion_group!(benches, sha256, sha512); 108 | criterion_main!(benches); 109 | -------------------------------------------------------------------------------- /graviola-bench/benches/x25519.rs: -------------------------------------------------------------------------------- 1 | mod criterion; 2 | use criterion::{Criterion, Throughput, black_box, criterion_group, criterion_main}; 3 | 4 | const PUBLIC_KEY: &[u8; 32] = b"\xe6\xdb\x68\x67\x58\x30\x30\xdb\x35\x94\xc1\xa4\x24\xb1\x5f\x7c\x72\x66\x24\xec\x26\xb3\x35\x3b\x10\xa9\x03\xa6\xd0\xab\x1c\x4c"; 5 | 6 | fn x25519(c: &mut Criterion) { 7 | let mut group = c.benchmark_group("x25519-ecdh"); 8 | group.throughput(Throughput::Elements(1)); 9 | 10 | #[cfg(feature = "__bench_openssl")] 11 | group.bench_function("openssl", |b| { 12 | b.iter(|| { 13 | use openssl::derive::Deriver; 14 | use openssl::pkey::{Id, PKey}; 15 | 16 | let priv_key = PKey::generate_x25519().unwrap(); 17 | black_box(priv_key.raw_public_key().unwrap()); 18 | 19 | let peer = PKey::public_key_from_raw_bytes(PUBLIC_KEY, Id::X25519).unwrap(); 20 | let mut deriver = Deriver::new(&priv_key).unwrap(); 21 | deriver.set_peer(&peer).unwrap(); 22 | let mut secret = [0u8; 32]; 23 | deriver.derive(&mut secret).unwrap(); 24 | black_box(secret); 25 | }); 26 | }); 27 | 28 | group.bench_function("ring", |b| { 29 | use ring::{agreement, rand}; 30 | let rng = rand::SystemRandom::new(); 31 | 32 | b.iter(|| { 33 | let our_private_key = 34 | agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng).unwrap(); 35 | black_box(our_private_key.compute_public_key().unwrap()); 36 | 37 | let peer_public_key = agreement::UnparsedPublicKey::new(&agreement::X25519, PUBLIC_KEY); 38 | 39 | agreement::agree_ephemeral(our_private_key, &peer_public_key, |key_material| { 40 | black_box(key_material); 41 | }) 42 | .unwrap(); 43 | }) 44 | }); 45 | 46 | group.bench_function("aws-lc-rs", |b| { 47 | use aws_lc_rs::{agreement, error, rand}; 48 | let rng = rand::SystemRandom::new(); 49 | 50 | b.iter(|| { 51 | let our_private_key = 52 | agreement::EphemeralPrivateKey::generate(&agreement::X25519, &rng).unwrap(); 53 | black_box(our_private_key.compute_public_key().unwrap()); 54 | 55 | let peer_public_key = agreement::UnparsedPublicKey::new(&agreement::X25519, PUBLIC_KEY); 56 | 57 | agreement::agree_ephemeral( 58 | our_private_key, 59 | &peer_public_key, 60 | error::Unspecified, 61 | |key_material| { 62 | black_box(key_material); 63 | Ok(()) 64 | }, 65 | ) 66 | .unwrap(); 67 | }) 68 | }); 69 | 70 | group.bench_function("dalek", |b| { 71 | b.iter(|| { 72 | let our_priv = x25519_dalek::EphemeralSecret::random_from_rng(rand_core::OsRng); 73 | let our_pub: x25519_dalek::PublicKey = (&our_priv).into(); 74 | black_box(our_pub); 75 | 76 | let their_pub = x25519_dalek::PublicKey::from(*PUBLIC_KEY); 77 | 78 | let shared_secret = our_priv.diffie_hellman(&their_pub); 79 | black_box(shared_secret.as_bytes()); 80 | }); 81 | }); 82 | 83 | group.bench_function("graviola", |b| { 84 | b.iter(|| { 85 | let our_private_key = 86 | graviola::key_agreement::x25519::PrivateKey::new_random().unwrap(); 87 | let our_public_key = our_private_key.public_key(); 88 | black_box(our_public_key); 89 | 90 | let peer = graviola::key_agreement::x25519::PublicKey::from_array(PUBLIC_KEY); 91 | let secret = our_private_key.diffie_hellman(&peer).unwrap(); 92 | black_box(secret); 93 | }) 94 | }); 95 | } 96 | 97 | criterion_group!(benches, x25519); 98 | criterion_main!(benches); 99 | -------------------------------------------------------------------------------- /graviola-bench/benches/xchacha20poly1305.rs: -------------------------------------------------------------------------------- 1 | mod criterion; 2 | use criterion::{BenchmarkId, Criterion, Throughput, criterion_group, criterion_main}; 3 | 4 | fn test_rc_chacha( 5 | key: &chacha20poly1305::XChaCha20Poly1305, 6 | nonce: &[u8; 24], 7 | aad: &[u8], 8 | plain: &[u8], 9 | ) { 10 | use chacha20poly1305::AeadInPlace; 11 | let mut ct = plain.to_vec(); 12 | let _tag = key 13 | .encrypt_in_place_detached(nonce.into(), aad, &mut ct) 14 | .unwrap(); 15 | } 16 | 17 | fn test_graviola_chacha( 18 | key: &graviola::aead::XChaCha20Poly1305, 19 | nonce: &[u8; 24], 20 | aad: &[u8], 21 | plain: &[u8], 22 | ) { 23 | let mut ct = plain.to_vec(); 24 | let mut tag = [0u8; 16]; 25 | key.encrypt(nonce, aad, &mut ct, &mut tag); 26 | } 27 | 28 | fn bench_chacha20poly1305(c: &mut Criterion) { 29 | let key = [0u8; 32]; 30 | let nonce = [0u8; 24]; 31 | let aad = [0u8; 32]; 32 | 33 | let mut group = c.benchmark_group("xchacha20poly1305"); 34 | for (size, size_name) in [(32, "32B"), (2048, "2KB"), (16384, "16KB")] { 35 | let input = vec![0u8; size]; 36 | group.throughput(Throughput::Bytes(size as u64)); 37 | 38 | group.bench_with_input( 39 | BenchmarkId::new("rustcrypto", size_name), 40 | &input, 41 | |b, input| { 42 | use chacha20poly1305::KeyInit; 43 | let key = chacha20poly1305::XChaCha20Poly1305::new_from_slice(&key).unwrap(); 44 | b.iter(|| test_rc_chacha(&key, &nonce, &aad, input)); 45 | }, 46 | ); 47 | group.bench_with_input( 48 | BenchmarkId::new("graviola", size_name), 49 | &input, 50 | |b, input| { 51 | let key = graviola::aead::XChaCha20Poly1305::new(key); 52 | b.iter(|| test_graviola_chacha(&key, &nonce, &aad, input)); 53 | }, 54 | ); 55 | } 56 | } 57 | 58 | criterion_group!(benches, bench_chacha20poly1305); 59 | criterion_main!(benches); 60 | -------------------------------------------------------------------------------- /graviola/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "graviola" 3 | version = "0.2.1" 4 | edition = "2021" 5 | repository = "https://github.com/ctz/graviola/" 6 | license = "Apache-2.0 OR ISC OR MIT-0" 7 | readme = "README.md" 8 | description = "graviola is a modern, fast cryptography library" 9 | categories = ["network-programming", "cryptography"] 10 | rust-version = "1.72" 11 | 12 | [features] 13 | default = [] 14 | 15 | [dependencies] 16 | cfg-if = "1" 17 | getrandom = "0.3" 18 | 19 | [dev-dependencies] 20 | aws-lc-rs = { version = "1.13", default-features = false, features = ["alloc", "prebuilt-nasm", "non-fips"] } 21 | hex = { version = "0.4", features = ["serde"] } 22 | proptest = "1.5.0" 23 | serde = { version = "1", features = ["derive"] } 24 | serde_json = "1" 25 | 26 | [target.'cfg(all(target_os = "linux", target_arch = "x86_64"))'.dev-dependencies] 27 | crabgrind = "=0.1.9" # compatible with valgrind package on GHA ubuntu-latest 28 | -------------------------------------------------------------------------------- /graviola/README.md: -------------------------------------------------------------------------------- 1 | ../README.md -------------------------------------------------------------------------------- /graviola/src/high/asn1/oid.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | #![allow(non_upper_case_globals, dead_code)] 5 | 6 | use super::asn1_oid; 7 | 8 | asn1_oid! { 9 | id_ecPublicKey OBJECT IDENTIFIER ::= { 10 | iso(1) member_body(2) us(840) 10045 keyType(2) 1 11 | } 12 | } 13 | 14 | asn1_oid! { 15 | id_prime256v1 OBJECT IDENTIFIER ::= { 16 | iso(1) member_body(2) us(840) 10045 curves(3) prime(1) 7 17 | } 18 | } 19 | 20 | asn1_oid! { 21 | secp384r1 OBJECT IDENTIFIER ::= { 22 | iso(1) identified_organization(3) certicom(132) curve(0) ansip384r1(34) 23 | } 24 | } 25 | 26 | asn1_oid! { 27 | rsaEncryption OBJECT IDENTIFIER ::= { 28 | iso(1) member_body(2) 29 | us(840) rsadsi(113549) pkcs(1) 1 rsaEncryption(1) 30 | } 31 | } 32 | 33 | asn1_oid! { 34 | id_sha256 OBJECT IDENTIFIER ::= { 35 | joint_iso_itu_t(2) country(16) us(840) organization(1) gov(101) 36 | csor(3) nistalgorithm(4) hashalgs(2) 1 37 | } 38 | } 39 | 40 | asn1_oid! { 41 | id_sha384 OBJECT IDENTIFIER ::= { 42 | joint_iso_itu_t(2) country(16) us(840) organization(1) gov(101) 43 | csor(3) nistalgorithm(4) hashalgs(2) 2 44 | } 45 | } 46 | 47 | asn1_oid! { 48 | id_sha512 OBJECT IDENTIFIER ::= { 49 | joint_iso_itu_t(2) country(16) us(840) organization(1) gov(101) 50 | csor(3) nistalgorithm(4) hashalgs(2) 3 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /graviola/src/high/asn1/testdata/nistp256-p8.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/asn1/testdata/nistp256-p8.bin -------------------------------------------------------------------------------- /graviola/src/high/asn1/testdata/nistp256-sec1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/asn1/testdata/nistp256-sec1.bin -------------------------------------------------------------------------------- /graviola/src/high/asn1/testdata/rsaprivatekey-1k.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/asn1/testdata/rsaprivatekey-1k.bin -------------------------------------------------------------------------------- /graviola/src/high/asn1/testdata/rsapublickey-1k.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/asn1/testdata/rsapublickey-1k.bin -------------------------------------------------------------------------------- /graviola/src/high/asn1/testdata/spki-ec-nistp256.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/asn1/testdata/spki-ec-nistp256.bin -------------------------------------------------------------------------------- /graviola/src/high/asn1/testdata/spki-rsa-2k.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/asn1/testdata/spki-rsa-2k.bin -------------------------------------------------------------------------------- /graviola/src/high/ecdsa/secp256r1.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/ecdsa/secp256r1.der -------------------------------------------------------------------------------- /graviola/src/high/ecdsa/secp256r1.pkcs8.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/ecdsa/secp256r1.pkcs8.der -------------------------------------------------------------------------------- /graviola/src/high/ecdsa/secp256r1.wrong-public-key.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/ecdsa/secp256r1.wrong-public-key.der -------------------------------------------------------------------------------- /graviola/src/high/ecdsa/secp256r1.wrong-version.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/ecdsa/secp256r1.wrong-version.der -------------------------------------------------------------------------------- /graviola/src/high/ecdsa/secp384r1.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/ecdsa/secp384r1.der -------------------------------------------------------------------------------- /graviola/src/high/ecdsa/secp384r1.pkcs8.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/ecdsa/secp384r1.pkcs8.der -------------------------------------------------------------------------------- /graviola/src/high/mod.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | #![deny(unsafe_code)] 5 | 6 | pub(super) mod asn1; 7 | pub(super) mod curve; 8 | pub(super) mod ecdsa; 9 | pub(super) mod hash; 10 | pub mod hmac; 11 | pub(super) mod hmac_drbg; 12 | pub(super) mod pkcs1; 13 | pub(super) mod pkcs8; 14 | pub(super) mod rsa; 15 | -------------------------------------------------------------------------------- /graviola/src/high/pkcs8.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use super::asn1::pkix; 5 | use super::asn1::{self, Integer, Type}; 6 | use crate::error::{Error, KeyFormatError}; 7 | 8 | /// Helper for decoding PKCS#8 key encodings. 9 | /// 10 | /// This decodes the given slice as a whole `PrivateKeyInfo`, and then: 11 | /// 12 | /// - ensures the version is 0, 13 | /// - ensures the key algorithm is `algorithm`, 14 | /// - ensures the parameters are `parameters`. 15 | /// 16 | /// Then returns the slice that covers the `privateKey` `OCTET STRING` body, 17 | /// that can be decoded by the caller as the correct asn1 type. 18 | pub(crate) fn decode_pkcs8<'a>( 19 | slice: &'a [u8], 20 | algorithm: &asn1::ObjectId, 21 | parameters: Option>, 22 | ) -> Result<&'a [u8], Error> { 23 | let pki = 24 | pkix::PrivateKeyInfo::parse(&mut asn1::Parser::new(slice)).map_err(Error::Asn1Error)?; 25 | 26 | if pki.version != Integer::new(&[0]) { 27 | return Err(KeyFormatError::UnsupportedPkcs8Version.into()); 28 | } 29 | 30 | if pki.privateKeyAlgorithm.algorithm != *algorithm { 31 | return Err(KeyFormatError::MismatchedPkcs8Algorithm.into()); 32 | } 33 | 34 | if pki.privateKeyAlgorithm.parameters != parameters { 35 | return Err(KeyFormatError::MismatchedPkcs8Parameters.into()); 36 | } 37 | 38 | Ok(pki.privateKey.into_octets()) 39 | } 40 | 41 | /// Helper for producing PKCS#8 key encodings. 42 | pub(crate) fn encode_pkcs8<'a>( 43 | private_key_encoding: &'_ [u8], 44 | algorithm: asn1::ObjectId, 45 | parameters: Option>, 46 | output: &'a mut [u8], 47 | ) -> Result<&'a [u8], Error> { 48 | let len = pkix::PrivateKeyInfo { 49 | version: Integer::new(&[0]), 50 | privateKeyAlgorithm: pkix::AlgorithmIdentifier { 51 | algorithm, 52 | parameters, 53 | }, 54 | privateKey: asn1::OctetString::new(private_key_encoding), 55 | } 56 | .encode(&mut asn1::Encoder::new(output)) 57 | .map_err(Error::Asn1Error)?; 58 | 59 | output.get(..len).ok_or(Error::WrongLength) 60 | } 61 | -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa2048.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa2048.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa2048.pkcs8.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa2048.pkcs8.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa3072.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa3072.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa3072.pkcs8.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa3072.pkcs8.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa4096.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa4096.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa4096.pkcs8.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa4096.pkcs8.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa6144.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa6144.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa6144.pkcs8.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa6144.pkcs8.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa8192.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa8192.der -------------------------------------------------------------------------------- /graviola/src/high/rsa/rsa8192.pkcs8.der: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/high/rsa/rsa8192.pkcs8.der -------------------------------------------------------------------------------- /graviola/src/low/aarch64/aes_gcm.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use crate::low::AesKey; 5 | use crate::low::ghash::Ghash; 6 | 7 | pub(crate) fn encrypt( 8 | key: &AesKey, 9 | ghash: &mut Ghash<'_>, 10 | initial_counter: &[u8; 16], 11 | aad: &[u8], 12 | cipher_inout: &mut [u8], 13 | ) { 14 | ghash.add(aad); 15 | key.ctr(initial_counter, cipher_inout); 16 | ghash.add(cipher_inout); 17 | } 18 | 19 | pub(crate) fn decrypt( 20 | key: &AesKey, 21 | ghash: &mut Ghash<'_>, 22 | initial_counter: &[u8; 16], 23 | aad: &[u8], 24 | cipher_inout: &mut [u8], 25 | ) { 26 | ghash.add(aad); 27 | ghash.add(cipher_inout); 28 | key.ctr(initial_counter, cipher_inout); 29 | } 30 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_bitsize.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Return size of bignum in bits 10 | // Input x[k]; output function return 11 | // 12 | // extern uint64_t bignum_bitsize(uint64_t k, const uint64_t *x); 13 | // 14 | // In the case of a zero bignum as input the result is 0 15 | // 16 | // In principle this has a precondition k < 2^58, but obviously that 17 | // is always true in practice because of address space limitations. 18 | // 19 | // Standard ARM ABI: X0 = k, X1 = x, returns X0 20 | // ---------------------------------------------------------------------------- 21 | 22 | macro_rules! k { 23 | () => { 24 | "x0" 25 | }; 26 | } 27 | macro_rules! x { 28 | () => { 29 | "x1" 30 | }; 31 | } 32 | macro_rules! i { 33 | () => { 34 | "x2" 35 | }; 36 | } 37 | macro_rules! w { 38 | () => { 39 | "x3" 40 | }; 41 | } 42 | macro_rules! a { 43 | () => { 44 | "x4" 45 | }; 46 | } 47 | macro_rules! j { 48 | () => { 49 | "x5" 50 | }; 51 | } 52 | 53 | /// Return size of bignum in bits 54 | /// 55 | /// Input x[k]; output function return 56 | /// 57 | /// In the case of a zero bignum as input the result is 0 58 | /// 59 | /// In principle this has a precondition k < 2^58, but obviously that 60 | /// is always true in practice because of address space limitations. 61 | pub(crate) fn bignum_bitsize(x: &[u64]) -> usize { 62 | let ret: u64; 63 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 64 | unsafe { 65 | core::arch::asm!( 66 | 67 | 68 | // If the bignum is zero-length, x0 is already the right answer of 0 69 | 70 | Q!(" cbz " k!() ", " Label!("bignum_bitsize_end", 2, After)), 71 | 72 | // Use w = a[i-1] to store nonzero words in a bottom-up sweep 73 | // Set the initial default to be as if we had a 11...11 word directly below 74 | 75 | Q!(" mov " i!() ", xzr"), 76 | Q!(" mov " w!() ", #-1"), 77 | Q!(" mov " j!() ", xzr"), 78 | Q!(Label!("bignum_bitsize_loop", 3) ":"), 79 | Q!(" ldr " a!() ", [" x!() ", " j!() ", lsl #3]"), 80 | Q!(" add " j!() ", " j!() ", #1"), 81 | Q!(" cmp " a!() ", #0"), 82 | Q!(" csel " i!() ", " j!() ", " i!() ", ne"), 83 | Q!(" csel " w!() ", " a!() ", " w!() ", ne"), 84 | Q!(" cmp " j!() ", " k!()), 85 | Q!(" bne " Label!("bignum_bitsize_loop", 3, Before)), 86 | 87 | // Now w = a[i-1] is the highest nonzero word, or in the zero case the 88 | // default of the "extra" 11...11 = a[0-1]. We now want 64* i - clz(w). 89 | // Note that this code does not rely on the behavior of the clz instruction 90 | // for zero inputs, though the ARM manual does in fact guarantee clz(0) = 64. 91 | 92 | Q!(" lsl " i!() ", " i!() ", #6"), 93 | Q!(" clz " a!() ", " w!()), 94 | Q!(" sub " "x0, " i!() ", " a!()), 95 | 96 | Q!(Label!("bignum_bitsize_end", 2) ":"), 97 | inout("x0") x.len() => ret, 98 | inout("x1") x.as_ptr() => _, 99 | // clobbers 100 | out("x2") _, 101 | out("x3") _, 102 | out("x4") _, 103 | out("x5") _, 104 | ) 105 | }; 106 | ret as usize 107 | } 108 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_copy_row_from_table_mux.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | /// Multiplex between NEON specialisations of `bignum_copy_row_from_table` 5 | #[inline] 6 | pub(crate) fn bignum_copy_row_from_table( 7 | z: &mut [u64], 8 | table: &[u64], 9 | height: u64, 10 | width: u64, 11 | index: u64, 12 | ) { 13 | match width { 14 | 32 => super::bignum_copy_row_from_table_32::bignum_copy_row_from_table_32( 15 | z, table, height, index, 16 | ), 17 | 16 => super::bignum_copy_row_from_table_16::bignum_copy_row_from_table_16( 18 | z, table, height, index, 19 | ), 20 | width if width % 8 == 0 => { 21 | super::bignum_copy_row_from_table_8n::bignum_copy_row_from_table_8n( 22 | z, table, height, width, index, 23 | ) 24 | } 25 | width => super::bignum_copy_row_from_table::bignum_copy_row_from_table( 26 | z, table, height, width, index, 27 | ), 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_ctz.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Count trailing zero bits 10 | // Input x[k]; output function return 11 | // 12 | // extern uint64_t bignum_ctz(uint64_t k, const uint64_t *x); 13 | // 14 | // 15 | // In the case of a zero bignum as input the result is 64 * k 16 | // 17 | // In principle this has a precondition k < 2^58, but obviously that 18 | // is always true in practice because of address space limitations 19 | // 20 | // Standard ARM ABI: X0 = k, X1 = x, returns X0 21 | // ---------------------------------------------------------------------------- 22 | 23 | macro_rules! k { 24 | () => { 25 | "x0" 26 | }; 27 | } 28 | macro_rules! x { 29 | () => { 30 | "x1" 31 | }; 32 | } 33 | macro_rules! i { 34 | () => { 35 | "x2" 36 | }; 37 | } 38 | macro_rules! w { 39 | () => { 40 | "x3" 41 | }; 42 | } 43 | macro_rules! a { 44 | () => { 45 | "x4" 46 | }; 47 | } 48 | 49 | /// Count trailing zero bits 50 | /// 51 | /// Input x[k]; output function return 52 | /// 53 | /// 54 | /// In the case of a zero bignum as input the result is 64 * k 55 | /// 56 | /// In principle this has a precondition k < 2^58, but obviously that 57 | /// is always true in practice because of address space limitations 58 | pub(crate) fn bignum_ctz(x: &[u64]) -> usize { 59 | let ret: u64; 60 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 61 | unsafe { 62 | core::arch::asm!( 63 | 64 | 65 | // If the bignum is zero-length, x0 is already the right answer of 0 66 | 67 | Q!(" cbz " k!() ", " Label!("bignum_ctz_end", 2, After)), 68 | 69 | // Use w = a[i] to store nonzero words in a top-down sweep 70 | // Set the initial default to be as if we had a 1 word directly above 71 | 72 | Q!(" mov " i!() ", " k!()), 73 | Q!(" mov " w!() ", #1"), 74 | 75 | Q!(Label!("bignum_ctz_loop", 3) ":"), 76 | Q!(" sub " k!() ", " k!() ", #1"), 77 | Q!(" ldr " a!() ", [" x!() ", " k!() ", lsl #3]"), 78 | Q!(" cmp " a!() ", #0"), 79 | Q!(" csel " i!() ", " k!() ", " i!() ", ne"), 80 | Q!(" csel " w!() ", " a!() ", " w!() ", ne"), 81 | Q!(" cbnz " k!() ", " Label!("bignum_ctz_loop", 3, Before)), 82 | 83 | // Now w = a[i] is the lowest nonzero word, or in the zero case the 84 | // default of the "extra" 1 = a[k]. We now want 64*i + ctz(w). 85 | // 86 | // ARM doesn't have a direct word ctz instruction, so we emulate it via 87 | // ctz(w) = 64 - clz(~w & (w-1)). This is depending, for cases of the form 88 | // ctz(....1), on the behavior clz(0) = 64, which is guaranteed according 89 | // to the ARM manual. 90 | 91 | Q!(" mvn " a!() ", " w!()), 92 | Q!(" sub " w!() ", " w!() ", #1"), 93 | Q!(" add " i!() ", " i!() ", #1"), 94 | Q!(" and " w!() ", " w!() ", " a!()), 95 | Q!(" lsl " i!() ", " i!() ", #6"), 96 | Q!(" clz " a!() ", " w!()), 97 | Q!(" sub " "x0, " i!() ", " a!()), 98 | 99 | Q!(Label!("bignum_ctz_end", 2) ":"), 100 | inout("x0") x.len() => ret, 101 | inout("x1") x.as_ptr() => _, 102 | // clobbers 103 | out("x2") _, 104 | out("x3") _, 105 | out("x4") _, 106 | ) 107 | }; 108 | ret as usize 109 | } 110 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_digitsize.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Return size of bignum in digits (64-bit word) 10 | // Input x[k]; output function return 11 | // 12 | // extern uint64_t bignum_digitsize(uint64_t k, const uint64_t *x); 13 | // 14 | // In the case of a zero bignum as input the result is 0 15 | // 16 | // Standard ARM ABI: X0 = k, X1 = x, returns X0 17 | // ---------------------------------------------------------------------------- 18 | 19 | macro_rules! k { 20 | () => { 21 | "x0" 22 | }; 23 | } 24 | macro_rules! x { 25 | () => { 26 | "x1" 27 | }; 28 | } 29 | macro_rules! i { 30 | () => { 31 | "x2" 32 | }; 33 | } 34 | macro_rules! a { 35 | () => { 36 | "x3" 37 | }; 38 | } 39 | macro_rules! j { 40 | () => { 41 | "x4" 42 | }; 43 | } 44 | 45 | /// Return size of bignum in digits (64-bit word) 46 | /// 47 | /// Input x[k]; output function return 48 | /// 49 | /// In the case of a zero bignum as input the result is 0 50 | pub(crate) fn bignum_digitsize(z: &[u64]) -> usize { 51 | let ret: u64; 52 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 53 | unsafe { 54 | core::arch::asm!( 55 | 56 | 57 | // If the bignum is zero-length, x0 is already the right answer of 0 58 | 59 | Q!(" cbz " k!() ", " Label!("bignum_digitsize_end", 2, After)), 60 | 61 | // Run over the words j = 0..i-1, and set i := j + 1 when hitting nonzero a[j] 62 | 63 | Q!(" mov " i!() ", xzr"), 64 | Q!(" mov " j!() ", xzr"), 65 | Q!(Label!("bignum_digitsize_loop", 3) ":"), 66 | Q!(" ldr " a!() ", [" x!() ", " j!() ", lsl #3]"), 67 | Q!(" add " j!() ", " j!() ", #1"), 68 | Q!(" cmp " a!() ", #0"), 69 | Q!(" csel " i!() ", " j!() ", " i!() ", ne"), 70 | Q!(" cmp " j!() ", " k!()), 71 | Q!(" bne " Label!("bignum_digitsize_loop", 3, Before)), 72 | 73 | Q!(" mov " "x0, " i!()), 74 | Q!(Label!("bignum_digitsize_end", 2) ":"), 75 | inout("x0") z.len() => ret, 76 | inout("x1") z.as_ptr() => _, 77 | // clobbers 78 | out("x2") _, 79 | out("x3") _, 80 | out("x4") _, 81 | ) 82 | }; 83 | ret as usize 84 | } 85 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_eq.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Test bignums for equality, x = y 10 | // Inputs x[m], y[n]; output function return 11 | // 12 | // extern uint64_t bignum_eq(uint64_t m, const uint64_t *x, uint64_t n, 13 | // const uint64_t *y); 14 | // 15 | // Standard ARM ABI: X0 = m, X1 = x, X2 = n, X3 = y, returns X0 16 | // ---------------------------------------------------------------------------- 17 | 18 | macro_rules! m { 19 | () => { 20 | "x0" 21 | }; 22 | } 23 | macro_rules! x { 24 | () => { 25 | "x1" 26 | }; 27 | } 28 | macro_rules! n { 29 | () => { 30 | "x2" 31 | }; 32 | } 33 | macro_rules! y { 34 | () => { 35 | "x3" 36 | }; 37 | } 38 | macro_rules! a { 39 | () => { 40 | "x4" 41 | }; 42 | } 43 | macro_rules! c { 44 | () => { 45 | "x5" 46 | }; 47 | } 48 | // We can re-use n for this, not needed when d appears 49 | macro_rules! d { 50 | () => { 51 | "x2" 52 | }; 53 | } 54 | 55 | /// Test bignums for equality, x = y 56 | /// 57 | /// Inputs x[m], y[n]; output function return 58 | pub(crate) fn bignum_eq(x: &[u64], y: &[u64]) -> bool { 59 | let ret: u64; 60 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 61 | unsafe { 62 | core::arch::asm!( 63 | 64 | 65 | // Initialize the accumulated OR of differences to zero 66 | 67 | Q!(" mov " c!() ", xzr"), 68 | 69 | // If m >= n jump into the m > n loop at the final equality test 70 | // This will drop through for m = n 71 | 72 | Q!(" cmp " m!() ", " n!()), 73 | Q!(" bcs " Label!("bignum_eq_mtest", 2, After)), 74 | 75 | // Toploop for the case n > m 76 | 77 | Q!(Label!("bignum_eq_nloop", 3) ":"), 78 | Q!(" sub " n!() ", " n!() ", #1"), 79 | Q!(" ldr " a!() ", [" y!() ", " n!() ", lsl #3]"), 80 | Q!(" orr " c!() ", " c!() ", " a!()), 81 | Q!(" cmp " m!() ", " n!()), 82 | Q!(" bne " Label!("bignum_eq_nloop", 3, Before)), 83 | Q!(" b " Label!("bignum_eq_mmain", 4, After)), 84 | 85 | // Toploop for the case m > n (or n = m which enters at "mtest") 86 | 87 | Q!(Label!("bignum_eq_mloop", 5) ":"), 88 | Q!(" sub " m!() ", " m!() ", #1"), 89 | Q!(" ldr " a!() ", [" x!() ", " m!() ", lsl #3]"), 90 | Q!(" orr " c!() ", " c!() ", " a!()), 91 | Q!(" cmp " m!() ", " n!()), 92 | Q!(Label!("bignum_eq_mtest", 2) ":"), 93 | Q!(" bne " Label!("bignum_eq_mloop", 5, Before)), 94 | 95 | // Combined main loop for the min(m,n) lower words 96 | 97 | Q!(Label!("bignum_eq_mmain", 4) ":"), 98 | Q!(" cbz " m!() ", " Label!("bignum_eq_end", 6, After)), 99 | 100 | Q!(Label!("bignum_eq_loop", 7) ":"), 101 | Q!(" sub " m!() ", " m!() ", #1"), 102 | Q!(" ldr " a!() ", [" x!() ", " m!() ", lsl #3]"), 103 | Q!(" ldr " d!() ", [" y!() ", " m!() ", lsl #3]"), 104 | Q!(" eor " a!() ", " a!() ", " d!()), 105 | Q!(" orr " c!() ", " c!() ", " a!()), 106 | Q!(" cbnz " m!() ", " Label!("bignum_eq_loop", 7, Before)), 107 | 108 | Q!(Label!("bignum_eq_end", 6) ":"), 109 | Q!(" cmp " c!() ", xzr"), 110 | Q!(" cset " "x0, eq"), 111 | inout("x0") x.len() => ret, 112 | inout("x1") x.as_ptr() => _, 113 | inout("x2") y.len() => _, 114 | inout("x3") y.as_ptr() => _, 115 | // clobbers 116 | out("x4") _, 117 | out("x5") _, 118 | ) 119 | }; 120 | ret > 0 121 | } 122 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_mod_n256.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Reduce modulo group order, z := x mod n_256 10 | // Input x[4]; output z[4] 11 | // 12 | // extern void bignum_mod_n256_4(uint64_t z[static 4], const uint64_t x[static 4]); 13 | // 14 | // Reduction is modulo the group order of the NIST curve P-256. 15 | // 16 | // Standard ARM ABI: X0 = z, X1 = x 17 | // ---------------------------------------------------------------------------- 18 | 19 | macro_rules! z { 20 | () => { 21 | "x0" 22 | }; 23 | } 24 | macro_rules! x { 25 | () => { 26 | "x1" 27 | }; 28 | } 29 | 30 | macro_rules! n0 { 31 | () => { 32 | "x2" 33 | }; 34 | } 35 | macro_rules! n1 { 36 | () => { 37 | "x3" 38 | }; 39 | } 40 | macro_rules! n2 { 41 | () => { 42 | "x4" 43 | }; 44 | } 45 | macro_rules! n3 { 46 | () => { 47 | "x5" 48 | }; 49 | } 50 | 51 | macro_rules! d0 { 52 | () => { 53 | "x6" 54 | }; 55 | } 56 | macro_rules! d1 { 57 | () => { 58 | "x7" 59 | }; 60 | } 61 | macro_rules! d2 { 62 | () => { 63 | "x8" 64 | }; 65 | } 66 | macro_rules! d3 { 67 | () => { 68 | "x9" 69 | }; 70 | } 71 | 72 | // Loading large constants 73 | 74 | macro_rules! movbig { 75 | ($nn:expr, $n3:expr, $n2:expr, $n1:expr, $n0:expr) => { Q!( 76 | "movz " $nn ", " $n0 ";\n" 77 | "movk " $nn ", " $n1 ", lsl #16;\n" 78 | "movk " $nn ", " $n2 ", lsl #32;\n" 79 | "movk " $nn ", " $n3 ", lsl #48" 80 | )} 81 | } 82 | 83 | /// Reduce modulo group order, z := x mod n_256 84 | /// 85 | /// Input x[4]; output z[4] 86 | /// 87 | /// Reduction is modulo the group order of the NIST curve P-256. 88 | pub(crate) fn bignum_mod_n256(z: &mut [u64; 4], x: &[u64; 4]) { 89 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 90 | unsafe { 91 | core::arch::asm!( 92 | 93 | 94 | // Load the complicated three words of n_256, the other being all 1s 95 | 96 | movbig!(n0!(), "#0xf3b9", "#0xcac2", "#0xfc63", "#0x2551"), 97 | movbig!(n1!(), "#0xbce6", "#0xfaad", "#0xa717", "#0x9e84"), 98 | Q!(" mov " n3!() ", #0xffffffff00000000"), 99 | 100 | // Load the input number 101 | 102 | Q!(" ldp " d0!() ", " d1!() ", [" x!() "]"), 103 | Q!(" ldp " d2!() ", " d3!() ", [" x!() ", #16]"), 104 | 105 | // Do the subtraction. Since word 2 of n_256 is all 1s, that can be 106 | // done by adding zero with carry, thanks to the inverted carry. 107 | 108 | Q!(" subs " n0!() ", " d0!() ", " n0!()), 109 | Q!(" sbcs " n1!() ", " d1!() ", " n1!()), 110 | Q!(" adcs " n2!() ", " d2!() ", xzr"), 111 | Q!(" sbcs " n3!() ", " d3!() ", " n3!()), 112 | 113 | // Now if the carry is *clear* (inversion at work) the subtraction carried 114 | // and hence we should have done nothing, so we reset each n_i = d_i 115 | 116 | Q!(" csel " n0!() ", " d0!() ", " n0!() ", cc"), 117 | Q!(" csel " n1!() ", " d1!() ", " n1!() ", cc"), 118 | Q!(" csel " n2!() ", " d2!() ", " n2!() ", cc"), 119 | Q!(" csel " n3!() ", " d3!() ", " n3!() ", cc"), 120 | 121 | // Store the end result 122 | 123 | Q!(" stp " n0!() ", " n1!() ", [" z!() "]"), 124 | Q!(" stp " n2!() ", " n3!() ", [" z!() ", #16]"), 125 | 126 | inout("x0") z.as_mut_ptr() => _, 127 | inout("x1") x.as_ptr() => _, 128 | // clobbers 129 | out("x2") _, 130 | out("x3") _, 131 | out("x4") _, 132 | out("x5") _, 133 | out("x6") _, 134 | out("x7") _, 135 | out("x8") _, 136 | out("x9") _, 137 | ) 138 | }; 139 | } 140 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_modsub.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Subtract modulo m, z := (x - y) mod m, assuming x and y reduced 10 | // Inputs x[k], y[k], m[k]; output z[k] 11 | // 12 | // extern void bignum_modsub(uint64_t k, uint64_t *z, const uint64_t *x, 13 | // const uint64_t *y, const uint64_t *m); 14 | // 15 | // Standard ARM ABI: X0 = k, X1 = z, X2 = x, X3 = y, X4 = m 16 | // ---------------------------------------------------------------------------- 17 | 18 | macro_rules! k { 19 | () => { 20 | "x0" 21 | }; 22 | } 23 | macro_rules! z { 24 | () => { 25 | "x1" 26 | }; 27 | } 28 | macro_rules! x { 29 | () => { 30 | "x2" 31 | }; 32 | } 33 | macro_rules! y { 34 | () => { 35 | "x3" 36 | }; 37 | } 38 | macro_rules! m { 39 | () => { 40 | "x4" 41 | }; 42 | } 43 | macro_rules! i { 44 | () => { 45 | "x5" 46 | }; 47 | } 48 | macro_rules! j { 49 | () => { 50 | "x6" 51 | }; 52 | } 53 | macro_rules! a { 54 | () => { 55 | "x7" 56 | }; 57 | } 58 | macro_rules! b { 59 | () => { 60 | "x8" 61 | }; 62 | } 63 | macro_rules! c { 64 | () => { 65 | "x9" 66 | }; 67 | } 68 | 69 | /// Subtract modulo m, z := (x - y) mod m, assuming x and y reduced 70 | /// 71 | /// Inputs x[k], y[k], m[k]; output z[k] 72 | pub(crate) fn bignum_modsub(z: &mut [u64], x: &[u64], y: &[u64], m: &[u64]) { 73 | debug_assert!(z.len() == x.len()); 74 | debug_assert!(z.len() == y.len()); 75 | debug_assert!(z.len() == m.len()); 76 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 77 | unsafe { 78 | core::arch::asm!( 79 | 80 | 81 | Q!(" adds " j!() ", " k!() ", xzr"), 82 | Q!(" beq " Label!("bignum_modsub_end", 2, After)), 83 | Q!(" subs " i!() ", xzr, xzr"), 84 | 85 | // Subtract z := x - y and record a mask for the carry x - y < 0 86 | 87 | Q!(Label!("bignum_modsub_subloop", 3) ":"), 88 | Q!(" ldr " a!() ", [" x!() ", " i!() "]"), 89 | Q!(" ldr " b!() ", [" y!() ", " i!() "]"), 90 | Q!(" sbcs " a!() ", " a!() ", " b!()), 91 | Q!(" str " a!() ", [" z!() ", " i!() "]"), 92 | Q!(" add " i!() ", " i!() ", #8"), 93 | Q!(" sub " j!() ", " j!() ", #1"), 94 | Q!(" cbnz " j!() ", " Label!("bignum_modsub_subloop", 3, Before)), 95 | Q!(" csetm " c!() ", cc"), 96 | 97 | // Now do a masked addition z := z + [c] * m 98 | 99 | Q!(" mov " j!() ", " k!()), 100 | Q!(" adds " i!() ", xzr, xzr"), 101 | Q!(Label!("bignum_modsub_addloop", 4) ":"), 102 | Q!(" ldr " a!() ", [" z!() ", " i!() "]"), 103 | Q!(" ldr " b!() ", [" m!() ", " i!() "]"), 104 | Q!(" and " b!() ", " b!() ", " c!()), 105 | Q!(" adcs " a!() ", " a!() ", " b!()), 106 | Q!(" str " a!() ", [" z!() ", " i!() "]"), 107 | Q!(" add " i!() ", " i!() ", #8"), 108 | Q!(" sub " j!() ", " j!() ", #1"), 109 | Q!(" cbnz " j!() ", " Label!("bignum_modsub_addloop", 4, Before)), 110 | 111 | Q!(Label!("bignum_modsub_end", 2) ":"), 112 | inout("x0") z.len() => _, 113 | inout("x1") z.as_mut_ptr() => _, 114 | inout("x2") x.as_ptr() => _, 115 | inout("x3") y.as_ptr() => _, 116 | inout("x4") m.as_ptr() => _, 117 | // clobbers 118 | out("x5") _, 119 | out("x6") _, 120 | out("x7") _, 121 | out("x8") _, 122 | out("x9") _, 123 | ) 124 | }; 125 | } 126 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_mux.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Multiplex/select z := x (if p nonzero) or z := y (if p zero) 10 | // Inputs p, x[k], y[k]; output z[k] 11 | // 12 | // extern void bignum_mux(uint64_t p, uint64_t k, uint64_t *z, const uint64_t *x, 13 | // const uint64_t *y); 14 | // 15 | // It is assumed that all numbers x, y and z have the same size k digits. 16 | // 17 | // Standard ARM ABI: X0 = p, X1 = k, X2 = z, X3 = x, X4 = y 18 | // ---------------------------------------------------------------------------- 19 | 20 | macro_rules! b { 21 | () => { 22 | "x0" 23 | }; 24 | } 25 | macro_rules! k { 26 | () => { 27 | "x1" 28 | }; 29 | } 30 | macro_rules! z { 31 | () => { 32 | "x2" 33 | }; 34 | } 35 | macro_rules! x { 36 | () => { 37 | "x3" 38 | }; 39 | } 40 | macro_rules! y { 41 | () => { 42 | "x4" 43 | }; 44 | } 45 | macro_rules! a { 46 | () => { 47 | "x5" 48 | }; 49 | } 50 | 51 | /// Multiplex/select z := x (if p nonzero) or z := y (if p zero) 52 | /// 53 | /// Inputs p, x[k], y[k]; output z[k] 54 | /// 55 | /// It is assumed that all numbers x, y and z have the same size k digits. 56 | pub(crate) fn bignum_mux(p: u64, z: &mut [u64], x_if_p: &[u64], y_if_not_p: &[u64]) { 57 | debug_assert!(z.len() == x_if_p.len()); 58 | debug_assert!(z.len() == y_if_not_p.len()); 59 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 60 | unsafe { 61 | core::arch::asm!( 62 | 63 | 64 | Q!(" cbz " k!() ", " Label!("bignum_mux_end", 2, After)), 65 | Q!(" cmp " b!() ", #0"), 66 | 67 | // We've set cc's from b once and for all and can now re-use "b" as a temporary 68 | 69 | Q!(Label!("bignum_mux_loop", 3) ":"), 70 | Q!(" sub " k!() ", " k!() ", #1"), 71 | Q!(" ldr " a!() ", [" x!() ", " k!() ", lsl #3]"), 72 | Q!(" ldr " b!() ", [" y!() ", " k!() ", lsl #3]"), 73 | Q!(" csel " a!() ", " a!() ", " b!() ", ne"), 74 | Q!(" str " a!() ", [" z!() ", " k!() ", lsl #3]"), 75 | Q!(" cbnz " k!() ", " Label!("bignum_mux_loop", 3, Before)), 76 | 77 | Q!(Label!("bignum_mux_end", 2) ":"), 78 | inout("x0") p => _, 79 | inout("x1") z.len() => _, 80 | inout("x2") z.as_mut_ptr() => _, 81 | inout("x3") x_if_p.as_ptr() => _, 82 | inout("x4") y_if_not_p.as_ptr() => _, 83 | // clobbers 84 | out("x5") _, 85 | ) 86 | }; 87 | } 88 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_neg_p256.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Negate modulo p_256, z := (-x) mod p_256, assuming x reduced 10 | // Input x[4]; output z[4] 11 | // 12 | // extern void bignum_neg_p256(uint64_t z[static 4], const uint64_t x[static 4]); 13 | // 14 | // Standard ARM ABI: X0 = z, X1 = x 15 | // ---------------------------------------------------------------------------- 16 | 17 | macro_rules! z { 18 | () => { 19 | "x0" 20 | }; 21 | } 22 | macro_rules! x { 23 | () => { 24 | "x1" 25 | }; 26 | } 27 | 28 | macro_rules! p { 29 | () => { 30 | "x2" 31 | }; 32 | } 33 | macro_rules! t { 34 | () => { 35 | "x3" 36 | }; 37 | } 38 | 39 | macro_rules! d0 { 40 | () => { 41 | "x4" 42 | }; 43 | } 44 | macro_rules! d1 { 45 | () => { 46 | "x5" 47 | }; 48 | } 49 | macro_rules! d2 { 50 | () => { 51 | "x6" 52 | }; 53 | } 54 | macro_rules! d3 { 55 | () => { 56 | "x7" 57 | }; 58 | } 59 | 60 | /// Negate modulo p_256, z := (-x) mod p_256, assuming x reduced 61 | /// 62 | /// Input x[4]; output z[4] 63 | pub(crate) fn bignum_neg_p256(z: &mut [u64; 4], x: &[u64; 4]) { 64 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 65 | unsafe { 66 | core::arch::asm!( 67 | 68 | 69 | // Load the 4 digits of x 70 | 71 | Q!(" ldp " d0!() ", " d1!() ", [" x!() "]"), 72 | Q!(" ldp " d2!() ", " d3!() ", [" x!() ", #16]"), 73 | 74 | // Set a bitmask p for the input being nonzero, so that we avoid doing 75 | // -0 = p_256 and hence maintain strict modular reduction 76 | 77 | Q!(" orr " t!() ", " d0!() ", " d1!()), 78 | Q!(" orr " p!() ", " d2!() ", " d3!()), 79 | Q!(" orr " p!() ", " p!() ", " t!()), 80 | Q!(" cmp " p!() ", #0"), 81 | Q!(" csetm " p!() ", ne"), 82 | 83 | // Mask the nontrivial words of p_256 = [n3;0;n1;-1] and subtract 84 | 85 | Q!(" subs " d0!() ", " p!() ", " d0!()), 86 | Q!(" and " t!() ", " p!() ", #0x00000000ffffffff"), 87 | Q!(" sbcs " d1!() ", " t!() ", " d1!()), 88 | Q!(" sbcs " d2!() ", xzr, " d2!()), 89 | Q!(" and " t!() ", " p!() ", #0xffffffff00000001"), 90 | Q!(" sbc " d3!() ", " t!() ", " d3!()), 91 | 92 | // Write back the result 93 | 94 | Q!(" stp " d0!() ", " d1!() ", [" z!() "]"), 95 | Q!(" stp " d2!() ", " d3!() ", [" z!() ", #16]"), 96 | 97 | // Return 98 | 99 | inout("x0") z.as_mut_ptr() => _, 100 | inout("x1") x.as_ptr() => _, 101 | // clobbers 102 | out("x2") _, 103 | out("x3") _, 104 | out("x4") _, 105 | out("x5") _, 106 | out("x6") _, 107 | out("x7") _, 108 | ) 109 | }; 110 | } 111 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_neg_p384.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Negate modulo p_384, z := (-x) mod p_384, assuming x reduced 10 | // Input x[6]; output z[6] 11 | // 12 | // extern void bignum_neg_p384(uint64_t z[static 6], const uint64_t x[static 6]); 13 | // 14 | // Standard ARM ABI: X0 = z, X1 = x 15 | // ---------------------------------------------------------------------------- 16 | 17 | macro_rules! z { 18 | () => { 19 | "x0" 20 | }; 21 | } 22 | macro_rules! x { 23 | () => { 24 | "x1" 25 | }; 26 | } 27 | 28 | macro_rules! p { 29 | () => { 30 | "x2" 31 | }; 32 | } 33 | macro_rules! t { 34 | () => { 35 | "x3" 36 | }; 37 | } 38 | 39 | macro_rules! d0 { 40 | () => { 41 | "x4" 42 | }; 43 | } 44 | macro_rules! d1 { 45 | () => { 46 | "x5" 47 | }; 48 | } 49 | macro_rules! d2 { 50 | () => { 51 | "x6" 52 | }; 53 | } 54 | macro_rules! d3 { 55 | () => { 56 | "x7" 57 | }; 58 | } 59 | macro_rules! d4 { 60 | () => { 61 | "x8" 62 | }; 63 | } 64 | macro_rules! d5 { 65 | () => { 66 | "x9" 67 | }; 68 | } 69 | 70 | /// Negate modulo p_384, z := (-x) mod p_384, assuming x reduced 71 | /// 72 | /// Input x[6]; output z[6] 73 | pub(crate) fn bignum_neg_p384(z: &mut [u64; 6], x: &[u64; 6]) { 74 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 75 | unsafe { 76 | core::arch::asm!( 77 | 78 | 79 | // Load the 6 digits of x 80 | 81 | Q!(" ldp " d0!() ", " d1!() ", [" x!() "]"), 82 | Q!(" ldp " d2!() ", " d3!() ", [" x!() ", #16]"), 83 | Q!(" ldp " d4!() ", " d5!() ", [" x!() ", #32]"), 84 | 85 | // Set a bitmask p for the input being nonzero, so that we avoid doing 86 | // -0 = p_384 and hence maintain strict modular reduction 87 | 88 | Q!(" orr " p!() ", " d0!() ", " d1!()), 89 | Q!(" orr " t!() ", " d2!() ", " d3!()), 90 | Q!(" orr " p!() ", " p!() ", " t!()), 91 | Q!(" orr " t!() ", " d4!() ", " d5!()), 92 | Q!(" orr " p!() ", " p!() ", " t!()), 93 | Q!(" cmp " p!() ", #0"), 94 | Q!(" csetm " p!() ", ne"), 95 | 96 | // Mask the complicated lower three words of p_384 = [-1;-1;-1;n2;n1;n0] 97 | // and subtract, using mask itself for upper digits 98 | 99 | Q!(" and " t!() ", " p!() ", #0x00000000ffffffff"), 100 | Q!(" subs " d0!() ", " t!() ", " d0!()), 101 | Q!(" and " t!() ", " p!() ", #0xffffffff00000000"), 102 | Q!(" sbcs " d1!() ", " t!() ", " d1!()), 103 | Q!(" and " t!() ", " p!() ", #0xfffffffffffffffe"), 104 | Q!(" sbcs " d2!() ", " t!() ", " d2!()), 105 | Q!(" sbcs " d3!() ", " p!() ", " d3!()), 106 | Q!(" sbcs " d4!() ", " p!() ", " d4!()), 107 | Q!(" sbc " d5!() ", " p!() ", " d5!()), 108 | 109 | // Write back the result 110 | 111 | Q!(" stp " d0!() ", " d1!() ", [" z!() "]"), 112 | Q!(" stp " d2!() ", " d3!() ", [" z!() ", #16]"), 113 | Q!(" stp " d4!() ", " d5!() ", [" z!() ", #32]"), 114 | 115 | // Return 116 | 117 | inout("x0") z.as_mut_ptr() => _, 118 | inout("x1") x.as_ptr() => _, 119 | // clobbers 120 | out("x2") _, 121 | out("x3") _, 122 | out("x4") _, 123 | out("x5") _, 124 | out("x6") _, 125 | out("x7") _, 126 | out("x8") _, 127 | out("x9") _, 128 | ) 129 | }; 130 | } 131 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_optsub.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Optionally subtract, z := x - y (if p nonzero) or z := x (if p zero) 10 | // Inputs x[k], p, y[k]; outputs function return (carry-out) and z[k] 11 | // 12 | // extern uint64_t bignum_optsub(uint64_t k, uint64_t *z, const uint64_t *x, 13 | // uint64_t p, const uint64_t *y); 14 | // 15 | // It is assumed that all numbers x, y and z have the same size k digits. 16 | // Returns carry-out as per usual subtraction, always 0 if p was zero. 17 | // 18 | // Standard ARM ABI: X0 = k, X1 = z, X2 = x, X3 = p, X4 = y, returns X0 19 | // ---------------------------------------------------------------------------- 20 | 21 | macro_rules! k { 22 | () => { 23 | "x0" 24 | }; 25 | } 26 | macro_rules! z { 27 | () => { 28 | "x1" 29 | }; 30 | } 31 | macro_rules! x { 32 | () => { 33 | "x2" 34 | }; 35 | } 36 | macro_rules! p { 37 | () => { 38 | "x3" 39 | }; 40 | } 41 | macro_rules! m { 42 | () => { 43 | "x3" 44 | }; 45 | } 46 | macro_rules! y { 47 | () => { 48 | "x4" 49 | }; 50 | } 51 | macro_rules! a { 52 | () => { 53 | "x5" 54 | }; 55 | } 56 | macro_rules! b { 57 | () => { 58 | "x6" 59 | }; 60 | } 61 | macro_rules! i { 62 | () => { 63 | "x7" 64 | }; 65 | } 66 | 67 | /// Optionally subtract, z := x - y (if p nonzero) or z := x (if p zero) 68 | /// 69 | /// Inputs x[k], p, y[k]; outputs function return (carry-out) and z[k] 70 | /// 71 | /// It is assumed that all numbers x, y and z have the same size k digits. 72 | /// Returns carry-out as per usual subtraction, always 0 if p was zero. 73 | pub(crate) fn bignum_optsub(z: &mut [u64], x: &[u64], y: &[u64], p: u64) { 74 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 75 | unsafe { 76 | core::arch::asm!( 77 | 78 | 79 | // if k = 0 do nothing. This is also the right top carry in X0 80 | 81 | Q!(" cbz " k!() ", " Label!("bignum_optsub_end", 2, After)), 82 | 83 | // Convert p into a strict bitmask (same register in fact) 84 | 85 | Q!(" cmp " p!() ", xzr"), 86 | Q!(" csetm " m!() ", ne"), 87 | 88 | // Set i = 0 *and* make sure initial ~CF = 0 89 | 90 | Q!(" subs " i!() ", xzr, xzr"), 91 | 92 | // Main loop 93 | 94 | Q!(Label!("bignum_optsub_loop", 3) ":"), 95 | Q!(" ldr " a!() ", [" x!() ", " i!() "]"), 96 | Q!(" ldr " b!() ", [" y!() ", " i!() "]"), 97 | Q!(" and " b!() ", " b!() ", " m!()), 98 | Q!(" sbcs " a!() ", " a!() ", " b!()), 99 | Q!(" str " a!() ", [" z!() ", " i!() "]"), 100 | Q!(" add " i!() ", " i!() ", #8"), 101 | Q!(" sub " k!() ", " k!() ", #1"), 102 | Q!(" cbnz " k!() ", " Label!("bignum_optsub_loop", 3, Before)), 103 | 104 | // Return (non-inverted) carry flag 105 | 106 | Q!(" cset " "x0, cc"), 107 | 108 | Q!(Label!("bignum_optsub_end", 2) ":"), 109 | inout("x0") z.len() => _, 110 | inout("x1") z.as_mut_ptr() => _, 111 | inout("x2") x.as_ptr() => _, 112 | inout("x3") p => _, 113 | inout("x4") y.as_ptr() => _, 114 | // clobbers 115 | out("x5") _, 116 | out("x6") _, 117 | out("x7") _, 118 | ) 119 | }; 120 | } 121 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/bignum_point_select_p384.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use core::arch::aarch64::*; 5 | use core::mem; 6 | 7 | /// Viewing table as rows of 18 words width, copy the 18 words at 8 | /// table[idx - 1] into z. If `idx` is zero or larger than `height`, 9 | /// `z` is set to zero (ie, a jacobian point at infinity). 10 | pub(crate) fn bignum_jac_point_select_p384(z: &mut [u64; 18], table: &[u64], index: u8) { 11 | // SAFETY: crate requires `neon` cpu feature 12 | unsafe { _select_jac_p384(z, table, index) } 13 | } 14 | 15 | #[target_feature(enable = "neon")] 16 | unsafe fn _select_jac_p384(z: &mut [u64; 18], table: &[u64], index: u8) { 17 | // SAFETY: intrinsics. see [crate::low::inline_assembly_safety#safety-of-intrinsics] for safety info. 18 | unsafe { 19 | let mut acc0: uint32x4_t = mem::transmute(0u128); 20 | let mut acc1 = acc0; 21 | let mut acc2 = acc0; 22 | let mut acc3 = acc0; 23 | let mut acc4 = acc0; 24 | let mut acc5 = acc0; 25 | let mut acc6 = acc0; 26 | let mut acc7 = acc0; 27 | let mut acc8 = acc0; 28 | 29 | let desired_index = vdupq_n_u32(index as u32); 30 | let mut index = vdupq_n_u32(1); 31 | let ones = index; 32 | 33 | for point in table.chunks_exact(18) { 34 | let row0 = vld1q_u32(point.as_ptr().add(0).cast()); 35 | let row1 = vld1q_u32(point.as_ptr().add(2).cast()); 36 | let row2 = vld1q_u32(point.as_ptr().add(4).cast()); 37 | let row3 = vld1q_u32(point.as_ptr().add(6).cast()); 38 | let row4 = vld1q_u32(point.as_ptr().add(8).cast()); 39 | let row5 = vld1q_u32(point.as_ptr().add(10).cast()); 40 | let row6 = vld1q_u32(point.as_ptr().add(12).cast()); 41 | let row7 = vld1q_u32(point.as_ptr().add(14).cast()); 42 | let row8 = vld1q_u32(point.as_ptr().add(16).cast()); 43 | 44 | let mask = vceqq_u32(index, desired_index); 45 | index = vaddq_u32(index, ones); 46 | 47 | let row0 = vandq_u32(row0, mask); 48 | let row1 = vandq_u32(row1, mask); 49 | let row2 = vandq_u32(row2, mask); 50 | let row3 = vandq_u32(row3, mask); 51 | let row4 = vandq_u32(row4, mask); 52 | let row5 = vandq_u32(row5, mask); 53 | let row6 = vandq_u32(row6, mask); 54 | let row7 = vandq_u32(row7, mask); 55 | let row8 = vandq_u32(row8, mask); 56 | 57 | acc0 = veorq_u32(acc0, row0); 58 | acc1 = veorq_u32(acc1, row1); 59 | acc2 = veorq_u32(acc2, row2); 60 | acc3 = veorq_u32(acc3, row3); 61 | acc4 = veorq_u32(acc4, row4); 62 | acc5 = veorq_u32(acc5, row5); 63 | acc6 = veorq_u32(acc6, row6); 64 | acc7 = veorq_u32(acc7, row7); 65 | acc8 = veorq_u32(acc8, row8); 66 | } 67 | 68 | vst1q_u32(z.as_mut_ptr().add(0).cast(), acc0); 69 | vst1q_u32(z.as_mut_ptr().add(2).cast(), acc1); 70 | vst1q_u32(z.as_mut_ptr().add(4).cast(), acc2); 71 | vst1q_u32(z.as_mut_ptr().add(6).cast(), acc3); 72 | vst1q_u32(z.as_mut_ptr().add(8).cast(), acc4); 73 | vst1q_u32(z.as_mut_ptr().add(10).cast(), acc5); 74 | vst1q_u32(z.as_mut_ptr().add(12).cast(), acc6); 75 | vst1q_u32(z.as_mut_ptr().add(14).cast(), acc7); 76 | vst1q_u32(z.as_mut_ptr().add(16).cast(), acc8); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /graviola/src/low/aarch64/mod.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | pub(crate) mod aes; 5 | pub(crate) mod aes_gcm; 6 | pub(crate) mod bignum_add; 7 | pub(crate) mod bignum_add_p256; 8 | pub(crate) mod bignum_add_p384; 9 | pub(crate) mod bignum_bitsize; 10 | pub(crate) mod bignum_cmp_lt; 11 | pub(crate) mod bignum_coprime; 12 | pub(crate) mod bignum_copy_row_from_table; 13 | pub(crate) mod bignum_copy_row_from_table_16; 14 | pub(crate) mod bignum_copy_row_from_table_32; 15 | pub(crate) mod bignum_copy_row_from_table_8n; 16 | pub(crate) mod bignum_copy_row_from_table_mux; 17 | pub(crate) mod bignum_ctz; 18 | pub(crate) mod bignum_demont; 19 | pub(crate) mod bignum_demont_p256; 20 | pub(crate) mod bignum_demont_p384; 21 | pub(crate) mod bignum_digitsize; 22 | pub(crate) mod bignum_emontredc_8n; 23 | pub(crate) mod bignum_eq; 24 | pub(crate) mod bignum_inv_p256; 25 | pub(crate) mod bignum_inv_p384; 26 | pub(crate) mod bignum_kmul_16_32; 27 | pub(crate) mod bignum_kmul_32_64; 28 | pub(crate) mod bignum_ksqr_16_32; 29 | pub(crate) mod bignum_ksqr_32_64; 30 | pub(crate) mod bignum_mod_n256; 31 | pub(crate) mod bignum_mod_n384; 32 | pub(crate) mod bignum_modadd; 33 | pub(crate) mod bignum_modinv; 34 | pub(crate) mod bignum_modsub; 35 | pub(crate) mod bignum_montifier; 36 | pub(crate) mod bignum_montmul; 37 | pub(crate) mod bignum_montmul_p256; 38 | pub(crate) mod bignum_montmul_p384; 39 | pub(crate) mod bignum_montredc; 40 | pub(crate) mod bignum_montsqr; 41 | pub(crate) mod bignum_montsqr_p256; 42 | pub(crate) mod bignum_montsqr_p384; 43 | pub(crate) mod bignum_mul; 44 | pub(crate) mod bignum_mux; 45 | pub(crate) mod bignum_neg_p256; 46 | pub(crate) mod bignum_neg_p384; 47 | pub(crate) mod bignum_negmodinv; 48 | pub(crate) mod bignum_optsub; 49 | pub(crate) mod bignum_point_select_p256; 50 | pub(crate) mod bignum_point_select_p384; 51 | pub(crate) mod bignum_shr_small; 52 | pub(crate) mod bignum_tomont_p256; 53 | pub(crate) mod bignum_tomont_p384; 54 | pub(crate) mod cpu; 55 | pub(crate) mod curve25519_x25519; 56 | pub(crate) mod curve25519_x25519base; 57 | pub(crate) mod ghash; 58 | pub(crate) mod p256_montjadd; 59 | pub(crate) mod p256_montjdouble; 60 | pub(crate) mod p256_montjmixadd; 61 | pub(crate) mod p384_montjadd; 62 | pub(crate) mod p384_montjdouble; 63 | pub(crate) mod sha256; 64 | -------------------------------------------------------------------------------- /graviola/src/low/ct.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2025. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | cfg_if::cfg_if! { 5 | if #[cfg(all(test, target_os = "linux", target_arch = "x86_64"))] { 6 | use crabgrind as cg; 7 | use core::mem::size_of_val; 8 | 9 | #[inline] 10 | pub(crate) fn secret_slice(v: &[T]) { 11 | cg::monitor_command(format!( 12 | "make_memory undefined {:p} {}", 13 | v.as_ptr(), 14 | size_of_val(v) 15 | )) 16 | .unwrap(); 17 | } 18 | 19 | #[inline] 20 | pub(crate) fn public_slice(v: &[T]) { 21 | cg::monitor_command(format!( 22 | "make_memory defined {:p} {}", 23 | v.as_ptr(), 24 | size_of_val(v) 25 | )) 26 | .unwrap(); 27 | } 28 | 29 | #[inline] 30 | #[must_use] 31 | pub(crate) fn into_secret(v: T) -> T { 32 | cg::monitor_command(format!( 33 | "make_memory undefined {:p} {}", 34 | &v as *const T, 35 | size_of_val(&v) 36 | )) 37 | .unwrap(); 38 | v 39 | } 40 | 41 | #[inline] 42 | #[must_use] 43 | pub(crate) fn into_public(v: T) -> T { 44 | cg::monitor_command(format!( 45 | "make_memory defined {:p} {}", 46 | &v as *const T, 47 | size_of_val(&v) 48 | )) 49 | .unwrap(); 50 | v 51 | } 52 | } else { 53 | #[inline] 54 | pub(crate) fn secret_slice(_v: &[T]) {} 55 | 56 | #[inline] 57 | pub(crate) fn public_slice(_v: &[T]) {} 58 | 59 | #[inline] 60 | #[must_use] 61 | pub(crate) fn into_secret(v: T) -> T { v } 62 | 63 | #[inline] 64 | #[must_use] 65 | pub(crate) fn into_public(v: T) -> T { v } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /graviola/src/low/entry.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use super::{enter_cpu_state, leave_cpu_state, verify_cpu_features}; 5 | 6 | /// One of these should be made at library entry points: every `pub` function. 7 | /// 8 | /// Trivial conversions, accessors (ie, functions which do no actual computation) 9 | /// need not. 10 | pub(crate) struct Entry { 11 | secret: bool, 12 | cpu_state: u32, 13 | } 14 | 15 | impl Entry { 16 | /// Must be called at top-level crate entry points for public functions. 17 | /// 18 | /// Public functions have no secret data in their arguments or return values. 19 | #[must_use] 20 | pub(crate) fn new_public() -> Self { 21 | verify_cpu_features(); 22 | 23 | Self { 24 | secret: false, 25 | cpu_state: 0, 26 | } 27 | } 28 | 29 | /// Must be called at top-level crate entry points for secret functions. 30 | /// 31 | /// Secret functions have secret data in their arguments or return values 32 | /// (directly, or transitively). 33 | #[must_use] 34 | pub(crate) fn new_secret() -> Self { 35 | verify_cpu_features(); 36 | let cpu_state = enter_cpu_state(); 37 | 38 | Self { 39 | secret: true, 40 | cpu_state, 41 | } 42 | } 43 | } 44 | 45 | impl Drop for Entry { 46 | fn drop(&mut self) { 47 | if self.secret { 48 | leave_cpu_state(self.cpu_state); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /graviola/src/low/generic/blockwise.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | #[derive(Clone)] 5 | pub(crate) struct Blockwise { 6 | buffer: [u8; N], 7 | used: usize, 8 | } 9 | 10 | impl Blockwise { 11 | pub(crate) const fn new() -> Self { 12 | Self { 13 | buffer: [0u8; N], 14 | used: 0, 15 | } 16 | } 17 | 18 | pub(crate) const fn used(&self) -> usize { 19 | self.used 20 | } 21 | 22 | pub(crate) fn add_leading<'a>(&mut self, bytes: &'a [u8]) -> &'a [u8] { 23 | if self.used == 0 { 24 | return bytes; 25 | } 26 | 27 | let space = N - self.used; 28 | let take = core::cmp::min(bytes.len(), space); 29 | let (taken, returned) = bytes.split_at(take); 30 | self.buffer[self.used..self.used + take].copy_from_slice(taken); 31 | self.used += take; 32 | returned 33 | } 34 | 35 | pub(crate) fn take(&mut self) -> Option<[u8; N]> { 36 | if self.used == N { 37 | self.used = 0; 38 | Some(self.buffer) 39 | } else { 40 | None 41 | } 42 | } 43 | 44 | pub(crate) fn peek_remaining(&self) -> Option<&[u8]> { 45 | if self.used > 0 { 46 | Some(&self.buffer[..self.used]) 47 | } else { 48 | None 49 | } 50 | } 51 | 52 | pub(crate) fn add_trailing(&mut self, trailing: &[u8]) { 53 | self.buffer[..trailing.len()].copy_from_slice(trailing); 54 | self.used += trailing.len(); 55 | } 56 | 57 | pub(crate) fn md_pad_with_length(&mut self, length_bits: &[u8]) -> FinalBlocks { 58 | let space = N - self.used; 59 | let required = 1 + length_bits.len(); 60 | 61 | if required > space { 62 | // two block case (not especially optimised) 63 | self.add_leading(&[0x80]); 64 | self.add_leading(&[0u8; N]); 65 | 66 | let first = self.take().unwrap(); 67 | let mut second = [0u8; N]; 68 | let (_, length) = second.split_at_mut(N - length_bits.len()); 69 | length.copy_from_slice(length_bits); 70 | FinalBlocks::Two([first, second]) 71 | } else { 72 | let (_used, trailer) = self.buffer.split_at_mut(self.used); 73 | let (padding, length) = trailer.split_at_mut(trailer.len() - length_bits.len()); 74 | let (delim, zeroes) = padding.split_at_mut(1); 75 | delim[0] = 0x80; 76 | zeroes.fill(0x00); 77 | length.copy_from_slice(length_bits); 78 | self.used = 0; 79 | FinalBlocks::One(self.buffer) 80 | } 81 | } 82 | } 83 | 84 | pub(crate) enum FinalBlocks { 85 | One([u8; N]), 86 | Two([[u8; N]; 2]), 87 | } 88 | 89 | impl AsRef<[u8]> for FinalBlocks { 90 | fn as_ref(&self) -> &[u8] { 91 | match self { 92 | Self::One(one) => &one[..], 93 | Self::Two(two) => { 94 | // SAFETY: `[T]` is layout-identical to `[T; N]` 95 | // TODO(msrv): replace with as_flattened() 96 | unsafe { core::slice::from_raw_parts(two.as_ptr().cast(), N * 2) } 97 | } 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /graviola/src/low/generic/ct_equal.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use crate::low::ct_compare_bytes; 5 | 6 | pub(crate) fn ct_equal(a: &[u8], b: &[u8]) -> bool { 7 | if a.len() != b.len() { 8 | return false; 9 | } 10 | 11 | // SAFETY: prior code guarantees a.len() == b.len() 12 | let diff = unsafe { ct_compare_bytes(a.as_ptr(), b.as_ptr(), a.len()) }; 13 | diff == 0 14 | } 15 | -------------------------------------------------------------------------------- /graviola/src/low/generic/ghash.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | /// An extremely slow, by-the-book implementation. 5 | /// 6 | /// Useful as a test model for faster implementations. 7 | pub(crate) struct GhashTable { 8 | h: u128, 9 | } 10 | 11 | impl GhashTable { 12 | pub(crate) fn new(h: u128) -> Self { 13 | Self { h } 14 | } 15 | } 16 | 17 | pub(crate) struct Ghash<'a> { 18 | table: &'a GhashTable, 19 | current: u128, 20 | } 21 | impl<'a> Ghash<'a> { 22 | pub(crate) fn new(table: &'a GhashTable) -> Self { 23 | Self { table, current: 0 } 24 | } 25 | 26 | /// Input `bytes` to the computation. 27 | /// 28 | /// `bytes` is zero-padded, if required. 29 | pub(crate) fn add(&mut self, bytes: &[u8]) { 30 | let mut whole_blocks = bytes.chunks_exact(16); 31 | 32 | for chunk in whole_blocks.by_ref() { 33 | let u = u128::from_be_bytes(chunk.try_into().unwrap()); 34 | self.one_block(u); 35 | } 36 | 37 | let bytes = whole_blocks.remainder(); 38 | if !bytes.is_empty() { 39 | let mut block = [0u8; 16]; 40 | block[..bytes.len()].copy_from_slice(bytes); 41 | 42 | let u = u128::from_be_bytes(block); 43 | self.one_block(u); 44 | } 45 | } 46 | 47 | pub(crate) fn into_bytes(self) -> [u8; 16] { 48 | self.current.to_be_bytes() 49 | } 50 | 51 | fn one_block(&mut self, block: u128) { 52 | self.current ^= block; 53 | self.current = mul(self.current, self.table.h); 54 | } 55 | } 56 | 57 | pub(crate) fn mul(x: u128, y: u128) -> u128 { 58 | let mut z = 0; 59 | let mut v = x; 60 | 61 | for i in 0..128 { 62 | let bit = 127 - i; 63 | let mask = ((y >> bit) & 1).wrapping_neg(); 64 | let sum = z ^ v; 65 | z = (z & !mask) | (sum & mask); 66 | v = double(v); 67 | } 68 | 69 | z 70 | } 71 | 72 | fn double(a: u128) -> u128 { 73 | let mask = (a & 1).wrapping_neg(); 74 | let b = a >> 1; 75 | b ^ (mask & R) 76 | } 77 | 78 | const R: u128 = 0xe1000000_00000000_00000000_00000000; 79 | 80 | #[cfg(test)] 81 | mod tests { 82 | use super::*; 83 | 84 | #[test] 85 | fn test_double() { 86 | assert_eq!(0, double(0)); 87 | assert_eq!(R, double(1)); 88 | assert_eq!(1, double(2)); 89 | assert_eq!(R + 1, double(3)); 90 | 91 | let e = u128::from_be_bytes( 92 | *b"\x5e\x2e\xc7\x46\x91\x70\x62\x88\x2c\x85\xb0\x68\x53\x53\xde\xb7", 93 | ); 94 | let e2 = double(e); 95 | assert_eq!( 96 | &e2.to_be_bytes(), 97 | b"\xce\x17\x63\xa3\x48\xb8\x31\x44\x16\x42\xd8\x34\x29\xa9\xef\x5b" 98 | ); 99 | } 100 | 101 | #[test] 102 | fn test_mul() { 103 | assert_eq!(0, mul(1, 0)); 104 | 105 | let x = u128::from_be_bytes( 106 | *b"\x03\x88\xda\xce\x60\xb6\xa3\x92\xf3\x28\xc2\xb9\x71\xb2\xfe\x78", 107 | ); 108 | let y = u128::from_be_bytes( 109 | *b"\x66\xe9\x4b\xd4\xef\x8a\x2c\x3b\x88\x4c\xfa\x59\xca\x34\x2b\x2e", 110 | ); 111 | assert_eq!( 112 | b"\x5e\x2e\xc7\x46\x91\x70\x62\x88\x2c\x85\xb0\x68\x53\x53\xde\xb7", 113 | &mul(x, y).to_be_bytes() 114 | ); 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /graviola/src/low/generic/sha256.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | macro_rules! CH { 5 | ($x:expr, $y:expr, $z:expr) => { 6 | ($x & $y) ^ (!$x & $z) 7 | }; 8 | } 9 | 10 | macro_rules! MAJ { 11 | ($x:expr, $y:expr, $z:expr) => { 12 | ($x & $y) ^ ($x & $z) ^ ($y & $z) 13 | }; 14 | } 15 | 16 | macro_rules! BSIG0 { 17 | ($x:expr) => { 18 | $x.rotate_right(2) ^ $x.rotate_right(13) ^ $x.rotate_right(22) 19 | }; 20 | } 21 | 22 | macro_rules! BSIG1 { 23 | ($x:expr) => { 24 | $x.rotate_right(6) ^ $x.rotate_right(11) ^ $x.rotate_right(25) 25 | }; 26 | } 27 | 28 | macro_rules! SSIG0 { 29 | ($x:expr) => { 30 | $x.rotate_right(7) ^ $x.rotate_right(18) ^ ($x >> 3) 31 | }; 32 | } 33 | 34 | macro_rules! SSIG1 { 35 | ($x:expr) => { 36 | $x.rotate_right(17) ^ $x.rotate_right(19) ^ ($x >> 10) 37 | }; 38 | } 39 | 40 | fn sha256_compress_block(state: &mut [u32; 8], block: &[u8]) { 41 | let mut a = state[0]; 42 | let mut b = state[1]; 43 | let mut c = state[2]; 44 | let mut d = state[3]; 45 | let mut e = state[4]; 46 | let mut f = state[5]; 47 | let mut g = state[6]; 48 | let mut h = state[7]; 49 | 50 | // This is a 16-word window into the whole W array. 51 | let mut w: [u32; 16] = [0; 16]; 52 | 53 | for t in 0..64 { 54 | // For W[0..16] we process the input into W. 55 | // For W[16..64] we compute the next W value: 56 | // 57 | // W[t] = SSIG1(W[t - 2]) + W[t - 7] + SSIG0(W[t - 15]) + W[t - 16]; 58 | // 59 | // But all W indices are reduced mod 16 into our window. 60 | let w_t = if t < 16 { 61 | let w_t = u32::from_be_bytes(block[t * 4..(t + 1) * 4].try_into().unwrap()); 62 | w[t] = w_t; 63 | w_t 64 | } else { 65 | let w_t = SSIG1!(w[(t - 2) % 16]) 66 | .wrapping_add(w[(t - 7) % 16]) 67 | .wrapping_add(SSIG0!(w[(t - 15) % 16])) 68 | .wrapping_add(w[(t - 16) % 16]); 69 | w[t % 16] = w_t; 70 | w_t 71 | }; 72 | 73 | let t1 = h 74 | .wrapping_add(BSIG1!(e)) 75 | .wrapping_add(CH!(e, f, g)) 76 | .wrapping_add(K[t]) 77 | .wrapping_add(w_t); 78 | let t2 = BSIG0!(a).wrapping_add(MAJ!(a, b, c)); 79 | h = g; 80 | g = f; 81 | f = e; 82 | e = d.wrapping_add(t1); 83 | d = c; 84 | c = b; 85 | b = a; 86 | a = t1.wrapping_add(t2); 87 | } 88 | 89 | state[0] = state[0].wrapping_add(a); 90 | state[1] = state[1].wrapping_add(b); 91 | state[2] = state[2].wrapping_add(c); 92 | state[3] = state[3].wrapping_add(d); 93 | state[4] = state[4].wrapping_add(e); 94 | state[5] = state[5].wrapping_add(f); 95 | state[6] = state[6].wrapping_add(g); 96 | state[7] = state[7].wrapping_add(h); 97 | } 98 | 99 | pub(crate) fn sha256_compress_blocks(state: &mut [u32; 8], blocks: &[u8]) { 100 | debug_assert!(blocks.len() % 64 == 0); 101 | 102 | for block in blocks.chunks_exact(64) { 103 | sha256_compress_block(state, block); 104 | } 105 | } 106 | 107 | static K: [u32; 64] = [ 108 | 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, 109 | 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 110 | 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, 111 | 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, 112 | 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 113 | 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, 114 | 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, 115 | 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, 116 | ]; 117 | -------------------------------------------------------------------------------- /graviola/src/low/generic/zeroise.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use core::mem::{size_of, size_of_val}; 5 | 6 | use crate::low::zero_bytes; 7 | 8 | /// Writes zeroes over the whole of the `v` slice. 9 | pub(crate) fn zeroise(v: &mut [T]) { 10 | zero_bytes(v.as_mut_ptr().cast(), size_of_val(v)); 11 | } 12 | 13 | /// Writes zeroes over the whole of the `v` value. 14 | pub(crate) fn zeroise_value(v: &mut T) { 15 | zero_bytes(v as *mut T as *mut _, size_of::()); 16 | } 17 | 18 | /// Marker trait for types who have valid all-bits-zero values. 19 | pub(crate) trait Zeroable {} 20 | 21 | impl Zeroable for u8 {} 22 | impl Zeroable for u64 {} 23 | impl Zeroable for usize {} 24 | 25 | #[cfg(target_arch = "x86_64")] 26 | impl Zeroable for core::arch::x86_64::__m256i {} 27 | #[cfg(target_arch = "x86_64")] 28 | impl Zeroable for core::arch::x86_64::__m128i {} 29 | 30 | #[cfg(target_arch = "aarch64")] 31 | impl Zeroable for core::arch::aarch64::uint8x16_t {} 32 | #[cfg(target_arch = "aarch64")] 33 | impl Zeroable for core::arch::aarch64::uint64x2_t {} 34 | -------------------------------------------------------------------------------- /graviola/src/low/macros.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | /// takes a sequence of expressions (not separated by commas), 5 | /// and feeds them into concat!() to form a single string 6 | /// 7 | /// named after perl's q operator. 8 | macro_rules! Q { 9 | ($($e:expr)*) => { 10 | concat!($($e ,)*) 11 | }; 12 | } 13 | 14 | pub(crate) use Q; 15 | 16 | /// Label macro, which just resolves to the id as a string, 17 | /// but keeps the name close to it in the code. 18 | /// 19 | /// See the warnings about labels in the rust guide, this 20 | /// means we use local labels without compromising so much 21 | /// on readability. 22 | macro_rules! Label { 23 | // declaration form 24 | ($name:literal, $id:literal) => { 25 | stringify!($id) 26 | }; 27 | 28 | // reference form (downwards) 29 | ($name:literal, $id:literal, After) => { 30 | stringify!($id f) 31 | }; 32 | 33 | // reference form (upwards) 34 | ($name:literal, $id:literal, Before) => { 35 | stringify!($id b) 36 | } 37 | } 38 | 39 | pub(crate) use Label; 40 | 41 | /// Plasters over the difference between ELF and Mach-O relocation 42 | /// syntax, for page-aligned items. (Only makes sense on aarch64). 43 | #[cfg(target_os = "macos")] 44 | macro_rules! PageRef { 45 | ($sym:literal) => { Q!( "{" $sym "}@PAGE" ) } 46 | } 47 | 48 | #[allow(unused_macros)] 49 | #[cfg(not(target_os = "macos"))] 50 | macro_rules! PageRef { 51 | ($sym:literal) => { Q!( "{" $sym "}" ) } 52 | } 53 | 54 | #[allow(unused_imports)] 55 | pub(crate) use PageRef; 56 | -------------------------------------------------------------------------------- /graviola/src/low/tests.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | fn bignum_mux_equiv(p: u64, x_if_p: &[u64], y_if_not_p: &[u64]) { 5 | let mut model_z = vec![0; x_if_p.len()]; 6 | let mut real_z = vec![0; x_if_p.len()]; 7 | model::bignum_mux(p, &mut model_z, x_if_p, y_if_not_p); 8 | super::bignum_mux(p, &mut real_z, x_if_p, y_if_not_p); 9 | assert_eq!(model_z, real_z); 10 | } 11 | 12 | #[test] 13 | fn bignum_mux() { 14 | bignum_mux_equiv(0, &[0u64; 4], &[1u64; 4]); 15 | bignum_mux_equiv(1, &[1u64; 4], &[0xff; 4]); 16 | bignum_mux_equiv(u64::MAX, &[1; 1], &[0; 1]); 17 | } 18 | 19 | #[test] 20 | fn zeroise() { 21 | for n in 0..1024 { 22 | zeroise_equiv(n); 23 | } 24 | } 25 | 26 | fn zeroise_equiv(len: usize) { 27 | let expect = vec![0x00u8; len]; 28 | let mut bytes = vec![0xffu8; len]; 29 | super::zeroise(&mut bytes); 30 | assert_eq!(expect, bytes); 31 | } 32 | 33 | #[test] 34 | fn ct_equal() { 35 | ct_equal_equiv(&[], &[]); 36 | 37 | for n in 1..1024 { 38 | let a = vec![0u8; n]; 39 | 40 | for i in 0..n { 41 | let mut b = vec![0u8; n]; 42 | b[i] = i as u8; 43 | ct_equal_equiv(&a, &b); 44 | } 45 | } 46 | } 47 | 48 | fn ct_equal_equiv(a: &[u8], b: &[u8]) { 49 | assert_eq!(a == b, super::ct_equal(a, b)); 50 | } 51 | 52 | mod model { 53 | pub(super) fn bignum_mux(p: u64, z: &mut [u64], x_if_p: &[u64], y_if_not_p: &[u64]) { 54 | if p > 0 { 55 | z.copy_from_slice(x_if_p); 56 | } else { 57 | z.copy_from_slice(y_if_not_p); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_bitsize.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Return size of bignum in bits 10 | // Input x[k]; output function return 11 | // 12 | // extern uint64_t bignum_bitsize(uint64_t k, const uint64_t *x); 13 | // 14 | // In the case of a zero bignum as input the result is 0 15 | // 16 | // In principle this has a precondition k < 2^58, but obviously that 17 | // is always true in practice because of address space limitations. 18 | // 19 | // Standard x86-64 ABI: RDI = k, RSI = x, returns RAX 20 | // Microsoft x64 ABI: RCX = k, RDX = x, returns RAX 21 | // ---------------------------------------------------------------------------- 22 | 23 | macro_rules! k { 24 | () => { 25 | "rdi" 26 | }; 27 | } 28 | macro_rules! x { 29 | () => { 30 | "rsi" 31 | }; 32 | } 33 | macro_rules! i { 34 | () => { 35 | "rax" 36 | }; 37 | } 38 | macro_rules! w { 39 | () => { 40 | "rdx" 41 | }; 42 | } 43 | macro_rules! a { 44 | () => { 45 | "rcx" 46 | }; 47 | } 48 | macro_rules! j { 49 | () => { 50 | "r8" 51 | }; 52 | } 53 | 54 | /// Return size of bignum in bits 55 | /// 56 | /// Input x[k]; output function return 57 | /// 58 | /// In the case of a zero bignum as input the result is 0 59 | /// 60 | /// In principle this has a precondition k < 2^58, but obviously that 61 | /// is always true in practice because of address space limitations. 62 | pub(crate) fn bignum_bitsize(x: &[u64]) -> usize { 63 | let ret: u64; 64 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 65 | unsafe { 66 | core::arch::asm!( 67 | 68 | Q!(" endbr64 " ), 69 | 70 | 71 | // Initialize the index i and also prepare default return value of 0 (i = rax) 72 | 73 | Q!(" xor " i!() ", " i!()), 74 | 75 | // If the bignum is zero-length, just return 0 76 | 77 | Q!(" test " k!() ", " k!()), 78 | Q!(" jz " Label!("bignum_bitsize_end", 2, After)), 79 | 80 | // Use w = a[i-1] to store nonzero words in a bottom-up sweep 81 | // Set the initial default to be as if we had a 11...11 word directly below 82 | 83 | Q!(" mov " w!() ", -1"), 84 | Q!(" xor " j!() ", " j!()), 85 | Q!(Label!("bignum_bitsize_loop", 3) ":"), 86 | Q!(" mov " a!() ", [" x!() "+ 8 * " j!() "]"), 87 | Q!(" inc " j!()), 88 | Q!(" test " a!() ", " a!()), 89 | Q!(" cmovnz " i!() ", " j!()), 90 | Q!(" cmovnz " w!() ", " a!()), 91 | Q!(" cmp " j!() ", " k!()), 92 | Q!(" jnz " Label!("bignum_bitsize_loop", 3, Before)), 93 | 94 | // Now w = a[i-1] is the highest nonzero word, or in the zero case the 95 | // default of the "extra" 11...11 = a[0-1]. We now want 64* i - clz(w) = 96 | // 64 * i - (63 - bsr(w)) = (64 * i - 63) + bsr(w). Note that this code 97 | // does not rely on the behavior of the bsr instruction for zero inputs, 98 | // which is undefined. 99 | 100 | Q!(" shl " i!() ", 6"), 101 | Q!(" sub " i!() ", 63"), 102 | Q!(" bsr " w!() ", " w!()), 103 | Q!(" add " "rax, " w!()), 104 | 105 | Q!(Label!("bignum_bitsize_end", 2) ":"), 106 | inout("rdi") x.len() => _, 107 | inout("rsi") x.as_ptr() => _, 108 | out("rax") ret, 109 | // clobbers 110 | out("r8") _, 111 | out("rcx") _, 112 | out("rdx") _, 113 | ) 114 | }; 115 | ret as usize 116 | } 117 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_copy_row_from_table_16_avx2.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use core::arch::x86_64::*; 5 | 6 | pub(crate) fn bignum_copy_row_from_table_16_avx2( 7 | z: &mut [u64], 8 | table: &[u64], 9 | _height: u64, 10 | index: u64, 11 | ) { 12 | debug_assert!(z.len() == 16); 13 | debug_assert!(table.len() == (_height as usize) * z.len()); 14 | 15 | // SAFETY: this crate requires the `avx` and `avx2` cpu features 16 | unsafe { _bignum_copy_row_from_table_16_avx2(z, table, index) } 17 | } 18 | 19 | #[target_feature(enable = "avx,avx2")] 20 | unsafe fn _bignum_copy_row_from_table_16_avx2(z: &mut [u64], table: &[u64], index: u64) { 21 | // SAFETY: intrinsics. see [crate::low::inline_assembly_safety#safety-of-intrinsics] for safety info. 22 | unsafe { 23 | // SAFETY: prefetches do not fault and are not architecturally visible 24 | _mm_prefetch(table.as_ptr().cast(), _MM_HINT_T0); 25 | _mm_prefetch(table.as_ptr().add(16).cast(), _MM_HINT_T0); 26 | 27 | let mut acc0 = _mm256_setzero_si256(); 28 | let mut acc1 = _mm256_setzero_si256(); 29 | let mut acc2 = _mm256_setzero_si256(); 30 | let mut acc3 = _mm256_setzero_si256(); 31 | 32 | let desired_index = _mm_set1_epi64x(index as i64); 33 | let desired_index = _mm256_setr_m128i(desired_index, desired_index); 34 | 35 | let index = _mm_set1_epi64x(0); 36 | let mut index = _mm256_setr_m128i(index, index); 37 | 38 | let ones = _mm_set1_epi64x(1); 39 | let ones = _mm256_setr_m128i(ones, ones); 40 | 41 | for row in table.chunks_exact(16) { 42 | let mask = _mm256_cmpeq_epi64(index, desired_index); 43 | index = _mm256_add_epi64(index, ones); 44 | 45 | // SAFETY: `row` is exactly 16 words; `loadu` relaxes 256-bit alignment req. 46 | let row0 = _mm256_loadu_si256(row.as_ptr().add(0).cast()); 47 | let row1 = _mm256_loadu_si256(row.as_ptr().add(4).cast()); 48 | let row2 = _mm256_loadu_si256(row.as_ptr().add(8).cast()); 49 | let row3 = _mm256_loadu_si256(row.as_ptr().add(12).cast()); 50 | 51 | let row0 = _mm256_and_si256(row0, mask); 52 | let row1 = _mm256_and_si256(row1, mask); 53 | let row2 = _mm256_and_si256(row2, mask); 54 | let row3 = _mm256_and_si256(row3, mask); 55 | 56 | acc0 = _mm256_xor_si256(row0, acc0); 57 | acc1 = _mm256_xor_si256(row1, acc1); 58 | acc2 = _mm256_xor_si256(row2, acc2); 59 | acc3 = _mm256_xor_si256(row3, acc3); 60 | } 61 | 62 | // SAFETY: `z` is exactly 16 words 63 | _mm256_storeu_si256(z.as_mut_ptr().add(0).cast(), acc0); 64 | _mm256_storeu_si256(z.as_mut_ptr().add(4).cast(), acc1); 65 | _mm256_storeu_si256(z.as_mut_ptr().add(8).cast(), acc2); 66 | _mm256_storeu_si256(z.as_mut_ptr().add(12).cast(), acc3); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_copy_row_from_table_8n_avx2.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use core::arch::x86_64::*; 5 | 6 | pub(crate) fn bignum_copy_row_from_table_8n_avx2( 7 | z: &mut [u64], 8 | table: &[u64], 9 | _height: u64, 10 | width: u64, 11 | index: u64, 12 | ) { 13 | debug_assert!(z.len() as u64 == width); 14 | debug_assert!(width % 8 == 0); 15 | debug_assert!(table.len() as u64 == _height * width); 16 | 17 | // SAFETY: this crate requires the `avx` and `avx2` cpu features 18 | unsafe { _bignum_copy_row_from_table_8n_avx2(z, table, width, index) } 19 | } 20 | 21 | #[target_feature(enable = "avx,avx2")] 22 | unsafe fn _bignum_copy_row_from_table_8n_avx2( 23 | z: &mut [u64], 24 | table: &[u64], 25 | width: u64, 26 | index: u64, 27 | ) { 28 | // SAFETY: intrinsics. see [crate::low::inline_assembly_safety#safety-of-intrinsics] for safety info. 29 | unsafe { 30 | // SAFETY: prefetches do not fault and are not architecturally visible 31 | _mm_prefetch(table.as_ptr().cast(), _MM_HINT_T0); 32 | _mm_prefetch(table.as_ptr().add(16).cast(), _MM_HINT_T0); 33 | 34 | z.fill(0); 35 | 36 | let desired_index = _mm_set1_epi64x(index as i64); 37 | let desired_index = _mm256_setr_m128i(desired_index, desired_index); 38 | 39 | let index = _mm_set1_epi64x(0); 40 | let mut index = _mm256_setr_m128i(index, index); 41 | 42 | let ones = _mm_set1_epi64x(1); 43 | let ones = _mm256_setr_m128i(ones, ones); 44 | 45 | for row in table.chunks_exact(width as usize) { 46 | let mask = _mm256_cmpeq_epi64(index, desired_index); 47 | index = _mm256_add_epi64(index, ones); 48 | 49 | for (i, zz) in z.chunks_exact_mut(8).enumerate() { 50 | // SAFETY: `row` is a multiple of 8 words in length 51 | let row0 = _mm256_loadu_si256(row.as_ptr().add(i * 8).cast()); 52 | let row1 = _mm256_loadu_si256(row.as_ptr().add(i * 8 + 4).cast()); 53 | 54 | let row0 = _mm256_and_si256(row0, mask); 55 | let row1 = _mm256_and_si256(row1, mask); 56 | 57 | // SAFETY: `zz` is exactly 8 words 58 | let store0 = _mm256_loadu_si256(zz.as_ptr().add(0).cast()); 59 | let store1 = _mm256_loadu_si256(zz.as_ptr().add(4).cast()); 60 | let store0 = _mm256_xor_si256(store0, row0); 61 | let store1 = _mm256_xor_si256(store1, row1); 62 | 63 | // SAFETY: `zz` is exactly 8 words 64 | _mm256_storeu_si256(zz.as_mut_ptr().add(0).cast(), store0); 65 | _mm256_storeu_si256(zz.as_mut_ptr().add(4).cast(), store1); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_copy_row_from_table_mux.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | /// Multiplex between specialisations of `bignum_copy_row_from_table` 5 | #[inline] 6 | pub(crate) fn bignum_copy_row_from_table( 7 | z: &mut [u64], 8 | table: &[u64], 9 | height: u64, 10 | width: u64, 11 | index: u64, 12 | ) { 13 | match width { 14 | 16 => super::bignum_copy_row_from_table_16_avx2::bignum_copy_row_from_table_16_avx2( 15 | z, table, height, index, 16 | ), 17 | width if width % 8 == 0 => { 18 | super::bignum_copy_row_from_table_8n_avx2::bignum_copy_row_from_table_8n_avx2( 19 | z, table, height, width, index, 20 | ) 21 | } 22 | width => super::bignum_copy_row_from_table::bignum_copy_row_from_table( 23 | z, table, height, width, index, 24 | ), 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_ctz.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Count trailing zero bits 10 | // Input x[k]; output function return 11 | // 12 | // extern uint64_t bignum_ctz(uint64_t k, const uint64_t *x); 13 | // 14 | // 15 | // In the case of a zero bignum as input the result is 64 * k 16 | // 17 | // In principle this has a precondition k < 2^58, but obviously that 18 | // is always true in practice because of address space limitations 19 | // 20 | // Standard x86-64 ABI: RDI = k, RSI = x, returns RAX 21 | // Microsoft x64 ABI: RCX = k, RDX = x, returns RAX 22 | // ---------------------------------------------------------------------------- 23 | 24 | macro_rules! k { 25 | () => { 26 | "rdi" 27 | }; 28 | } 29 | macro_rules! x { 30 | () => { 31 | "rsi" 32 | }; 33 | } 34 | macro_rules! i { 35 | () => { 36 | "rdx" 37 | }; 38 | } 39 | macro_rules! w { 40 | () => { 41 | "rcx" 42 | }; 43 | } 44 | macro_rules! a { 45 | () => { 46 | "rax" 47 | }; 48 | } 49 | 50 | macro_rules! wshort { 51 | () => { 52 | "ecx" 53 | }; 54 | } 55 | 56 | /// Count trailing zero bits 57 | /// 58 | /// Input x[k]; output function return 59 | /// 60 | /// 61 | /// In the case of a zero bignum as input the result is 64 * k 62 | /// 63 | /// In principle this has a precondition k < 2^58, but obviously that 64 | /// is always true in practice because of address space limitations 65 | pub(crate) fn bignum_ctz(x: &[u64]) -> usize { 66 | let ret: u64; 67 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 68 | unsafe { 69 | core::arch::asm!( 70 | 71 | Q!(" endbr64 " ), 72 | 73 | 74 | // If the bignum is zero-length, just return 0 75 | 76 | Q!(" xor " "rax, rax"), 77 | Q!(" test " k!() ", " k!()), 78 | Q!(" jz " Label!("bignum_ctz_end", 2, After)), 79 | 80 | // Use w = a[i-1] to store nonzero words in a top-down sweep 81 | // Set the initial default to be as if we had a 1 word directly above 82 | 83 | Q!(" mov " i!() ", " k!()), 84 | Q!(" inc " i!()), 85 | Q!(" mov " wshort!() ", 1"), 86 | 87 | Q!(Label!("bignum_ctz_loop", 3) ":"), 88 | Q!(" mov " a!() ", [" x!() "+ 8 * " k!() "-8]"), 89 | Q!(" test " a!() ", " a!()), 90 | Q!(" cmovne " i!() ", " k!()), 91 | Q!(" cmovne " w!() ", " a!()), 92 | Q!(" dec " k!()), 93 | Q!(" jnz " Label!("bignum_ctz_loop", 3, Before)), 94 | 95 | // Now w = a[i-1] is the lowest nonzero word, or in the zero case the 96 | // default of the "extra" 1 = a[k]. We now want 64*(i-1) + ctz(w). 97 | // Note that this code does not rely on the behavior of the BSF instruction 98 | // for zero inputs, which is undefined according to the manual. 99 | 100 | Q!(" dec " i!()), 101 | Q!(" shl " i!() ", 6"), 102 | Q!(" bsf " "rax, " w!()), 103 | Q!(" add " "rax, " i!()), 104 | 105 | Q!(Label!("bignum_ctz_end", 2) ":"), 106 | inout("rdi") x.len() => _, 107 | inout("rsi") x.as_ptr() => _, 108 | out("rax") ret, 109 | // clobbers 110 | out("rcx") _, 111 | out("rdx") _, 112 | ) 113 | }; 114 | ret as usize 115 | } 116 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_digitsize.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Return size of bignum in digits (64-bit word) 10 | // Input x[k]; output function return 11 | // 12 | // extern uint64_t bignum_digitsize(uint64_t k, const uint64_t *x); 13 | // 14 | // In the case of a zero bignum as input the result is 0 15 | // 16 | // Standard x86-64 ABI: RDI = k, RSI = x, returns RAX 17 | // Microsoft x64 ABI: RCX = k, RDX = x, returns RAX 18 | // ---------------------------------------------------------------------------- 19 | 20 | macro_rules! k { 21 | () => { 22 | "rdi" 23 | }; 24 | } 25 | macro_rules! x { 26 | () => { 27 | "rsi" 28 | }; 29 | } 30 | macro_rules! i { 31 | () => { 32 | "rax" 33 | }; 34 | } 35 | macro_rules! a { 36 | () => { 37 | "rcx" 38 | }; 39 | } 40 | macro_rules! j { 41 | () => { 42 | "rdx" 43 | }; 44 | } 45 | 46 | /// Return size of bignum in digits (64-bit word) 47 | /// 48 | /// Input x[k]; output function return 49 | /// 50 | /// In the case of a zero bignum as input the result is 0 51 | pub(crate) fn bignum_digitsize(z: &[u64]) -> usize { 52 | let ret: u64; 53 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 54 | unsafe { 55 | core::arch::asm!( 56 | 57 | Q!(" endbr64 " ), 58 | 59 | 60 | // Initialize the index i and also prepare default return value of 0 (i = rax) 61 | 62 | Q!(" xor " i!() ", " i!()), 63 | 64 | // If the bignum is zero-length, just return 0 65 | 66 | Q!(" test " k!() ", " k!()), 67 | Q!(" jz " Label!("bignum_digitsize_end", 2, After)), 68 | 69 | // Run over the words j = 0..i-1, and set i := j + 1 when hitting nonzero a[j] 70 | 71 | Q!(" xor " j!() ", " j!()), 72 | Q!(Label!("bignum_digitsize_loop", 3) ":"), 73 | Q!(" mov " a!() ", [" x!() "+ 8 * " j!() "]"), 74 | Q!(" inc " j!()), 75 | Q!(" test " a!() ", " a!()), 76 | Q!(" cmovnz " i!() ", " j!()), 77 | Q!(" cmp " j!() ", " k!()), 78 | Q!(" jnz " Label!("bignum_digitsize_loop", 3, Before)), 79 | 80 | Q!(Label!("bignum_digitsize_end", 2) ":"), 81 | inout("rdi") z.len() => _, 82 | inout("rsi") z.as_ptr() => _, 83 | out("rax") ret, 84 | // clobbers 85 | out("rcx") _, 86 | out("rdx") _, 87 | ) 88 | }; 89 | ret as usize 90 | } 91 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_eq.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Test bignums for equality, x = y 10 | // Inputs x[m], y[n]; output function return 11 | // 12 | // extern uint64_t bignum_eq(uint64_t m, const uint64_t *x, uint64_t n, 13 | // const uint64_t *y); 14 | // 15 | // Standard x86-64 ABI: RDI = m, RSI = x, RDX = n, RCX = y, returns RAX 16 | // Microsoft x64 ABI: RCX = m, RDX = x, R8 = n, R9 = y, returns RAX 17 | // ---------------------------------------------------------------------------- 18 | 19 | macro_rules! m { 20 | () => { 21 | "rdi" 22 | }; 23 | } 24 | macro_rules! x { 25 | () => { 26 | "rsi" 27 | }; 28 | } 29 | macro_rules! n { 30 | () => { 31 | "rdx" 32 | }; 33 | } 34 | macro_rules! y { 35 | () => { 36 | "rcx" 37 | }; 38 | } 39 | macro_rules! c { 40 | () => { 41 | "rax" 42 | }; 43 | } 44 | // We can re-use n for this, not needed when d appears 45 | macro_rules! d { 46 | () => { 47 | "rdx" 48 | }; 49 | } 50 | 51 | /// Test bignums for equality, x = y 52 | /// 53 | /// Inputs x[m], y[n]; output function return 54 | pub(crate) fn bignum_eq(x: &[u64], y: &[u64]) -> bool { 55 | let ret: u64; 56 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 57 | unsafe { 58 | core::arch::asm!( 59 | 60 | Q!(" endbr64 " ), 61 | 62 | 63 | // Initialize the accumulated OR of differences to zero 64 | 65 | Q!(" xor " c!() ", " c!()), 66 | 67 | // If m >= n jump into the m > n loop at the final equality test 68 | // This will drop through for m = n 69 | 70 | Q!(" cmp " m!() ", " n!()), 71 | Q!(" jnc " Label!("bignum_eq_mtest", 2, After)), 72 | 73 | // Toploop for the case n > m 74 | 75 | Q!(Label!("bignum_eq_nloop", 3) ":"), 76 | Q!(" dec " n!()), 77 | Q!(" or " c!() ", [" y!() "+ 8 * " n!() "]"), 78 | Q!(" cmp " m!() ", " n!()), 79 | Q!(" jnz " Label!("bignum_eq_nloop", 3, Before)), 80 | Q!(" jmp " Label!("bignum_eq_mmain", 4, After)), 81 | 82 | // Toploop for the case m > n (or n = m which enters at "mtest") 83 | 84 | Q!(Label!("bignum_eq_mloop", 5) ":"), 85 | Q!(" dec " m!()), 86 | Q!(" or " c!() ", [" x!() "+ 8 * " m!() "]"), 87 | Q!(" cmp " m!() ", " n!()), 88 | Q!(Label!("bignum_eq_mtest", 2) ":"), 89 | Q!(" jnz " Label!("bignum_eq_mloop", 5, Before)), 90 | 91 | // Combined main loop for the min(m,n) lower words 92 | 93 | Q!(Label!("bignum_eq_mmain", 4) ":"), 94 | Q!(" test " m!() ", " m!()), 95 | Q!(" jz " Label!("bignum_eq_end", 6, After)), 96 | 97 | Q!(Label!("bignum_eq_loop", 7) ":"), 98 | Q!(" mov " d!() ", [" x!() "+ 8 * " m!() "-8]"), 99 | Q!(" xor " d!() ", [" y!() "+ 8 * " m!() "-8]"), 100 | Q!(" or " c!() ", " d!()), 101 | Q!(" dec " m!()), 102 | Q!(" jnz " Label!("bignum_eq_loop", 7, Before)), 103 | 104 | // Set a standard C condition based on whether c is nonzero 105 | 106 | Q!(Label!("bignum_eq_end", 6) ":"), 107 | Q!(" neg " c!()), 108 | Q!(" sbb " c!() ", " c!()), 109 | Q!(" inc " c!()), 110 | inout("rdi") x.len() => _, 111 | inout("rsi") x.as_ptr() => _, 112 | inout("rdx") y.len() => _, 113 | inout("rcx") y.as_ptr() => _, 114 | out("rax") ret, 115 | // clobbers 116 | ) 117 | }; 118 | ret > 0 119 | } 120 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_modsub.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Subtract modulo m, z := (x - y) mod m, assuming x and y reduced 10 | // Inputs x[k], y[k], m[k]; output z[k] 11 | // 12 | // extern void bignum_modsub(uint64_t k, uint64_t *z, const uint64_t *x, 13 | // const uint64_t *y, const uint64_t *m); 14 | // 15 | // Standard x86-64 ABI: RDI = k, RSI = z, RDX = x, RCX = y, R8 = m 16 | // Microsoft x64 ABI: RCX = k, RDX = z, R8 = x, R9 = y, [RSP+40] = m 17 | // ---------------------------------------------------------------------------- 18 | 19 | macro_rules! k { 20 | () => { 21 | "rdi" 22 | }; 23 | } 24 | macro_rules! z { 25 | () => { 26 | "rsi" 27 | }; 28 | } 29 | macro_rules! x { 30 | () => { 31 | "rdx" 32 | }; 33 | } 34 | macro_rules! y { 35 | () => { 36 | "rcx" 37 | }; 38 | } 39 | macro_rules! m { 40 | () => { 41 | "r8" 42 | }; 43 | } 44 | macro_rules! i { 45 | () => { 46 | "r9" 47 | }; 48 | } 49 | macro_rules! j { 50 | () => { 51 | "r10" 52 | }; 53 | } 54 | macro_rules! a { 55 | () => { 56 | "rax" 57 | }; 58 | } 59 | macro_rules! c { 60 | () => { 61 | "r11" 62 | }; 63 | } 64 | 65 | /// Subtract modulo m, z := (x - y) mod m, assuming x and y reduced 66 | /// 67 | /// Inputs x[k], y[k], m[k]; output z[k] 68 | pub(crate) fn bignum_modsub(z: &mut [u64], x: &[u64], y: &[u64], m: &[u64]) { 69 | debug_assert!(z.len() == x.len()); 70 | debug_assert!(z.len() == y.len()); 71 | debug_assert!(z.len() == m.len()); 72 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 73 | unsafe { 74 | core::arch::asm!( 75 | 76 | Q!(" endbr64 " ), 77 | 78 | 79 | // If k = 0 do nothing 80 | 81 | Q!(" test " k!() ", " k!()), 82 | Q!(" jz " Label!("bignum_modsub_end", 2, After)), 83 | 84 | // Subtract z := x - y and record a mask for the carry x - y < 0 85 | 86 | Q!(" xor " c!() ", " c!()), 87 | Q!(" mov " j!() ", " k!()), 88 | Q!(" xor " i!() ", " i!()), 89 | Q!(Label!("bignum_modsub_subloop", 3) ":"), 90 | Q!(" mov " a!() ", [" x!() "+ 8 * " i!() "]"), 91 | Q!(" sbb " a!() ", [" y!() "+ 8 * " i!() "]"), 92 | Q!(" mov " "[" z!() "+ 8 * " i!() "], " a!()), 93 | Q!(" inc " i!()), 94 | Q!(" dec " j!()), 95 | Q!(" jnz " Label!("bignum_modsub_subloop", 3, Before)), 96 | Q!(" sbb " c!() ", " c!()), 97 | 98 | // Now do a masked addition z := z + [c] * m 99 | 100 | Q!(" xor " i!() ", " i!()), 101 | Q!(Label!("bignum_modsub_addloop", 4) ":"), 102 | Q!(" mov " a!() ", [" m!() "+ 8 * " i!() "]"), 103 | Q!(" and " a!() ", " c!()), 104 | Q!(" neg " j!()), 105 | Q!(" adc " "[" z!() "+ 8 * " i!() "], " a!()), 106 | Q!(" sbb " j!() ", " j!()), 107 | Q!(" inc " i!()), 108 | Q!(" cmp " i!() ", " k!()), 109 | Q!(" jc " Label!("bignum_modsub_addloop", 4, Before)), 110 | 111 | Q!(Label!("bignum_modsub_end", 2) ":"), 112 | inout("rdi") z.len() => _, 113 | inout("rsi") z.as_mut_ptr() => _, 114 | inout("rdx") x.as_ptr() => _, 115 | inout("rcx") y.as_ptr() => _, 116 | inout("r8") m.as_ptr() => _, 117 | // clobbers 118 | out("r10") _, 119 | out("r11") _, 120 | out("r9") _, 121 | out("rax") _, 122 | ) 123 | }; 124 | } 125 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_mux.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Multiplex/select z := x (if p nonzero) or z := y (if p zero) 10 | // Inputs p, x[k], y[k]; output z[k] 11 | // 12 | // extern void bignum_mux(uint64_t p, uint64_t k, uint64_t *z, const uint64_t *x, 13 | // const uint64_t *y); 14 | // 15 | // It is assumed that all numbers x, y and z have the same size k digits. 16 | // 17 | // Standard x86-64 ABI: RDI = p, RSI = k, RDX = z, RCX = x, R8 = y 18 | // Microsoft x64 ABI: RCX = p, RDX = k, R8 = z, R9 = x, [RSP+40] = y 19 | // ---------------------------------------------------------------------------- 20 | 21 | macro_rules! b { 22 | () => { 23 | "rdi" 24 | }; 25 | } 26 | macro_rules! k { 27 | () => { 28 | "rsi" 29 | }; 30 | } 31 | macro_rules! z { 32 | () => { 33 | "rdx" 34 | }; 35 | } 36 | macro_rules! x { 37 | () => { 38 | "rcx" 39 | }; 40 | } 41 | macro_rules! y { 42 | () => { 43 | "r8" 44 | }; 45 | } 46 | macro_rules! i { 47 | () => { 48 | "r9" 49 | }; 50 | } 51 | macro_rules! a { 52 | () => { 53 | "rax" 54 | }; 55 | } 56 | 57 | /// Multiplex/select z := x (if p nonzero) or z := y (if p zero) 58 | /// 59 | /// Inputs p, x[k], y[k]; output z[k] 60 | /// 61 | /// It is assumed that all numbers x, y and z have the same size k digits. 62 | pub(crate) fn bignum_mux(p: u64, z: &mut [u64], x_if_p: &[u64], y_if_not_p: &[u64]) { 63 | debug_assert!(z.len() == x_if_p.len()); 64 | debug_assert!(z.len() == y_if_not_p.len()); 65 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 66 | unsafe { 67 | core::arch::asm!( 68 | 69 | Q!(" endbr64 " ), 70 | 71 | Q!(" test " k!() ", " k!()), 72 | Q!(" jz " Label!("bignum_mux_end", 2, After)), 73 | 74 | Q!(" xor " i!() ", " i!()), 75 | Q!(" neg " b!()), 76 | Q!(Label!("bignum_mux_loop", 3) ":"), 77 | Q!(" mov " a!() ", [" x!() "+ 8 * " i!() "]"), 78 | Q!(" mov " b!() ", [" y!() "+ 8 * " i!() "]"), 79 | Q!(" cmovnc " a!() ", " b!()), 80 | Q!(" mov " "[" z!() "+ 8 * " i!() "], " a!()), 81 | Q!(" inc " i!()), 82 | Q!(" dec " k!()), 83 | Q!(" jnz " Label!("bignum_mux_loop", 3, Before)), 84 | Q!(Label!("bignum_mux_end", 2) ":"), 85 | inout("rdi") p => _, 86 | inout("rsi") z.len() => _, 87 | inout("rdx") z.as_mut_ptr() => _, 88 | inout("rcx") x_if_p.as_ptr() => _, 89 | inout("r8") y_if_not_p.as_ptr() => _, 90 | // clobbers 91 | out("r9") _, 92 | out("rax") _, 93 | ) 94 | }; 95 | } 96 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_neg_p256.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Negate modulo p_256, z := (-x) mod p_256, assuming x reduced 10 | // Input x[4]; output z[4] 11 | // 12 | // extern void bignum_neg_p256(uint64_t z[static 4], const uint64_t x[static 4]); 13 | // 14 | // Standard x86-64 ABI: RDI = z, RSI = x 15 | // Microsoft x64 ABI: RCX = z, RDX = x 16 | // ---------------------------------------------------------------------------- 17 | 18 | macro_rules! z { 19 | () => { 20 | "rdi" 21 | }; 22 | } 23 | macro_rules! x { 24 | () => { 25 | "rsi" 26 | }; 27 | } 28 | 29 | macro_rules! q { 30 | () => { 31 | "rdx" 32 | }; 33 | } 34 | 35 | macro_rules! d0 { 36 | () => { 37 | "rax" 38 | }; 39 | } 40 | macro_rules! d1 { 41 | () => { 42 | "rcx" 43 | }; 44 | } 45 | macro_rules! d2 { 46 | () => { 47 | "r8" 48 | }; 49 | } 50 | macro_rules! d3 { 51 | () => { 52 | "r9" 53 | }; 54 | } 55 | 56 | macro_rules! n1 { 57 | () => { 58 | "r10" 59 | }; 60 | } 61 | macro_rules! n3 { 62 | () => { 63 | "r11" 64 | }; 65 | } 66 | 67 | macro_rules! d0short { 68 | () => { 69 | "eax" 70 | }; 71 | } 72 | macro_rules! n1short { 73 | () => { 74 | "r10d" 75 | }; 76 | } 77 | 78 | /// Negate modulo p_256, z := (-x) mod p_256, assuming x reduced 79 | /// 80 | /// Input x[4]; output z[4] 81 | pub(crate) fn bignum_neg_p256(z: &mut [u64; 4], x: &[u64; 4]) { 82 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 83 | unsafe { 84 | core::arch::asm!( 85 | 86 | Q!(" endbr64 " ), 87 | 88 | 89 | // Load the input digits as [d3;d2;d1;d0] and also set a bitmask q 90 | // for the input being nonzero, so that we avoid doing -0 = p_256 91 | // and hence maintain strict modular reduction 92 | 93 | Q!(" mov " d0!() ", [" x!() "]"), 94 | Q!(" mov " d1!() ", [" x!() "+ 8]"), 95 | Q!(" mov " n1!() ", " d0!()), 96 | Q!(" or " n1!() ", " d1!()), 97 | Q!(" mov " d2!() ", [" x!() "+ 16]"), 98 | Q!(" mov " d3!() ", [" x!() "+ 24]"), 99 | Q!(" mov " n3!() ", " d2!()), 100 | Q!(" or " n3!() ", " d3!()), 101 | Q!(" or " n3!() ", " n1!()), 102 | Q!(" neg " n3!()), 103 | Q!(" sbb " q!() ", " q!()), 104 | 105 | // Load the non-trivial words of p_256 = [n3;0;n1;-1] and mask them with q 106 | 107 | Q!(" mov " n1short!() ", 0x00000000ffffffff"), 108 | Q!(" mov " n3!() ", 0xffffffff00000001"), 109 | Q!(" and " n1!() ", " q!()), 110 | Q!(" and " n3!() ", " q!()), 111 | 112 | // Do the subtraction, getting it as [n3;d0;n1;q] to avoid moves 113 | 114 | Q!(" sub " q!() ", " d0!()), 115 | Q!(" mov " d0short!() ", 0"), 116 | Q!(" sbb " n1!() ", " d1!()), 117 | Q!(" sbb " d0!() ", " d2!()), 118 | Q!(" sbb " n3!() ", " d3!()), 119 | 120 | // Write back 121 | 122 | Q!(" mov " "[" z!() "], " q!()), 123 | Q!(" mov " "[" z!() "+ 8], " n1!()), 124 | Q!(" mov " "[" z!() "+ 16], " d0!()), 125 | Q!(" mov " "[" z!() "+ 24], " n3!()), 126 | 127 | inout("rdi") z.as_mut_ptr() => _, 128 | inout("rsi") x.as_ptr() => _, 129 | // clobbers 130 | out("r10") _, 131 | out("r11") _, 132 | out("r8") _, 133 | out("r9") _, 134 | out("rax") _, 135 | out("rcx") _, 136 | out("rdx") _, 137 | ) 138 | }; 139 | } 140 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_optsub.rs: -------------------------------------------------------------------------------- 1 | // generated source. do not edit. 2 | #![allow(non_upper_case_globals, unused_macros, unused_imports)] 3 | use crate::low::macros::*; 4 | 5 | // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 6 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 7 | 8 | // ---------------------------------------------------------------------------- 9 | // Optionally subtract, z := x - y (if p nonzero) or z := x (if p zero) 10 | // Inputs x[k], p, y[k]; outputs function return (carry-out) and z[k] 11 | // 12 | // extern uint64_t bignum_optsub(uint64_t k, uint64_t *z, const uint64_t *x, 13 | // uint64_t p, const uint64_t *y); 14 | // 15 | // It is assumed that all numbers x, y and z have the same size k digits. 16 | // Returns carry-out as per usual subtraction, always 0 if p was zero. 17 | // 18 | // Standard x86-64 ABI: RDI = k, RSI = z, RDX = x, RCX = p, R8 = y, returns RAX 19 | // Microsoft x64 ABI: RCX = k, RDX = z, R8 = x, R9 = p, [RSP+40] = y, returns RAX 20 | // ---------------------------------------------------------------------------- 21 | 22 | macro_rules! k { 23 | () => { 24 | "rdi" 25 | }; 26 | } 27 | macro_rules! z { 28 | () => { 29 | "rsi" 30 | }; 31 | } 32 | macro_rules! x { 33 | () => { 34 | "rdx" 35 | }; 36 | } 37 | macro_rules! p { 38 | () => { 39 | "rcx" 40 | }; 41 | } 42 | macro_rules! y { 43 | () => { 44 | "r8" 45 | }; 46 | } 47 | 48 | macro_rules! i { 49 | () => { 50 | "r9" 51 | }; 52 | } 53 | macro_rules! b { 54 | () => { 55 | "r10" 56 | }; 57 | } 58 | macro_rules! c { 59 | () => { 60 | "rax" 61 | }; 62 | } 63 | macro_rules! a { 64 | () => { 65 | "r11" 66 | }; 67 | } 68 | 69 | /// Optionally subtract, z := x - y (if p nonzero) or z := x (if p zero) 70 | /// 71 | /// Inputs x[k], p, y[k]; outputs function return (carry-out) and z[k] 72 | /// 73 | /// It is assumed that all numbers x, y and z have the same size k digits. 74 | /// Returns carry-out as per usual subtraction, always 0 if p was zero. 75 | pub(crate) fn bignum_optsub(z: &mut [u64], x: &[u64], y: &[u64], p: u64) { 76 | // SAFETY: inline assembly. see [crate::low::inline_assembly_safety] for safety info. 77 | unsafe { 78 | core::arch::asm!( 79 | 80 | Q!(" endbr64 " ), 81 | 82 | 83 | // Initialize top carry to zero in all cases (also return value) 84 | 85 | Q!(" xor " c!() ", " c!()), 86 | 87 | // If k = 0 do nothing 88 | 89 | Q!(" test " k!() ", " k!()), 90 | Q!(" jz " Label!("bignum_optsub_end", 2, After)), 91 | 92 | // Convert the nonzero/zero status of p into an all-1s or all-0s mask 93 | 94 | Q!(" neg " p!()), 95 | Q!(" sbb " p!() ", " p!()), 96 | 97 | // Now go round the loop for i=0...k-1, saving the carry in c each iteration 98 | 99 | Q!(" xor " i!() ", " i!()), 100 | Q!(Label!("bignum_optsub_loop", 3) ":"), 101 | Q!(" mov " a!() ", [" x!() "+ 8 * " i!() "]"), 102 | Q!(" mov " b!() ", [" y!() "+ 8 * " i!() "]"), 103 | Q!(" and " b!() ", " p!()), 104 | Q!(" neg " c!()), 105 | Q!(" sbb " a!() ", " b!()), 106 | Q!(" sbb " c!() ", " c!()), 107 | Q!(" mov " "[" z!() "+ 8 * " i!() "], " a!()), 108 | Q!(" inc " i!()), 109 | Q!(" cmp " i!() ", " k!()), 110 | Q!(" jc " Label!("bignum_optsub_loop", 3, Before)), 111 | 112 | // Return top carry 113 | 114 | Q!(" neg " "rax"), 115 | 116 | Q!(Label!("bignum_optsub_end", 2) ":"), 117 | inout("rdi") z.len() => _, 118 | inout("rsi") z.as_mut_ptr() => _, 119 | inout("rdx") x.as_ptr() => _, 120 | inout("rcx") p => _, 121 | inout("r8") y.as_ptr() => _, 122 | // clobbers 123 | out("r10") _, 124 | out("r11") _, 125 | out("r9") _, 126 | out("rax") _, 127 | ) 128 | }; 129 | } 130 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/bignum_point_select_p384.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use core::arch::x86_64::*; 5 | 6 | /// Viewing table as rows of 18 words width, copy the 18 words at 7 | /// table[idx - 1] into z. If `idx` is zero or larger than `height`, 8 | /// `z` is set to zero (ie, a jacobian point at infinity). 9 | pub(crate) fn bignum_jac_point_select_p384(z: &mut [u64; 18], table: &[u64], index: u8) { 10 | // SAFETY: this crate requires the `avx` and `avx2` cpu features 11 | unsafe { _select_jac_p384(z, table, index) } 12 | } 13 | 14 | #[target_feature(enable = "avx,avx2")] 15 | unsafe fn _select_jac_p384(z: &mut [u64; 18], table: &[u64], index: u8) { 16 | // SAFETY: intrinsics. see [crate::low::inline_assembly_safety#safety-of-intrinsics] for safety info. 17 | unsafe { 18 | _mm_prefetch(table.as_ptr().cast(), _MM_HINT_T0); 19 | _mm_prefetch(table.as_ptr().add(16).cast(), _MM_HINT_T0); 20 | 21 | let mut acc0 = _mm256_setzero_si256(); 22 | let mut acc1 = _mm256_setzero_si256(); 23 | let mut acc2 = _mm256_setzero_si256(); 24 | let mut acc3 = _mm256_setzero_si256(); 25 | let mut acc4 = _mm256_setzero_si256(); 26 | 27 | let desired_index = _mm_set1_epi32(index as i32); 28 | let desired_index = _mm256_setr_m128i(desired_index, desired_index); 29 | 30 | let index = _mm_set1_epi32(1); 31 | let mut index = _mm256_setr_m128i(index, index); 32 | 33 | let ones = index; 34 | 35 | for point in table.chunks_exact(18) { 36 | let row0 = _mm256_loadu_si256(point.as_ptr().add(0).cast()); 37 | let row1 = _mm256_loadu_si256(point.as_ptr().add(4).cast()); 38 | let row2 = _mm256_loadu_si256(point.as_ptr().add(8).cast()); 39 | let row3 = _mm256_loadu_si256(point.as_ptr().add(12).cast()); 40 | 41 | let mut tmp = [0u64; 4]; 42 | tmp[0..2].copy_from_slice(&point[16..18]); 43 | let row4 = _mm256_loadu_si256(tmp.as_ptr().cast()); 44 | 45 | let mask = _mm256_cmpeq_epi32(index, desired_index); 46 | index = _mm256_add_epi32(index, ones); 47 | 48 | let row0 = _mm256_and_si256(row0, mask); 49 | let row1 = _mm256_and_si256(row1, mask); 50 | let row2 = _mm256_and_si256(row2, mask); 51 | let row3 = _mm256_and_si256(row3, mask); 52 | let row4 = _mm256_and_si256(row4, mask); 53 | 54 | acc0 = _mm256_xor_si256(acc0, row0); 55 | acc1 = _mm256_xor_si256(acc1, row1); 56 | acc2 = _mm256_xor_si256(acc2, row2); 57 | acc3 = _mm256_xor_si256(acc3, row3); 58 | acc4 = _mm256_xor_si256(acc4, row4); 59 | } 60 | 61 | // SAFETY: `z` is 18-words/1152-bits, requiring a partial write of the final 256-bit term 62 | _mm256_storeu_si256(z.as_mut_ptr().add(0).cast(), acc0); 63 | _mm256_storeu_si256(z.as_mut_ptr().add(4).cast(), acc1); 64 | _mm256_storeu_si256(z.as_mut_ptr().add(8).cast(), acc2); 65 | _mm256_storeu_si256(z.as_mut_ptr().add(12).cast(), acc3); 66 | 67 | let mut tmp = [0u64; 4]; 68 | // SAFETY: `tmp` is 256-bits 69 | _mm256_storeu_si256(tmp.as_mut_ptr().cast(), acc4); 70 | z[16..18].copy_from_slice(&tmp[0..2]); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/mod.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | pub(crate) mod aes; 5 | pub(crate) mod aes_gcm; 6 | pub(crate) mod bignum_add; 7 | pub(crate) mod bignum_add_p256; 8 | pub(crate) mod bignum_add_p384; 9 | pub(crate) mod bignum_bitsize; 10 | pub(crate) mod bignum_cmp_lt; 11 | pub(crate) mod bignum_coprime; 12 | pub(crate) mod bignum_copy_row_from_table; 13 | pub(crate) mod bignum_copy_row_from_table_16_avx2; 14 | pub(crate) mod bignum_copy_row_from_table_8n_avx2; 15 | pub(crate) mod bignum_copy_row_from_table_mux; 16 | pub(crate) mod bignum_ctz; 17 | pub(crate) mod bignum_demont; 18 | pub(crate) mod bignum_demont_p256; 19 | pub(crate) mod bignum_demont_p384; 20 | pub(crate) mod bignum_digitsize; 21 | pub(crate) mod bignum_emontredc_8n; 22 | pub(crate) mod bignum_eq; 23 | pub(crate) mod bignum_inv_p256; 24 | pub(crate) mod bignum_inv_p384; 25 | pub(crate) mod bignum_kmul_16_32; 26 | pub(crate) mod bignum_kmul_32_64; 27 | pub(crate) mod bignum_ksqr_16_32; 28 | pub(crate) mod bignum_ksqr_32_64; 29 | pub(crate) mod bignum_mod_n256; 30 | pub(crate) mod bignum_mod_n384; 31 | pub(crate) mod bignum_modadd; 32 | pub(crate) mod bignum_modinv; 33 | pub(crate) mod bignum_modsub; 34 | pub(crate) mod bignum_montifier; 35 | pub(crate) mod bignum_montmul; 36 | pub(crate) mod bignum_montmul_p256; 37 | pub(crate) mod bignum_montmul_p384; 38 | pub(crate) mod bignum_montredc; 39 | pub(crate) mod bignum_montsqr; 40 | pub(crate) mod bignum_montsqr_p256; 41 | pub(crate) mod bignum_montsqr_p384; 42 | pub(crate) mod bignum_mul; 43 | pub(crate) mod bignum_mux; 44 | pub(crate) mod bignum_neg_p256; 45 | pub(crate) mod bignum_neg_p384; 46 | pub(crate) mod bignum_negmodinv; 47 | pub(crate) mod bignum_optsub; 48 | pub(crate) mod bignum_point_select_p256; 49 | pub(crate) mod bignum_point_select_p384; 50 | pub(crate) mod bignum_shr_small; 51 | pub(crate) mod bignum_tomont_p256; 52 | pub(crate) mod bignum_tomont_p384; 53 | pub(crate) mod chacha20; 54 | pub(crate) mod cpu; 55 | pub(crate) mod curve25519_x25519; 56 | pub(crate) mod curve25519_x25519base; 57 | pub(crate) mod ghash; 58 | pub(crate) mod p256_montjadd; 59 | pub(crate) mod p256_montjdouble; 60 | pub(crate) mod p256_montjmixadd; 61 | pub(crate) mod p384_montjadd; 62 | pub(crate) mod p384_montjdouble; 63 | pub(crate) mod sha256; 64 | pub(crate) mod sha256_mux; 65 | pub(crate) mod sha512; 66 | pub(crate) mod sha512_mux; 67 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/sha256_mux.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use crate::low::generic; 5 | use crate::low::x86_64; 6 | 7 | pub(crate) fn sha256_compress_blocks(state: &mut [u32; 8], blocks: &[u8]) { 8 | if x86_64::cpu::have_cpu_feature!("sha") { 9 | x86_64::sha256::sha256_compress_blocks_shaext(state, blocks) 10 | } else { 11 | generic::sha256::sha256_compress_blocks(state, blocks) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /graviola/src/low/x86_64/sha512_mux.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use crate::low::generic; 5 | use crate::low::x86_64; 6 | 7 | pub(crate) fn sha512_compress_blocks(state: &mut [u64; 8], blocks: &[u8]) { 8 | // nb. avx2 is in our required set. 9 | if x86_64::cpu::have_cpu_feature!("bmi2") { 10 | x86_64::sha512::sha512_compress_blocks(state, blocks) 11 | } else { 12 | generic::sha512::sha512_compress_blocks(state, blocks) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /graviola/src/mid/mod.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | #![deny(unsafe_code)] 5 | 6 | pub(super) mod aes_gcm; 7 | pub(super) mod chacha20poly1305; 8 | pub(super) mod p256; 9 | pub(super) mod p384; 10 | pub(super) mod rng; 11 | pub(super) mod rsa_priv; 12 | pub(super) mod rsa_pub; 13 | pub mod sha2; 14 | pub(super) mod util; 15 | pub(super) mod x25519; 16 | pub(super) mod xchacha20poly1305; 17 | -------------------------------------------------------------------------------- /graviola/src/mid/rng.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | #[cfg(test)] 5 | use core::mem; 6 | 7 | use crate::Error; 8 | 9 | /// The library's external and internal trait for all 10 | /// random consumption. 11 | pub trait RandomSource { 12 | fn fill(&mut self, out: &mut [u8]) -> Result<(), Error>; 13 | } 14 | 15 | /// Random generation from the system entropy source via 16 | /// the `getrandom` crate. 17 | pub(crate) struct SystemRandom; 18 | 19 | impl RandomSource for SystemRandom { 20 | fn fill(&mut self, out: &mut [u8]) -> Result<(), Error> { 21 | getrandom::fill(out).map_err(|_| Error::RngFailed) 22 | } 23 | } 24 | 25 | /// Random generation from a slice. 26 | /// 27 | /// Returns an error once exhausted. Intended only for testing. 28 | #[cfg(test)] 29 | pub(crate) struct SliceRandomSource<'a>(pub &'a [u8]); 30 | 31 | #[cfg(test)] 32 | impl RandomSource for SliceRandomSource<'_> { 33 | fn fill(&mut self, out: &mut [u8]) -> Result<(), Error> { 34 | if out.len() > self.0.len() { 35 | return Err(Error::RngFailed); 36 | } 37 | 38 | let (chunk, rest) = self.0.split_at(out.len()); 39 | self.0 = rest; 40 | out.copy_from_slice(chunk); 41 | Ok(()) 42 | } 43 | } 44 | 45 | /// Random generation from two subsources. 46 | /// 47 | /// The first subsource is used first, until it returns an error. 48 | /// Then the second is used for all subsequent requests. 49 | /// 50 | /// Intended only for testing. 51 | #[cfg(test)] 52 | pub(crate) enum ChainRandomSource<'a> { 53 | First(&'a mut dyn RandomSource, &'a mut dyn RandomSource), 54 | Rest(&'a mut dyn RandomSource), 55 | Dead, 56 | } 57 | 58 | #[cfg(test)] 59 | impl RandomSource for ChainRandomSource<'_> { 60 | fn fill(&mut self, out: &mut [u8]) -> Result<(), Error> { 61 | let taken = mem::replace(self, Self::Dead); 62 | *self = match taken { 63 | ChainRandomSource::First(source, rest) => match source.fill(out) { 64 | Ok(()) => Self::First(source, rest), 65 | Err(_) => { 66 | rest.fill(out)?; 67 | ChainRandomSource::Rest(rest) 68 | } 69 | }, 70 | ChainRandomSource::Rest(source) => { 71 | source.fill(out)?; 72 | Self::Rest(source) 73 | } 74 | ChainRandomSource::Dead => return Err(Error::RngFailed), 75 | }; 76 | Ok(()) 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /graviola/src/mid/util.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | // Once const generics is completed this should be able to be 5 | // done better that way. 6 | 7 | macro_rules! little_endian { 8 | ([u64; $N:literal], $fn_array_to:ident, $fn_slice_to:ident, $fn_to_bytes:ident) => { 9 | pub(crate) fn $fn_array_to(b: &[u8; $N * 8]) -> [u64; $N] { 10 | let mut r = [0; $N]; 11 | for (ir, b) in (0..$N).zip(b.chunks_exact(8)) { 12 | r[ir] = u64::from_le_bytes(b.try_into().unwrap()); 13 | } 14 | r 15 | } 16 | 17 | pub(crate) fn $fn_slice_to(bytes: &[u8]) -> Option<[u64; $N]> { 18 | let as_array: [u8; $N * 8] = bytes.try_into().ok()?; 19 | Some($fn_array_to(&as_array)) 20 | } 21 | 22 | pub(crate) fn $fn_to_bytes(v: &[u64; $N]) -> [u8; $N * 8] { 23 | let mut r = [0u8; $N * 8]; 24 | for (iv, rb) in (0..$N).zip(r.chunks_exact_mut(8)) { 25 | rb.copy_from_slice(&v[iv].to_le_bytes()); 26 | } 27 | r 28 | } 29 | }; 30 | } 31 | 32 | little_endian!( 33 | [u64; 4], 34 | little_endian_to_u64x4, 35 | little_endian_slice_to_u64x4, 36 | u64x4_to_little_endian 37 | ); 38 | 39 | macro_rules! big_endian { 40 | ([u64; $N:literal], $fn_array_to:ident, $fn_slice_to:ident, $fn_slice_any_size_to:ident, $fn_to_bytes:ident) => { 41 | pub(crate) fn $fn_array_to(b: &[u8; $N * 8]) -> [u64; $N] { 42 | let mut r = [0; $N]; 43 | for (ir, b) in (0..$N).zip(b.chunks_exact(8).rev()) { 44 | r[ir] = u64::from_be_bytes(b.try_into().unwrap()); 45 | } 46 | r 47 | } 48 | 49 | pub(crate) fn $fn_slice_to(bytes: &[u8]) -> Option<[u64; $N]> { 50 | let as_array: [u8; $N * 8] = bytes.try_into().ok()?; 51 | Some($fn_array_to(&as_array)) 52 | } 53 | 54 | pub(crate) fn $fn_slice_any_size_to(bytes: &[u8]) -> Option<[u64; $N]> { 55 | // short circuit for correct lengths 56 | if let Ok(array) = bytes.try_into() { 57 | return Some($fn_array_to(array)); 58 | } 59 | 60 | fn add_leading_zeroes(bytes: &[u8]) -> [u64; $N] { 61 | let mut tmp = [0u8; $N * 8]; 62 | tmp[$N * 8 - bytes.len()..].copy_from_slice(bytes); 63 | $fn_array_to(&tmp) 64 | } 65 | 66 | fn remove_leading_zeroes(mut bytes: &[u8]) -> Option<[u64; $N]> { 67 | loop { 68 | // remove the next leading zero 69 | match bytes.split_first() { 70 | Some((first, remain)) if *first == 0x00 => { 71 | if let Ok(array) = remain.try_into() { 72 | return Some($fn_array_to(array)); 73 | } 74 | bytes = remain; 75 | } 76 | _ => return None, 77 | } 78 | } 79 | } 80 | 81 | if bytes.len() < $N * 8 { 82 | Some(add_leading_zeroes(bytes)) 83 | } else { 84 | remove_leading_zeroes(bytes) 85 | } 86 | } 87 | 88 | pub(crate) fn $fn_to_bytes(v: &[u64; $N]) -> [u8; $N * 8] { 89 | let mut r = [0u8; $N * 8]; 90 | for (iv, rb) in (0..$N).zip(r.chunks_exact_mut(8).rev()) { 91 | rb.copy_from_slice(&v[iv].to_be_bytes()); 92 | } 93 | r 94 | } 95 | }; 96 | } 97 | 98 | big_endian!( 99 | [u64; 4], 100 | big_endian_to_u64x4, 101 | big_endian_slice_to_u64x4, 102 | big_endian_slice_any_size_to_u64x4, 103 | u64x4_to_big_endian 104 | ); 105 | big_endian!( 106 | [u64; 6], 107 | big_endian_to_u64x6, 108 | big_endian_slice_to_u64x6, 109 | big_endian_slice_any_size_to_u64x6, 110 | u64x6_to_big_endian 111 | ); 112 | -------------------------------------------------------------------------------- /graviola/src/test.rs: -------------------------------------------------------------------------------- 1 | // Written for Graviola by Joe Birr-Pixton, 2024. 2 | // SPDX-License-Identifier: Apache-2.0 OR ISC OR MIT-0 3 | 4 | use std::fs::File; 5 | use std::io::{BufRead, BufReader}; 6 | use std::path::Path; 7 | 8 | pub(crate) trait CavpSink { 9 | fn on_meta(&mut self, meta: &str); 10 | fn on_value(&mut self, name: &str, value: Value<'_>); 11 | } 12 | 13 | #[derive(Debug)] 14 | pub(crate) struct Value<'a>(&'a str); 15 | 16 | impl Value<'_> { 17 | pub(crate) fn bytes(&self) -> Vec { 18 | if self.0.len() % 2 == 0 { 19 | (0..self.0.len()) 20 | .step_by(2) 21 | .map(|i| u8::from_str_radix(&self.0[i..i + 2], 16).unwrap()) 22 | .collect() 23 | } else { 24 | let mut buf = self.0.to_string(); 25 | buf.insert(0, '0'); 26 | (0..buf.len()) 27 | .step_by(2) 28 | .map(|i| u8::from_str_radix(&buf[i..i + 2], 16).unwrap()) 29 | .collect() 30 | } 31 | } 32 | 33 | pub(crate) fn int(&self) -> u64 { 34 | self.0.parse::().unwrap() 35 | } 36 | 37 | pub(crate) fn str(&self) -> &str { 38 | self.0 39 | } 40 | } 41 | 42 | pub(crate) fn process_cavp(filename: impl AsRef, sink: &mut dyn CavpSink) { 43 | let f = File::open(filename).expect("cannot open {filename}"); 44 | for line in BufReader::new(f).lines() { 45 | let line = line.unwrap(); 46 | 47 | match line.chars().next() { 48 | Some('[') => { 49 | let right = line.rfind(']').expect("missing ] for meta"); 50 | sink.on_meta(&line[1..right]); 51 | continue; 52 | } 53 | Some('#') => { 54 | println!("{line}"); 55 | continue; 56 | } 57 | None => continue, 58 | _ => {} 59 | }; 60 | 61 | if let Some(equal_idx) = line.find(" = ") { 62 | let name = &line[..equal_idx]; 63 | let value = &line[equal_idx + 3..]; 64 | 65 | sink.on_value(name, Value(value)); 66 | } else { 67 | sink.on_value(&line, Value("")); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /graviola/src/testdata/aes-gcm-ciphertext.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ctz/graviola/397ecf708b3b5683005f86890491660a3396bbbb/graviola/src/testdata/aes-gcm-ciphertext.bin -------------------------------------------------------------------------------- /graviola/src/testdata/rsa.phi-not-coprime-e.2048.txt: -------------------------------------------------------------------------------- 1 | f68be4166c4bf00a01261d1d51e8a3da28da241cd07d2eb50696c14e7e02de7f83250b669842b0d3cb77e926408377b47b7ed01d54d8ad2ec57a453c3eca57b8faf1caf84c94e383351a0ad2ee179be14c9170b63e6328062689f5569e6cfe4524cd3bff0c2abb7de6d4a80827c1b2cd180e23a8b84a21cee5cd0a9be7306a9d 2 | e58b13cc5ae5cf25e685f0c6b5c8eee7d2f3a2a54f3b7520d64d30c36e476f0a42c8183f84695537c94001633d560aa16c8edcc990ff0f30869d7ddab426500763aebf8d27ccfca872696872316e6a378323d9a9a8fa256d16f70601e7b519c22daf63126caf2642253de823ab3d575ee84445bc5bb9aa1df2ae9cb624d0b963 3 | -------------------------------------------------------------------------------- /graviola/tests/crosschecks.rs: -------------------------------------------------------------------------------- 1 | use aws_lc_rs::rsa::KeyPair; 2 | use graviola::signing::rsa::{KeySize, SigningKey}; 3 | 4 | #[test] 5 | fn rsa_2048_key_generation() { 6 | check_key_generation(KeySize::Rsa2048); 7 | } 8 | 9 | #[test] 10 | fn rsa_2048_key_generation_soak() { 11 | if std::env::var_os("SLOW_TESTS").is_some() { 12 | for _ in 0..512 { 13 | check_key_generation(KeySize::Rsa2048); 14 | } 15 | } 16 | } 17 | 18 | #[test] 19 | fn rsa_3072_key_generation() { 20 | check_key_generation(KeySize::Rsa3072); 21 | } 22 | 23 | #[test] 24 | fn rsa_4096_key_generation() { 25 | check_key_generation(KeySize::Rsa4096); 26 | } 27 | 28 | #[test] 29 | fn rsa_6144_key_generation() { 30 | if std::env::var_os("SLOW_TESTS").is_some() { 31 | check_key_generation(KeySize::Rsa6144); 32 | } 33 | } 34 | 35 | #[test] 36 | fn rsa_8192_key_generation() { 37 | if std::env::var_os("SLOW_TESTS").is_some() { 38 | check_key_generation(KeySize::Rsa8192); 39 | } 40 | } 41 | 42 | fn check_key_generation(size: KeySize) { 43 | let key = SigningKey::generate(size).unwrap(); 44 | let mut buf = [0u8; 8192]; 45 | let key_enc = key.to_pkcs8_der(&mut buf).unwrap(); 46 | 47 | KeyPair::from_pkcs8(key_enc).expect("aws-lc-rs rejected a key we generated"); 48 | } 49 | -------------------------------------------------------------------------------- /rustls-graviola/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "rustls-graviola" 3 | version = "0.2.1" 4 | edition = "2021" 5 | repository = "https://github.com/ctz/graviola/" 6 | license = "Apache-2.0 OR ISC OR MIT-0" 7 | description = "graviola is a modern, fast cryptography library" 8 | categories = ["network-programming", "cryptography"] 9 | rust-version = "1.72" 10 | readme = "README.md" 11 | 12 | [dependencies] 13 | graviola = { version = "0.2.1", path = "../graviola" } 14 | rustls = { version = "0.23.18", default-features = false, features = ["std", "tls12"] } 15 | 16 | [dev-dependencies] 17 | env_logger = "0.11" 18 | http = "1" 19 | http-body-util = "0.1" 20 | hyper = { version = "1", default-features = false } 21 | hyper-rustls = { version = "0.27", default-features = false, features = ["native-tokio", "http1", "tls12", "logging"] } 22 | hyper-util = { version = "0.1", default-features = false, features = ["server-auto"] } 23 | rustls = { version = "0.23.23", default-features = false, features = ["ring"] } 24 | rustls-pemfile = "2" 25 | tokio = { version = "1.0", features = ["io-std", "macros", "net", "rt-multi-thread"] } 26 | tokio-rustls = { version = "0.26", default-features = false } 27 | -------------------------------------------------------------------------------- /rustls-graviola/README.md: -------------------------------------------------------------------------------- 1 |

rustls-graviola

2 | 3 | 4 | [![Latest release](https://img.shields.io/crates/v/rustls-graviola)](https://crates.io/crates/rustls-graviola) 5 | [![Documentation](https://img.shields.io/docsrs/rustls-graviola)](https://docs.rs/rustls-graviola/) 6 | 7 | This crate provides an integration between [rustls](https://github.com/rustls/rustls) and [Graviola](https://github.com/ctz/graviola/). 8 | 9 | Use it like: 10 | 11 | ```rust 12 | rustls_graviola::default_provider() 13 | .install_default() 14 | .unwrap(); 15 | ``` 16 | 17 | And then use rustls as normal. 18 | 19 | License: Apache-2.0 OR ISC OR MIT-0 20 | -------------------------------------------------------------------------------- /rustls-graviola/examples/client.rs: -------------------------------------------------------------------------------- 1 | //! Simple HTTPS GET client based on hyper-rustls 2 | //! 3 | //! First parameter is the mandatory URL to GET. 4 | //! Second parameter is an optional path to CA store. 5 | 6 | use std::str::FromStr; 7 | use std::{env, fs, io}; 8 | 9 | use http::Uri; 10 | use http_body_util::{BodyExt, Empty}; 11 | use hyper::body::Bytes; 12 | use hyper_rustls::ConfigBuilderExt; 13 | use hyper_util::{client::legacy::Client, rt::TokioExecutor}; 14 | use rustls::RootCertStore; 15 | 16 | fn main() { 17 | // Send GET request and inspect result, with proper error handling. 18 | if let Err(e) = run_client() { 19 | eprintln!("FAILED: {}", e); 20 | std::process::exit(1); 21 | } 22 | } 23 | 24 | fn error(err: String) -> io::Error { 25 | io::Error::new(io::ErrorKind::Other, err) 26 | } 27 | 28 | #[tokio::main] 29 | async fn run_client() -> io::Result<()> { 30 | // Set a process wide default crypto provider. 31 | rustls_graviola::default_provider() 32 | .install_default() 33 | .unwrap(); 34 | env_logger::init(); 35 | 36 | // First parameter is target URL (mandatory). 37 | let url = match env::args().nth(1) { 38 | Some(ref url) => Uri::from_str(url).map_err(|e| error(format!("{}", e)))?, 39 | None => { 40 | println!("Usage: client "); 41 | return Ok(()); 42 | } 43 | }; 44 | 45 | // Second parameter is custom Root-CA store (optional, defaults to native cert store). 46 | let mut ca = match env::args().nth(2) { 47 | Some(ref path) => { 48 | let f = fs::File::open(path) 49 | .map_err(|e| error(format!("failed to open {}: {}", path, e)))?; 50 | let rd = io::BufReader::new(f); 51 | Some(rd) 52 | } 53 | None => None, 54 | }; 55 | 56 | // Prepare the TLS client config 57 | let tls = match ca { 58 | Some(ref mut rd) => { 59 | // Read trust roots 60 | let certs = rustls_pemfile::certs(rd).collect::, _>>()?; 61 | let mut roots = RootCertStore::empty(); 62 | roots.add_parsable_certificates(certs); 63 | // TLS client config using the custom CA store for lookups 64 | rustls::ClientConfig::builder() 65 | .with_root_certificates(roots) 66 | .with_no_client_auth() 67 | } 68 | // Default TLS client config with native roots 69 | None => rustls::ClientConfig::builder() 70 | .with_native_roots()? 71 | .with_no_client_auth(), 72 | }; 73 | // Prepare the HTTPS connector 74 | let https = hyper_rustls::HttpsConnectorBuilder::new() 75 | .with_tls_config(tls) 76 | .https_or_http() 77 | .enable_http1() 78 | .build(); 79 | 80 | // Build the hyper client from the HTTPS connector. 81 | let client: Client<_, Empty> = Client::builder(TokioExecutor::new()).build(https); 82 | 83 | // Prepare a chain of futures which sends a GET request, inspects 84 | // the returned headers, collects the whole body and prints it to 85 | // stdout. 86 | let fut = async move { 87 | let res = client 88 | .get(url) 89 | .await 90 | .map_err(|e| error(format!("Could not get: {:?}", e)))?; 91 | println!("Status:\n{}", res.status()); 92 | println!("Headers:\n{:#?}", res.headers()); 93 | 94 | let body = res 95 | .into_body() 96 | .collect() 97 | .await 98 | .map_err(|e| error(format!("Could not get body: {:?}", e)))? 99 | .to_bytes(); 100 | println!("Body:\n{}", String::from_utf8_lossy(&body)); 101 | 102 | Ok(()) 103 | }; 104 | 105 | fut.await 106 | } 107 | -------------------------------------------------------------------------------- /rustls-graviola/src/hash.rs: -------------------------------------------------------------------------------- 1 | use graviola::hashing::sha2; 2 | use rustls::crypto::hash; 3 | 4 | pub struct Sha256; 5 | 6 | impl hash::Hash for Sha256 { 7 | fn start(&self) -> Box { 8 | Box::new(Sha256Context(sha2::Sha256Context::new())) 9 | } 10 | 11 | fn hash(&self, data: &[u8]) -> hash::Output { 12 | let mut ctx = sha2::Sha256Context::new(); 13 | ctx.update(data); 14 | 15 | hash::Output::new(ctx.finish().as_ref()) 16 | } 17 | 18 | fn algorithm(&self) -> hash::HashAlgorithm { 19 | hash::HashAlgorithm::SHA256 20 | } 21 | 22 | fn output_len(&self) -> usize { 23 | sha2::Sha256Context::OUTPUT_SZ 24 | } 25 | } 26 | 27 | struct Sha256Context(sha2::Sha256Context); 28 | 29 | impl hash::Context for Sha256Context { 30 | fn fork_finish(&self) -> hash::Output { 31 | hash::Output::new(self.0.clone().finish().as_ref()) 32 | } 33 | 34 | fn fork(&self) -> Box { 35 | Box::new(Self(self.0.clone())) 36 | } 37 | 38 | fn finish(self: Box) -> hash::Output { 39 | hash::Output::new(self.0.finish().as_ref()) 40 | } 41 | 42 | fn update(&mut self, data: &[u8]) { 43 | self.0.update(data); 44 | } 45 | } 46 | 47 | pub struct Sha384; 48 | 49 | impl hash::Hash for Sha384 { 50 | fn start(&self) -> Box { 51 | Box::new(Sha384Context(sha2::Sha384Context::new())) 52 | } 53 | 54 | fn hash(&self, data: &[u8]) -> hash::Output { 55 | let mut ctx = sha2::Sha384Context::new(); 56 | ctx.update(data); 57 | 58 | hash::Output::new(ctx.finish().as_ref()) 59 | } 60 | 61 | fn algorithm(&self) -> hash::HashAlgorithm { 62 | hash::HashAlgorithm::SHA384 63 | } 64 | 65 | fn output_len(&self) -> usize { 66 | sha2::Sha384Context::OUTPUT_SZ 67 | } 68 | } 69 | 70 | struct Sha384Context(sha2::Sha384Context); 71 | 72 | impl hash::Context for Sha384Context { 73 | fn fork_finish(&self) -> hash::Output { 74 | hash::Output::new(self.0.clone().finish().as_ref()) 75 | } 76 | 77 | fn fork(&self) -> Box { 78 | Box::new(Self(self.0.clone())) 79 | } 80 | 81 | fn finish(self: Box) -> hash::Output { 82 | hash::Output::new(self.0.finish().as_ref()) 83 | } 84 | 85 | fn update(&mut self, data: &[u8]) { 86 | self.0.update(data); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /rustls-graviola/src/hmac.rs: -------------------------------------------------------------------------------- 1 | use graviola::hashing::hmac::Hmac; 2 | use graviola::hashing::{Sha256, Sha384}; 3 | use rustls::crypto; 4 | 5 | pub struct Sha256Hmac; 6 | 7 | impl crypto::hmac::Hmac for Sha256Hmac { 8 | fn with_key(&self, key: &[u8]) -> Box { 9 | Box::new(Sha256HmacKey(Hmac::::new(key))) 10 | } 11 | 12 | fn hash_output_len(&self) -> usize { 13 | SHA256_OUTPUT 14 | } 15 | } 16 | 17 | struct Sha256HmacKey(Hmac); 18 | 19 | impl crypto::hmac::Key for Sha256HmacKey { 20 | fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag { 21 | let mut ctx = self.0.clone(); 22 | ctx.update(first); 23 | for m in middle { 24 | ctx.update(m); 25 | } 26 | ctx.update(last); 27 | crypto::hmac::Tag::new(ctx.finish().as_ref()) 28 | } 29 | 30 | fn tag_len(&self) -> usize { 31 | SHA256_OUTPUT 32 | } 33 | } 34 | 35 | pub struct Sha384Hmac; 36 | 37 | impl crypto::hmac::Hmac for Sha384Hmac { 38 | fn with_key(&self, key: &[u8]) -> Box { 39 | Box::new(Sha384HmacKey(Hmac::::new(key))) 40 | } 41 | 42 | fn hash_output_len(&self) -> usize { 43 | SHA384_OUTPUT 44 | } 45 | } 46 | 47 | struct Sha384HmacKey(Hmac); 48 | 49 | impl crypto::hmac::Key for Sha384HmacKey { 50 | fn sign_concat(&self, first: &[u8], middle: &[&[u8]], last: &[u8]) -> crypto::hmac::Tag { 51 | let mut ctx = self.0.clone(); 52 | ctx.update(first); 53 | for m in middle { 54 | ctx.update(m); 55 | } 56 | ctx.update(last); 57 | crypto::hmac::Tag::new(ctx.finish().as_ref()) 58 | } 59 | 60 | fn tag_len(&self) -> usize { 61 | SHA384_OUTPUT 62 | } 63 | } 64 | 65 | const SHA256_OUTPUT: usize = 32; 66 | const SHA384_OUTPUT: usize = 48; 67 | -------------------------------------------------------------------------------- /rustls-graviola/src/lib.rs: -------------------------------------------------------------------------------- 1 | //!

Graviola

2 | //! 3 | //! 4 | //! This crate provides an integration between [rustls](https://github.com/rustls/rustls) and [Graviola](https://github.com/ctz/graviola/). 5 | //! 6 | //! Use it like: 7 | //! 8 | //! ```rust 9 | //! rustls_graviola::default_provider() 10 | //! .install_default() 11 | //! .unwrap(); 12 | //! ``` 13 | //! 14 | //! And then use rustls as normal. 15 | 16 | use rustls::crypto::CryptoProvider; 17 | 18 | mod aead; 19 | mod hash; 20 | mod hmac; 21 | mod sign; 22 | mod verify; 23 | 24 | /// Supported key exchange algorithms. 25 | pub mod kx; 26 | 27 | /// Supported cipher suites. 28 | pub mod suites; 29 | 30 | mod ticketer; 31 | pub use ticketer::Ticketer; 32 | 33 | /// This is a rustls [`CryptoProvider`] using cryptography from Graviola. 34 | /// 35 | /// This provides the same algorithms as the rustls *ring*-based 36 | /// provider, which are interoperable and safe defaults for modern TLS. 37 | pub fn default_provider() -> CryptoProvider { 38 | CryptoProvider { 39 | cipher_suites: suites::ALL_CIPHER_SUITES.to_vec(), 40 | kx_groups: kx::ALL_KX_GROUPS.to_vec(), 41 | signature_verification_algorithms: verify::ALGORITHMS, 42 | secure_random: &RngProvider, 43 | key_provider: &sign::Provider, 44 | } 45 | } 46 | 47 | #[derive(Debug)] 48 | struct RngProvider; 49 | 50 | impl rustls::crypto::SecureRandom for RngProvider { 51 | fn fill(&self, bytes: &mut [u8]) -> Result<(), rustls::crypto::GetRandomFailed> { 52 | graviola::random::fill(bytes).map_err(|_| rustls::crypto::GetRandomFailed) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/ecdsa-p256/ca.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIBuDCCAV2gAwIBAgIBBDAKBggqhkjOPQQDAjAhMR8wHQYDVQQDDBZwb255dG93 3 | biBFQ0RTQSBwMjU2IENBMCAXDTc1MDEwMTAwMDAwMFoYDzQwOTYwMTAxMDAwMDAw 4 | WjAhMR8wHQYDVQQDDBZwb255dG93biBFQ0RTQSBwMjU2IENBMFkwEwYHKoZIzj0C 5 | AQYIKoZIzj0DAQcDQgAErHuPs1bVNMzbscPJcYhYsGVyi/ucclzRfj5QUm++2X8A 6 | rVqSzt92eQVZkgxYLewAAFUcZ7k7nRZz2zzfxw/qmKOBgzCBgDAfBgNVHSMEGDAW 7 | gBRWWeTz8Uf6fshoCzFD9RV9EjTIbjAOBgNVHQ8BAf8EBAMCAf4wHQYDVR0lBBYw 8 | FAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBRWWeTz8Uf6fshoCzFD9RV9 9 | EjTIbjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDBmJU916e5 10 | 63lKUYQg0GRb6wYVzM6uvR76e9fdNRP2AAIhAMzkXakQh48X9UmeRS+EacOXbTFh 11 | mvp3AZF3KBMrZMCF 12 | -----END CERTIFICATE----- 13 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/ecdsa-p256/end.fullchain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIBxzCCAW2gAwIBAgIBEjAKBggqhkjOPQQDAjAzMTEwLwYDVQQDDChwb255dG93 3 | biBFQ0RTQSBwMjU2IGxldmVsIDIgaW50ZXJtZWRpYXRlMCAXDTc1MDEwMTAwMDAw 4 | MFoYDzQwOTYwMTAxMDAwMDAwWjAZMRcwFQYDVQQDDA50ZXN0c2VydmVyLmNvbTBZ 5 | MBMGByqGSM49AgEGCCqGSM49AwEHA0IABLNSstLp9UFX3q/e7sp7A9+XNxq5TAI5 6 | atI0dtac82ed8WTieUAdIZzodiqolHs6eJWFRHdqf7VtOkgnEWfekC6jgYkwgYYw 7 | HwYDVR0jBBgwFoAUJjMYkSu1NZYglNZvdKzw3V1Xqc4wUwYDVR0RBEwwSoIOdGVz 8 | dHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJbG9jYWxob3N0hwTG 9 | M2QBhxAgAQ24AAAAAAAAAAAAAAABMA4GA1UdDwEB/wQEAwIGwDAKBggqhkjOPQQD 10 | AgNIADBFAiALMVfJ3mkvNMKr9pbwx9V5TcNHW6Yh3603hvlxuYuhlwIhAKI1zeMS 11 | r57S+4oeh23LfDTQZ90jUFhlym+/qY53THTd 12 | -----END CERTIFICATE----- 13 | -----BEGIN CERTIFICATE----- 14 | MIIByTCCAW+gAwIBAgIBCzAKBggqhkjOPQQDAjAhMR8wHQYDVQQDDBZwb255dG93 15 | biBFQ0RTQSBwMjU2IENBMCAXDTc1MDEwMTAwMDAwMFoYDzQwOTYwMTAxMDAwMDAw 16 | WjAzMTEwLwYDVQQDDChwb255dG93biBFQ0RTQSBwMjU2IGxldmVsIDIgaW50ZXJt 17 | ZWRpYXRlMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEC+U48MSA/hZEt0hF28PF 18 | 5E/WUojUMtwFFvjVjCHXKF9t2nKJA3BQjPcgQx8ijN2VdTlzxXO/7mWE/VNy3U2A 19 | fKOBgzCBgDAfBgNVHSMEGDAWgBRWWeTz8Uf6fshoCzFD9RV9EjTIbjAOBgNVHQ8B 20 | Af8EBAMCAf4wHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQW 21 | BBQmMxiRK7U1liCU1m90rPDdXVepzjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49 22 | BAMCA0gAMEUCIELRdy4pOTv6bJVtdtHpZrYSPd5hSqdwFtXd9nUW2skuAiEAjKPW 23 | uhC357m842cYo511pz/cvnDZ8RMrdjDtyKB4jMI= 24 | -----END CERTIFICATE----- 25 | -----BEGIN CERTIFICATE----- 26 | MIIBuDCCAV2gAwIBAgIBBDAKBggqhkjOPQQDAjAhMR8wHQYDVQQDDBZwb255dG93 27 | biBFQ0RTQSBwMjU2IENBMCAXDTc1MDEwMTAwMDAwMFoYDzQwOTYwMTAxMDAwMDAw 28 | WjAhMR8wHQYDVQQDDBZwb255dG93biBFQ0RTQSBwMjU2IENBMFkwEwYHKoZIzj0C 29 | AQYIKoZIzj0DAQcDQgAErHuPs1bVNMzbscPJcYhYsGVyi/ucclzRfj5QUm++2X8A 30 | rVqSzt92eQVZkgxYLewAAFUcZ7k7nRZz2zzfxw/qmKOBgzCBgDAfBgNVHSMEGDAW 31 | gBRWWeTz8Uf6fshoCzFD9RV9EjTIbjAOBgNVHQ8BAf8EBAMCAf4wHQYDVR0lBBYw 32 | FAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBRWWeTz8Uf6fshoCzFD9RV9 33 | EjTIbjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0kAMEYCIQDBmJU916e5 34 | 63lKUYQg0GRb6wYVzM6uvR76e9fdNRP2AAIhAMzkXakQh48X9UmeRS+EacOXbTFh 35 | mvp3AZF3KBMrZMCF 36 | -----END CERTIFICATE----- 37 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/ecdsa-p256/end.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQg6/t0qPJISdL4wsdU 3 | s/8C3LHzQLD2YbXlCNBESUPnuc+hRANCAASzUrLS6fVBV96v3u7KewPflzcauUwC 4 | OWrSNHbWnPNnnfFk4nlAHSGc6HYqqJR7OniVhUR3an+1bTpIJxFn3pAu 5 | -----END PRIVATE KEY----- 6 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/ecdsa-p384/ca.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIB8zCCAXqgAwIBAgIBBTAKBggqhkjOPQQDAzAhMR8wHQYDVQQDDBZwb255dG93 3 | biBFQ0RTQSBwMzg0IENBMCAXDTc1MDEwMTAwMDAwMFoYDzQwOTYwMTAxMDAwMDAw 4 | WjAhMR8wHQYDVQQDDBZwb255dG93biBFQ0RTQSBwMzg0IENBMHYwEAYHKoZIzj0C 5 | AQYFK4EEACIDYgAEaVm81FCW/VZ07c4P+cgoswKN9dGEAYVAkaPlTKq5eUoRLXdS 6 | YFeZn6iOYl1GzaMkHsP/5Qo98w6bsX3jQC2T5+wjgJAsoA2D+4POY5pV89/BX9HQ 7 | CaBrxEpLJ9YLkn6bo4GDMIGAMB8GA1UdIwQYMBaAFIcrjZU3WJ1Ka17rQPv29Hxc 8 | BOISMA4GA1UdDwEB/wQEAwIB/jAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH 9 | AwIwHQYDVR0OBBYEFIcrjZU3WJ1Ka17rQPv29HxcBOISMA8GA1UdEwEB/wQFMAMB 10 | Af8wCgYIKoZIzj0EAwMDZwAwZAIwfkd5ldIN/aAK1rlrzXTxsRxWuZ9XJeKqnLhV 11 | q4IqPgD8yakSoIbDi1dme5TDKJ+KAjAUWqvG2+SV9OavTSNN3NsX3dEDAv0wq3HZ 12 | V9nvAn0eY0WgIQdnz4A5ln769kgl2X4= 13 | -----END CERTIFICATE----- 14 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/ecdsa-p384/end.fullchain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICAzCCAYqgAwIBAgIBEzAKBggqhkjOPQQDAzAzMTEwLwYDVQQDDChwb255dG93 3 | biBFQ0RTQSBwMzg0IGxldmVsIDIgaW50ZXJtZWRpYXRlMCAXDTc1MDEwMTAwMDAw 4 | MFoYDzQwOTYwMTAxMDAwMDAwWjAZMRcwFQYDVQQDDA50ZXN0c2VydmVyLmNvbTB2 5 | MBAGByqGSM49AgEGBSuBBAAiA2IABA1Gf+aA3FaK5lNjO1Tsz/JbxZkVfpm99Wz8 6 | 1ZU1GAYOrOhNO0tX/pJDN0PM9D18TcepYwip5qpQwl8a57MSpHH6NpwrhU+5wlzT 7 | FwZzJ1NvFF26lexYzrMGKzbv+YS2PqOBiTCBhjAfBgNVHSMEGDAWgBTpk+KzOiQU 8 | 52eZdV+pdkkUmbQUJjBTBgNVHREETDBKgg50ZXN0c2VydmVyLmNvbYIVc2Vjb25k 9 | LnRlc3RzZXJ2ZXIuY29tgglsb2NhbGhvc3SHBMYzZAGHECABDbgAAAAAAAAAAAAA 10 | AAEwDgYDVR0PAQH/BAQDAgbAMAoGCCqGSM49BAMDA2cAMGQCMFAfZriC49peBoIh 11 | k7VoJ1yWT/VlecSmkTAeSx0EdoGDMMX3t0IM1ab0jdPmlVq/3wIwQ757f50+Ox3a 12 | E/3PhoJJr7R4dLGgNDK+omkIGgDsXsUbjq8bwnhRlGs8OrmPA/+8 13 | -----END CERTIFICATE----- 14 | -----BEGIN CERTIFICATE----- 15 | MIICBjCCAYygAwIBAgIBDDAKBggqhkjOPQQDAzAhMR8wHQYDVQQDDBZwb255dG93 16 | biBFQ0RTQSBwMzg0IENBMCAXDTc1MDEwMTAwMDAwMFoYDzQwOTYwMTAxMDAwMDAw 17 | WjAzMTEwLwYDVQQDDChwb255dG93biBFQ0RTQSBwMzg0IGxldmVsIDIgaW50ZXJt 18 | ZWRpYXRlMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEE2naCuthBdvG2KhmtKPax7ZV 19 | /c/wiT+co1n2QkhWDUkX43LZobKat11Y3dXcU5VTNRfBtUhUSlLRdKNs6UI68EnT 20 | ry3ygYHRyQu3J3aa5th7NFC+zhMpgmADsbDBwb2Zo4GDMIGAMB8GA1UdIwQYMBaA 21 | FIcrjZU3WJ1Ka17rQPv29HxcBOISMA4GA1UdDwEB/wQEAwIB/jAdBgNVHSUEFjAU 22 | BggrBgEFBQcDAQYIKwYBBQUHAwIwHQYDVR0OBBYEFOmT4rM6JBTnZ5l1X6l2SRSZ 23 | tBQmMA8GA1UdEwEB/wQFMAMBAf8wCgYIKoZIzj0EAwMDaAAwZQIwIH7M4PuJJnwD 24 | M9k8NF7wj81s7Vdu6Q6+pbPIXrsAxJAz6G7uPgYjggRRbrtHU53BAjEA+gCogZxd 25 | 0YeCxnnNUyfz5OQFs7QhBUQjOQNMZw2Jcp0iZtRrW1CSXaOtNRAXtMql 26 | -----END CERTIFICATE----- 27 | -----BEGIN CERTIFICATE----- 28 | MIIB8zCCAXqgAwIBAgIBBTAKBggqhkjOPQQDAzAhMR8wHQYDVQQDDBZwb255dG93 29 | biBFQ0RTQSBwMzg0IENBMCAXDTc1MDEwMTAwMDAwMFoYDzQwOTYwMTAxMDAwMDAw 30 | WjAhMR8wHQYDVQQDDBZwb255dG93biBFQ0RTQSBwMzg0IENBMHYwEAYHKoZIzj0C 31 | AQYFK4EEACIDYgAEaVm81FCW/VZ07c4P+cgoswKN9dGEAYVAkaPlTKq5eUoRLXdS 32 | YFeZn6iOYl1GzaMkHsP/5Qo98w6bsX3jQC2T5+wjgJAsoA2D+4POY5pV89/BX9HQ 33 | CaBrxEpLJ9YLkn6bo4GDMIGAMB8GA1UdIwQYMBaAFIcrjZU3WJ1Ka17rQPv29Hxc 34 | BOISMA4GA1UdDwEB/wQEAwIB/jAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH 35 | AwIwHQYDVR0OBBYEFIcrjZU3WJ1Ka17rQPv29HxcBOISMA8GA1UdEwEB/wQFMAMB 36 | Af8wCgYIKoZIzj0EAwMDZwAwZAIwfkd5ldIN/aAK1rlrzXTxsRxWuZ9XJeKqnLhV 37 | q4IqPgD8yakSoIbDi1dme5TDKJ+KAjAUWqvG2+SV9OavTSNN3NsX3dEDAv0wq3HZ 38 | V9nvAn0eY0WgIQdnz4A5ln769kgl2X4= 39 | -----END CERTIFICATE----- 40 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/ecdsa-p384/end.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDC8J5d2FlIl8mD21ZJA 3 | LHnuI33q0qAN1S+0ucwQoUsvO7mHB8OapQlPL06dAPpJJwahZANiAAQNRn/mgNxW 4 | iuZTYztU7M/yW8WZFX6ZvfVs/NWVNRgGDqzoTTtLV/6SQzdDzPQ9fE3HqWMIqeaq 5 | UMJfGuezEqRx+jacK4VPucJc0xcGcydTbxRdupXsWM6zBis27/mEtj4= 6 | -----END PRIVATE KEY----- 7 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/rsa-2048/ca.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDPzCCAiegAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRwb255 3 | dG93biBSU0EgMjA0OCBDQTAgFw03NTAxMDEwMDAwMDBaGA80MDk2MDEwMTAwMDAw 4 | MFowHzEdMBsGA1UEAwwUcG9ueXRvd24gUlNBIDIwNDggQ0EwggEiMA0GCSqGSIb3 5 | DQEBAQUAA4IBDwAwggEKAoIBAQCy4ZPzrQwfu3tz3ll0xHzlHtAQEHUyXzSo3VIn 6 | ULFPC9D84LWe9zpQBYGxOtl8OVcMdmEbzoIOHO6afNSnzbcQdZymJ4+FMpmusWdV 7 | CcWQ7Knu4Ok0mWlw7HXgtnhunjX0BRMy5M6WXWk6MH44G7n3DCQDINAJvGAwirIT 8 | kUfekbnwDCIEmIZNQQKyGdndn6mQGHt+oWdmgiWxI0dPjU/vsyFQDFomX2IF/fn4 9 | j/lKvhGPEccO/2zQThUrbVck1t7kRilCDZbShGav3+87h42mISriK5yqVOwPzPL4 10 | HWjIL+G2sMDY7RdFKQHBCY4Gis5rrLtOOhKtoDmos7oCCs1BAgMBAAGjgYMwgYAw 11 | HwYDVR0jBBgwFoAUZ8fKnr69bZrvOOQ1Jii60vG9ELYwDgYDVR0PAQH/BAQDAgH+ 12 | MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUZ8fKnr69 13 | bZrvOOQ1Jii60vG9ELYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC 14 | AQEAhTU7Iv/HBuSOaIAOTrgqbvwKUoZsGG0vb1DVOYINasnDDVx+celU9jvzSHRy 15 | +5kZUgflytZIy1TmE/RvQi8/vd2s6BL4DGF39VyFO49g746EcBUEmNGZFS0J/hVa 16 | iZj3yNO/tO5V3nzrGzTrrx9cRnFykLKE/qDnrIOfCiRk5KYui1M5JYBM61r3MDLA 17 | lrRCZh4u04jdNVHPF14km5VcgJvhpGkX2mpe3J9ZtOwBdc96e5zJ0PPKofAuVhuD 18 | J8t+QNnjXKSyf1Ud/5WAOKinqGK902mRAwEFISQko0OajUkUzjZabr6xnf4fYWId 19 | JPT9si0E6DxRUmBTQ0Dy4zU1AQ== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/rsa-2048/end.chain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDUTCCAjmgAwIBAgIBCDANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRwb255 3 | dG93biBSU0EgMjA0OCBDQTAgFw03NTAxMDEwMDAwMDBaGA80MDk2MDEwMTAwMDAw 4 | MFowMTEvMC0GA1UEAwwmcG9ueXRvd24gUlNBIDIwNDggbGV2ZWwgMiBpbnRlcm1l 5 | ZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPjnWAwXrjPM3N 6 | q2QmVaaxu5/EdMk5DCCTomaKYE9dEGa1hd+ZXuiqvdgX1J5jEn9RaTxY5gUcNVyT 7 | Utx6si7WqPTb+h1IBUT0hNZpXT7AOo4wbNg/9vjmTJ1GfX8EuLmaK+hkFH3IUGJL 8 | Mh7I47pIEo5WiPcb/tBT4fHN87vQdknT+S1K8BX1eGFDr+mmMbj2Kg5sxybAZmO4 9 | YbHeT1W1MKsewp/gBI3jZwXAtM3CDWrWMl/HXmiM01VVi57T/ZaUHIth5TOMIIkF 10 | wF52MeCFH9fHLgx3LJBTkeO76dbjn9CO6OwfvMmOzSJbDim9kAPB2FeM6xILGhKy 11 | T+Cq1k8dAgMBAAGjgYMwgYAwHwYDVR0jBBgwFoAUZ8fKnr69bZrvOOQ1Jii60vG9 12 | ELYwDgYDVR0PAQH/BAQDAgH+MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD 13 | AjAdBgNVHQ4EFgQUjGfueyc0aewV7xHMs0VoFAsF638wDwYDVR0TAQH/BAUwAwEB 14 | /zANBgkqhkiG9w0BAQsFAAOCAQEAiqcCAXqzbGQ08wxaWiUZ0ahZ2giTkGXgcluN 15 | P7LXnMgve3M1gac4XBHAnokuME33+ppxVvIiX8c0OxR8LUPPmKQTGMtivDbSTFJG 16 | UALdyol1xalNuCuX81rvd/UY8tV6UQg/PzJb6QZFAxeMrodhS/dcCyNVMLFbutyM 17 | Vq3RW+ZjIxY+RVSYiEqWvStcjga//ateG8ndUioAGsfX8cs3IVkHdSqCJ4YCgml0 18 | /scRGaep2uP6y+yW9XQGxDLI5FHIs5EVn5nmo23HfmvLw7fYIgGdguCJGnWzy+kS 19 | O2+9pDFibt7UieLOUKlxyw8PbtvHJrRVvy1ylgEaNLKncssxLg== 20 | -----END CERTIFICATE----- 21 | -----BEGIN CERTIFICATE----- 22 | MIIDPzCCAiegAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRwb255 23 | dG93biBSU0EgMjA0OCBDQTAgFw03NTAxMDEwMDAwMDBaGA80MDk2MDEwMTAwMDAw 24 | MFowHzEdMBsGA1UEAwwUcG9ueXRvd24gUlNBIDIwNDggQ0EwggEiMA0GCSqGSIb3 25 | DQEBAQUAA4IBDwAwggEKAoIBAQCy4ZPzrQwfu3tz3ll0xHzlHtAQEHUyXzSo3VIn 26 | ULFPC9D84LWe9zpQBYGxOtl8OVcMdmEbzoIOHO6afNSnzbcQdZymJ4+FMpmusWdV 27 | CcWQ7Knu4Ok0mWlw7HXgtnhunjX0BRMy5M6WXWk6MH44G7n3DCQDINAJvGAwirIT 28 | kUfekbnwDCIEmIZNQQKyGdndn6mQGHt+oWdmgiWxI0dPjU/vsyFQDFomX2IF/fn4 29 | j/lKvhGPEccO/2zQThUrbVck1t7kRilCDZbShGav3+87h42mISriK5yqVOwPzPL4 30 | HWjIL+G2sMDY7RdFKQHBCY4Gis5rrLtOOhKtoDmos7oCCs1BAgMBAAGjgYMwgYAw 31 | HwYDVR0jBBgwFoAUZ8fKnr69bZrvOOQ1Jii60vG9ELYwDgYDVR0PAQH/BAQDAgH+ 32 | MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUZ8fKnr69 33 | bZrvOOQ1Jii60vG9ELYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC 34 | AQEAhTU7Iv/HBuSOaIAOTrgqbvwKUoZsGG0vb1DVOYINasnDDVx+celU9jvzSHRy 35 | +5kZUgflytZIy1TmE/RvQi8/vd2s6BL4DGF39VyFO49g746EcBUEmNGZFS0J/hVa 36 | iZj3yNO/tO5V3nzrGzTrrx9cRnFykLKE/qDnrIOfCiRk5KYui1M5JYBM61r3MDLA 37 | lrRCZh4u04jdNVHPF14km5VcgJvhpGkX2mpe3J9ZtOwBdc96e5zJ0PPKofAuVhuD 38 | J8t+QNnjXKSyf1Ud/5WAOKinqGK902mRAwEFISQko0OajUkUzjZabr6xnf4fYWId 39 | JPT9si0E6DxRUmBTQ0Dy4zU1AQ== 40 | -----END CERTIFICATE----- 41 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/rsa-2048/end.fullchain: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDUTCCAjmgAwIBAgIBDzANBgkqhkiG9w0BAQsFADAxMS8wLQYDVQQDDCZwb255 3 | dG93biBSU0EgMjA0OCBsZXZlbCAyIGludGVybWVkaWF0ZTAgFw03NTAxMDEwMDAw 4 | MDBaGA80MDk2MDEwMTAwMDAwMFowGTEXMBUGA1UEAwwOdGVzdHNlcnZlci5jb20w 5 | ggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDHvQSjQATPtE602Qzx3wez 6 | 0oeELGoWqnj3lZw2V/gNPqmSwKB1bIqTSgWJerpvZfLZLWIadq7rrq4d16b6/nxN 7 | zBPzsdohLfAJeTbT4fHM6+wZ74qxfathFtjN8vzntla0rpF1P3YB8umkYUe4zXeT 8 | X+8kNPntt7GAPa8tNj95XiTT1YKhaYn7kiI4gT1jb9owoMA3viXqTPTVmmimN7k/ 9 | cyI6Hh0llTH5qa6+8l6TYhjJbOrpaP0X04MwXbQBOBWtLojDYBWoQ92g/mN1lIeq 10 | CYT8vddAJtalCfW4gZr2Zgh6CQxFiacbYtUPcpbxbqMlHVp+xEa67ZWbsLYMDHcZ 11 | AgMBAAGjgYkwgYYwHwYDVR0jBBgwFoAUjGfueyc0aewV7xHMs0VoFAsF638wUwYD 12 | VR0RBEwwSoIOdGVzdHNlcnZlci5jb22CFXNlY29uZC50ZXN0c2VydmVyLmNvbYIJ 13 | bG9jYWxob3N0hwTGM2QBhxAgAQ24AAAAAAAAAAAAAAABMA4GA1UdDwEB/wQEAwIG 14 | wDANBgkqhkiG9w0BAQsFAAOCAQEAoKQ9S8pjx4ETM1xaL3OfwtteGDGBumdMvqWQ 15 | +vvEy1ckMiYzpED8Rp3FM5J8Z9o2ZHoUABaLGb7pQClk5ig9MeuCDG4MYUUWbycn 16 | y+dxmqAS0p/4MtzXKd2GSEFICZR6FMkz7zj68We1orRi5sXl8PLJcZ8kfEg8wLOL 17 | j1iBwpw1GOB1In7eQ2iyNydXohEGz9qCkUgT/c/tY4cog+FzTEp3yTDGZLmNKUSz 18 | ttcg6HqitJ6Hn/dvbLNJC5wlY7MXWxjit5RBWVNTgf4QTAVpvdOymlM+jSfx/mq+ 19 | jgPosvpIjD8xXuVD7AA+lpMjsbD50prLecxwADPmg+bZmcQv3g== 20 | -----END CERTIFICATE----- 21 | -----BEGIN CERTIFICATE----- 22 | MIIDUTCCAjmgAwIBAgIBCDANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRwb255 23 | dG93biBSU0EgMjA0OCBDQTAgFw03NTAxMDEwMDAwMDBaGA80MDk2MDEwMTAwMDAw 24 | MFowMTEvMC0GA1UEAwwmcG9ueXRvd24gUlNBIDIwNDggbGV2ZWwgMiBpbnRlcm1l 25 | ZGlhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPjnWAwXrjPM3N 26 | q2QmVaaxu5/EdMk5DCCTomaKYE9dEGa1hd+ZXuiqvdgX1J5jEn9RaTxY5gUcNVyT 27 | Utx6si7WqPTb+h1IBUT0hNZpXT7AOo4wbNg/9vjmTJ1GfX8EuLmaK+hkFH3IUGJL 28 | Mh7I47pIEo5WiPcb/tBT4fHN87vQdknT+S1K8BX1eGFDr+mmMbj2Kg5sxybAZmO4 29 | YbHeT1W1MKsewp/gBI3jZwXAtM3CDWrWMl/HXmiM01VVi57T/ZaUHIth5TOMIIkF 30 | wF52MeCFH9fHLgx3LJBTkeO76dbjn9CO6OwfvMmOzSJbDim9kAPB2FeM6xILGhKy 31 | T+Cq1k8dAgMBAAGjgYMwgYAwHwYDVR0jBBgwFoAUZ8fKnr69bZrvOOQ1Jii60vG9 32 | ELYwDgYDVR0PAQH/BAQDAgH+MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD 33 | AjAdBgNVHQ4EFgQUjGfueyc0aewV7xHMs0VoFAsF638wDwYDVR0TAQH/BAUwAwEB 34 | /zANBgkqhkiG9w0BAQsFAAOCAQEAiqcCAXqzbGQ08wxaWiUZ0ahZ2giTkGXgcluN 35 | P7LXnMgve3M1gac4XBHAnokuME33+ppxVvIiX8c0OxR8LUPPmKQTGMtivDbSTFJG 36 | UALdyol1xalNuCuX81rvd/UY8tV6UQg/PzJb6QZFAxeMrodhS/dcCyNVMLFbutyM 37 | Vq3RW+ZjIxY+RVSYiEqWvStcjga//ateG8ndUioAGsfX8cs3IVkHdSqCJ4YCgml0 38 | /scRGaep2uP6y+yW9XQGxDLI5FHIs5EVn5nmo23HfmvLw7fYIgGdguCJGnWzy+kS 39 | O2+9pDFibt7UieLOUKlxyw8PbtvHJrRVvy1ylgEaNLKncssxLg== 40 | -----END CERTIFICATE----- 41 | -----BEGIN CERTIFICATE----- 42 | MIIDPzCCAiegAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRwb255 43 | dG93biBSU0EgMjA0OCBDQTAgFw03NTAxMDEwMDAwMDBaGA80MDk2MDEwMTAwMDAw 44 | MFowHzEdMBsGA1UEAwwUcG9ueXRvd24gUlNBIDIwNDggQ0EwggEiMA0GCSqGSIb3 45 | DQEBAQUAA4IBDwAwggEKAoIBAQCy4ZPzrQwfu3tz3ll0xHzlHtAQEHUyXzSo3VIn 46 | ULFPC9D84LWe9zpQBYGxOtl8OVcMdmEbzoIOHO6afNSnzbcQdZymJ4+FMpmusWdV 47 | CcWQ7Knu4Ok0mWlw7HXgtnhunjX0BRMy5M6WXWk6MH44G7n3DCQDINAJvGAwirIT 48 | kUfekbnwDCIEmIZNQQKyGdndn6mQGHt+oWdmgiWxI0dPjU/vsyFQDFomX2IF/fn4 49 | j/lKvhGPEccO/2zQThUrbVck1t7kRilCDZbShGav3+87h42mISriK5yqVOwPzPL4 50 | HWjIL+G2sMDY7RdFKQHBCY4Gis5rrLtOOhKtoDmos7oCCs1BAgMBAAGjgYMwgYAw 51 | HwYDVR0jBBgwFoAUZ8fKnr69bZrvOOQ1Jii60vG9ELYwDgYDVR0PAQH/BAQDAgH+ 52 | MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHQ4EFgQUZ8fKnr69 53 | bZrvOOQ1Jii60vG9ELYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC 54 | AQEAhTU7Iv/HBuSOaIAOTrgqbvwKUoZsGG0vb1DVOYINasnDDVx+celU9jvzSHRy 55 | +5kZUgflytZIy1TmE/RvQi8/vd2s6BL4DGF39VyFO49g746EcBUEmNGZFS0J/hVa 56 | iZj3yNO/tO5V3nzrGzTrrx9cRnFykLKE/qDnrIOfCiRk5KYui1M5JYBM61r3MDLA 57 | lrRCZh4u04jdNVHPF14km5VcgJvhpGkX2mpe3J9ZtOwBdc96e5zJ0PPKofAuVhuD 58 | J8t+QNnjXKSyf1Ud/5WAOKinqGK902mRAwEFISQko0OajUkUzjZabr6xnf4fYWId 59 | JPT9si0E6DxRUmBTQ0Dy4zU1AQ== 60 | -----END CERTIFICATE----- 61 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/rsa-2048/end.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHvQSjQATPtE60 3 | 2Qzx3wez0oeELGoWqnj3lZw2V/gNPqmSwKB1bIqTSgWJerpvZfLZLWIadq7rrq4d 4 | 16b6/nxNzBPzsdohLfAJeTbT4fHM6+wZ74qxfathFtjN8vzntla0rpF1P3YB8umk 5 | YUe4zXeTX+8kNPntt7GAPa8tNj95XiTT1YKhaYn7kiI4gT1jb9owoMA3viXqTPTV 6 | mmimN7k/cyI6Hh0llTH5qa6+8l6TYhjJbOrpaP0X04MwXbQBOBWtLojDYBWoQ92g 7 | /mN1lIeqCYT8vddAJtalCfW4gZr2Zgh6CQxFiacbYtUPcpbxbqMlHVp+xEa67ZWb 8 | sLYMDHcZAgMBAAECggEAA+3v1mR1R1Q8ykRM/KTT61NQAHkH/dLF5xIhVc3NhCq+ 9 | ngIB2aymLArnyLQG7VCAm1EeVQw5vQOEpzoku/ejNgLvqFOXULxmJl9W9zVQ3cgN 10 | LvQ3NlH4yiBTIhQZVR6myPk/b2KYFm2PmqR3LvIE+En0kEAJjpRPiXOii5aE0W/C 11 | MTR2dWxKoIGMWdJxkt4XtHKoRPHk18+lFfA7GgYuFe7QJD2Yc0a+EBe7ybJMrgZ4 12 | YlwkldAOp//tcJ3xsmmA8fAXCncvrZkOZgjV46aGr6Ul5N610Qy/ADi4Ewpe1gAp 13 | Rsos/0lMv9zd6rjo1pFpzdDsemj3180MDMaULEYeLQKBgQD2JYRac+XihJLZemTZ 14 | b4zw0WfgV90qbnFF9X4IIhGqtQov5xwVlbgZXBNyTnhXPDsVG6IejsBByRouFNM0 15 | PaNgnNGaKvhKx/pxQQbHykKydfnlwb1IOEV9pK4Po2LMH6ybO5AqeFQb+XCSK0iF 16 | EwG1yQYCqXdFlAAIg9IKjaEoDQKBgQDPu+o6YoudM8BD7mrfwc5bj73PIDejpHzG 17 | 7D+JHrlf/LGdUJsSu/GL2u59lz/htzaCO1A+oG84/lYIePURLhVKOXwdeKFB0NMX 18 | Arnd24T+WnFka8x+jdrXJA40VBLelVsNRhT79qMwb+2pOVMLDPnF9h1igAD9Zzzq 19 | RJopW7acPQKBgEiKUfEeStdw3p49Fc+GsnCeJhDVlBZXKgbGDHh1IeO/KttnLr2l 20 | u/WtTwXW3lxHIdpcpHCA/WPl0lNWS9APgkCMtrDKjRXszX/m/AqRLwrM/fKaICBS 21 | hRg8Ghf9vLYPd5zf9uKtR4xe/K/3FY4yRcS/E4hhTQcyULgxsQrvJllZAoGBAKrS 22 | mDYSu0Q2PjCeafw+XvckKK2ejKJgrMrXkxeq0D2CinwWwK6TJnofOmbEbZ+rDYPi 23 | SoZ1X4C6hPzKmpvaDV/QDaQeglyg4DTX5QfvcFnI/d3aV3rqI78uww9841dt8kXk 24 | D3Vyx5cZM5IotYUs0mhbjqZlJGs87fanGy5PYMbxAoGBAJXYPGf12yb51wKZ+peG 25 | MfPsWBgkZRyp3dYdV5/NqceLKG4v/UyHfgJ9c78SZy9cA+uE54TnR+eC1lvEz3HK 26 | Rh5nfmhv0ltFM7+M1Wl/LMWNMa+H+M6NWIAwwhUHw/5Vkipns9AK4WaLHLryvb8W 27 | KuaZzzAm3i/zKV83Nznrv8r3 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/rsa-3072/ca.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIEPzCCAqegAwIBAgIBAjANBgkqhkiG9w0BAQwFADAfMR0wGwYDVQQDDBRwb255 3 | dG93biBSU0EgMzA3MiBDQTAgFw03NTAxMDEwMDAwMDBaGA80MDk2MDEwMTAwMDAw 4 | MFowHzEdMBsGA1UEAwwUcG9ueXRvd24gUlNBIDMwNzIgQ0EwggGiMA0GCSqGSIb3 5 | DQEBAQUAA4IBjwAwggGKAoIBgQC5LL6kuGiI8cF0rHUKasFU37O174okW2QAWOIm 6 | FSI/JjLkr6ubKDpE/1fTf8VU/uGc2Sjmlz8LiEg/eQER3xaAR9Wf/WvRDDGKfsJv 7 | Hhl88gRbFzPNMOxB7q+albstVzcEqWaU77eo3RMNz7JHViDTPDP66z8M6dhk8zCz 8 | tqxw9C4hFZoZTIjFBoh2Q/iI87aye0Cswu2e/4cgweZErfHB9ogrr1j1UM663oeq 9 | TMmma5pDXZI16gsB3dMzI926z40uXAHVIRS2OeOohfiV0jvLkOzxukJ9O33MkALg 10 | 5jBrJPkjefGN9bg+9BNUqy3iRO+1D9LgfeRi56mpnOCQ2A5RkPY5zJE1EYOExLYf 11 | oIDg4rXP4tTb6tG3EdzWE7Ew4rOO3/JVjh/gWwxeSPv29/HaJQ6C+WmH2VCwA9HS 12 | DIl06qf4r7w0KWLPFsxmNDDQ1V+DW/zjS7toq0Oqk9t+Rim0trjgRsmfRiruQ54K 13 | JqTNzdwWqGk83Q3Kimu2MWwQ/hECAwEAAaOBgzCBgDAfBgNVHSMEGDAWgBQiSGE+ 14 | foY4+x6LQjFzL7nvoT2X5TAOBgNVHQ8BAf8EBAMCAf4wHQYDVR0lBBYwFAYIKwYB 15 | BQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQiSGE+foY4+x6LQjFzL7nvoT2X5TAP 16 | BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4IBgQBdXBIfKNUSRNvZC0+/ 17 | V3aFmm4d8PYqdUM64is+WKOB2Xl/oaCxNTSaeprXNqsDYheMtkUhec8tIO/Da0JT 18 | sUDu5HqL0dfqmF0RfjEVkMxoAJnPQVEPAeOWgHSKFwjIPpTYIqZyrIiRULwGMQFc 19 | RBdZtsrjP61tcPgF4MBRgI1C9Xr7ODUfjXIs7PkblgvDiVKrocUHStQ0w3hGURDX 20 | /Qyu1vFWAZsAoRdIbmPN+FFhL3965DH6O+hzPOXWOD2u0TPQk0gYnWYR4HRbAYAB 21 | KY/lbHThAb8gCkUy/FuOwKUWTxlFCGwxQCkCU/6QjJ/Ez54EQ+fiWNonQIm24rZb 22 | +REjAqX0VLg7jDTRH9wj1dXYszJQ94QlOetDUy+1GYbtPLtVd+IGB2RJhVCfubBU 23 | nO8sETCeSPV8Zbz4e34JXJbEZ8AXT89O0lAurNvLRSxAW5qeUNp+iVCNcL6+EjrE 24 | WyT3Jc9H2N9tKpa33xTXDUnRTSw8PnFnVyXg7pB63D/8AtE= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/rsa-3072/end.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIG/gIBADANBgkqhkiG9w0BAQEFAASCBugwggbkAgEAAoIBgQCMXi2nT1s43O7W 3 | 0f7sXj7RFYKZDid6Y89x7B/2x5nE6HXJQ//IMnrua8hWK2QNbPuxMjJzwB37EZrw 4 | K1mK1VE8XAjhNwIgzRSinwWP3L8f1os8pyO6Q5cGGXHLQZ358PkpbMZlUNpueyCQ 5 | zTCJFG4vXgkvkwZ0zFMhy1X+0LjWMl0RhLlIDI/wdLxpggkiFBX8GJq56fov1ocK 6 | YbxblEe4+WPepCjFm0Txnduhox/SR/tKgVDOjHgOqjKGH8PpqlJkp/iGwHyXcCJM 7 | 1hG60rLTcALzbZf6Tm+K1aI4+pUB3djWb/M1N+beVsU4RbhXqNr+ZqrZ75duXIDU 8 | RxMLC9UIrNd5pJXMNEQrpIDIobpMyuL3s4jocj89f7dAF3zKAQYiTkRS8/Bsqh6R 9 | dijrqVEAxpbXdT1W7kUEPnrHXTByXxYqMn8JexRG56Pj0RzWHEl82Rf/XCIO35Cb 10 | tH7j7Skmosl8StIDrhC+Ji28BarJnEKhsarOdecdCVIzEm6D6ekCAwEAAQKCAYAy 11 | 6S2x00yI0UknTT8iyAQMnbqifMnA0Fa7QSNOxJJ3IsEl4K3zFKwVsa4V4uMFI5Qe 12 | btBxvyqgl4AUwARYIIq4U8E8vlDdSMTFPtwrk6sWhyA1PYHt2vn50ly9le0QbGBS 13 | sAs9UBgJnkrvehyye2CDeZ3nTXI4BqvYRAHKzDVeKyIqanMxOK00T4LO2cUqQRLA 14 | PsRPzhdaJnsQPuasaJmi84FPjUbkdS6KW/D/LUUrZcQ0/7YpVDVvTDfLAdZy970k 15 | +kYijKrqQON2izjbU3moy6OtGSOpArY0uUHj8L6yr4qjVGKjpA9DqaHShmTk2JpS 16 | yo38xEeOr0qTPuPebv/XNfm79DPavEKz+/caGvMTJTd6r1g5nQf8vxvnGpgdbpGG 17 | /x5RkHjPx9OQDLbwmBzxsmNGJNADF/NfpIyKp/SJXcMymj68ricn/biFITEM25r1 18 | p1hcmS4y0c2fDl/OmnShsKHfOn3bOy6L6b6Q3j5GKRo1hm2gimgtJLz0G+AmoYkC 19 | gcEAxU27TN1rRcjlycw5yH0dlOd/qeDqY6TCISpXbA5eqvmZ4AsxDgDh4pRoEbA7 20 | GTjMoryO49dvx449W595Gx7RW2Ch03MJzgcBR1HftP01NrGHeN9aunKw3Y1sgad2 21 | 7AEmEWim85Bo7J+qVu6dC0nc5sAMqE754yxPbJQgI7IusesT1vLPngby165ZVepM 22 | UnYsgJrerLomuCriRHpyqOkdyvpvmOWZ3S3xXMBRr4LbNbdljcA45CjGKx5doyrv 23 | njnPAoHBALYgVAylFP4JvaCVZ/SdK6dJ5EXbgWMoQOFI/+pW08ISIgZzg3NfOXUP 24 | vX8RIjmeRI8BfNU4yLyuU/yMYnVE5MPfkwvco6IoYLjIokK6XrkWVcnXyg11rzmu 25 | FxFWuNy+Ky4IhDp2DKf9foEiQXxPMium+p2wyLK4AMEhW/Y5er91iEbpmRKzQ/CJ 26 | /sSuKbs8ZefG6kA+Iu3DmnNFhOhB2aSI19qwfTW3yKDJSCv+Trj4e3l5hU/naQWY 27 | ZHO4qlvmxwKBwQCr8tln3JPvhmzUmFpHYtqT+cilqTE8U8snkjoMHt3cDZlPyxEe 28 | TiCOEZ48xCRND9YvgTraT9fHxyusHOgzfYEhLK77k4cY+bvghvb6Sa3Fk6Qn8Cem 29 | 0+tVujm1KNgYR8wAYf8Vx2XZyjBugJd2zhFpPDgLuoBGvkgdrV3xHglZ3zA0JPpR 30 | k2ayFu0eVgnb18di8RVc3QJ/gEgfO8OPd1ISonz9eCPGwZJWrfjCh705LDKh/cLW 31 | /L3vuBAM8o9PirsCgcEAsie1kBj8C/SjVi5QXmxQg3g4oE00qDZ8IOQz0pvU0QbD 32 | 2eOtNnJz1hrrlxy/ifVTw0AFSN4fHtK4vVbmCSi3TxOo1/Wg68LrulYow3Vjq1I5 33 | 4RQBRmFUYuv1DLT0aJptyr3x+u33O20xDkjgHiWqQiE5DoAcExcDRejH+HgJprfl 34 | 8tgXML/DOc0DNonXsJxIYw2ln+ooaMTqlM/wTvH7YIOsAvSZxq5cx0ueGcrOXwpS 35 | XmWNDrijdyG3QavmmbeJAoHAaLztTdLPdhbOu2l+oHrohbBrNKxsE1LshGCbMqOK 36 | zuy9zReGDKtyR8FHLAtTf5MQCMaQqIr25gxKylocKqwTwPTCIOdUImnXjHZq29r/ 37 | nmaB6cApAFAW4YwYjf5dNKg4ZNTBMtulBS2HjoI6GBo95Yr76XtHIytOS5PV/E/v 38 | KyEXerarcPvBojjBk1w7vazySe+Ph+fr0f8TBaWqthjHFHA8mKdmG8Pa1mElXUpe 39 | c9a+7YRRJ6KDDPv27dhYbbaS 40 | -----END PRIVATE KEY----- 41 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/rsa-4096/ca.cert: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIFPzCCAyegAwIBAgIBAzANBgkqhkiG9w0BAQ0FADAfMR0wGwYDVQQDDBRwb255 3 | dG93biBSU0EgNDA5NiBDQTAgFw03NTAxMDEwMDAwMDBaGA80MDk2MDEwMTAwMDAw 4 | MFowHzEdMBsGA1UEAwwUcG9ueXRvd24gUlNBIDQwOTYgQ0EwggIiMA0GCSqGSIb3 5 | DQEBAQUAA4ICDwAwggIKAoICAQDSN1uvK7uiwuy8dZo4Y0VxUax4mHDh7BMbXPQn 6 | fpuHVqUM3zhurrq3e205wM+0vuFfslNKWthMkEyb1mdV3dSUSyckdDkDV1c5CgRu 7 | xH3kjGAGxkuHyrTHQIyx+6XeHVsz2CLZCZzIYQaczHHERSJsNnjK8sLWX6rsKYzc 8 | YiF5M2Zs+vGKVXLL4UY403ex7chFZ+0m+m6ym7jIkLiYdjp+/iWLWGxSYV8zEl3c 9 | 1zRF1HAsmsQnrot7s0rFagixU2rKGlwEqpF0Gx6Dp+Vj1eQyHvm5uBo9efAZ/GEK 10 | iYJB6XNmdDOw0sUZry0V/pQ5FBL+ht/bYXq1uQnYMQB0JwEGLQ/JCcevW7PcULuY 11 | uRYFnYDUbSUkbBpKazKpKwqaHzR2mL2YmC0m4NYNXT/dwveCduk4j0ETbiJCtJ94 12 | GN21VOoM+kTZhIRY4CHAAta552zyAyydE6iCb7ADHIov6MCLU2Il+JtPXuo13XIl 13 | 7FEJGIMOYwTW9LZVR+QDkX8z+SMJtnjykimgb0ity7f12E8htK0g8dupDAE0pXUC 14 | eA9i2po//ginch/8qczyV9pDdPKeq2/uZRTD5XaZx2AT58lKQCJ4DKSD/8MNcJuM 15 | KaodXb6UTkp7y8gOsMucZ4dJIbxfHdDoMzAw8PiNlXvaMAlwB1OsW0S26iNk2GFU 16 | Lm0iVwIDAQABo4GDMIGAMB8GA1UdIwQYMBaAFCer60UpWkSNmOJmF6PFuHcenFfQ 17 | MA4GA1UdDwEB/wQEAwIB/jAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw 18 | HQYDVR0OBBYEFCer60UpWkSNmOJmF6PFuHcenFfQMA8GA1UdEwEB/wQFMAMBAf8w 19 | DQYJKoZIhvcNAQENBQADggIBAGz1WxW6nfOzv0JFuZwNIw7umzVJ9Oaq/tlZ2Qxw 20 | dJ+cKoW5Aj/cG7AE3MNJGDLI1Y2dncEded9BXtaby+wi2N/eow3BR9b/7r3vI2Kv 21 | QjySyXji4CiZ+DLOKg+WjKrRnoMfgiUwYm8AMkg+d5GI2rKN3Ij9H3jTuQKs6I+d 22 | BhClNVUG2T6U9jUKh3sm7znJuAb5pyYt2KcojIc3+SyHEwsKif8LQKag30K5OfCy 23 | cbM6tJRP1vpWEd9ua6Afs9fMzF77fU6R2qjU6GFuWBJ2WjaGLNNP7jMnAJrmtZZT 24 | ODfLf6BUXKPldn+wYhHKsSdnBLe5Gp/k+9A81M2gu6Ql9W+j4bMklLhef1ZEoCWt 25 | 7QO3agpl4vGxvk/yOoZqDlvFQLP4IphVvja9cdP/+g6T5jKi8jXkVhc51c59vc1j 26 | n9Tq09cwSjKo+RLLRJE1tcPiYBU0/c4FAXsad9wGTRPdmGB1aFJCmvp7cZA0dOPV 27 | gf0ZeD8uS5Xdb3/YRm2/zMAnVwIOKkZrH3jTNOBIfVcCafQRzlzqujcs/w2u7I74 28 | C1OwYSVKsTyyHuiXhQGgXu5fDZFIYQoeiQOF47EEPuNaV3M903EEduluMOXhmbAe 29 | YSnUDVyiy1yDP5eB6K8wQEL2D3Yn0uA62nXahH/adcSj3Kw7ImQI8cb/V/qH3Lh+ 30 | C30c 31 | -----END CERTIFICATE----- 32 | -------------------------------------------------------------------------------- /rustls-graviola/tests/keys/rsa-4096/end.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIJQQIBADANBgkqhkiG9w0BAQEFAASCCSswggknAgEAAoICAQCx466I9P2A3GrS 3 | vS+K1KBxpyikG/5R21+O75jh/YNwBvDSQ+eVe8eoL89KZUelbhbFjNUw6opjjywX 4 | FzWLT/G0M3mNqi1lXaAx6/pVWBYS15RonjXlW6Dme5FRqTplQAR+Itx2j1FKw7ls 5 | M8DbJaGZe1e/9QfRPZBDKtHfmOGrkH51dPlP72avZcxNvlsWNu5qZKkmwWHmmCS5 6 | E+oKsKGJCxWVlZerswiVx3ZWc8WHMHrN18ui3A6aRUPUf+oWX+6poixaAas4l4AE 7 | eCLnukgFROZcZugsjeXRBToLTM/VE6dmhBZzWld2Vqso9liAeaS2q/VEFqSmauBB 8 | +LSHfIf6yzFGclWd3QnpSgnO9/8afmy1+2Gu2Sd8n65gKuqrrdVQZzH+LJHxp3Ma 9 | ejy+ZW9noYlTwEllV2ASIlNDw7LOQovedkSZeckbkzr6DVfMoHZtq5luKq9CdrrH 10 | jEWyZbo1AdNwhpwRl0tw2SWFY52wbLpIHLxfxuPEFsCynzGuGUiIZVwR7yPWyRwN 11 | 3mOkAhXFd+w5b09WJYnRF0p3HyxBLM/wa8fhPw7XG/xbXs0XR6mliJ7XpS14vQVu 12 | GAp8nuZYpIXSp3zSjoH6Gokl7EOwXy7BK+Wbt8dNOY2QLqnA+1Bam+gJ4DwMzuLv 13 | wn2QfwoWeBwaBy+hhdDKVAlrqxOhiwIDAQABAoICADWUutGN2X2i5porWdKbUOhq 14 | zRcBR40oYpQPHyGS1rA7pvXudibUbcL/A5UJBJeTnVBLpztgqeZrDYC3AO3BWrBI 15 | gOhmxd2uYb4nsfNa4Osz/AO3A8zd2I0T0yWhr3En4zKLFZSwfm/inEs3G3Pm1dIB 16 | EOFE0OH5hSZ2E1kiF3cxwqVmYmHtXiSeqPcRyyXZzd5GC50cynxGf2kv0mL96On6 17 | aLnxoQmal49l0QMhQ/IAbDzsLu4TEmLtUg0DqmKq6pw1uN4zentFRs4R0ZGyzlan 18 | 9isG5A/nfb2DsYQN0tv/W4DJcGm2YHnIiS2BZg7slOxgxzOHDnkB4CJ+4wGcROiJ 19 | DAXGNA4sqcJJXYYjjpH+tn34vH5kUrL5OiJ68n7Xu+Swpjih6N+QhlTjPzPe6GCt 20 | Uc5bESWtpQi2WXQvg3QeLtzPWnLDHu2vcLxixV+R6PIQlFMPGtrzzocdWfc/2/HP 21 | aRs+6JIoEJnAlUy1umZGVOPr4dkgbkKH70rmhCL/Q3vgY9UtIFszrExesusoGETS 22 | /Eq61MOB/+SbXcAVAUpTG65K18Py2tbhyRKZS2rA3KMg2sFExrJX1UJm0C3+5Udi 23 | R2k3giFRELsz3MCO0pZoOuplQthm91sx3nelrwtVZIiZd2CG4JIHzLtwHV+RzzWx 24 | J8sp8AW8lQkolDKNyUiBAoIBAQDaftrRT9T8L0xq40ncBSb7qsIwMBH73Vtsce8Z 25 | 2QJYIcfi2+pjCro0+pG4j+HEDqr/QEDfrAH6HGSO2dFuRHB2ocmcyUWDK6p5m2cx 26 | XFjOSptsfmG/VyNfced2q2iuqEFm2tkBpxGJRVmXzMnk0PKDVm70S5kNMaxztj3I 27 | m/wDp7cS80bSelZx5n1hz5mJ9Oxnz9cFYFXGXUKxZjZlUO1uSL1XOtS+RjjqAa9O 28 | /mNxGs96LtHsnSyo//1umuUnbELLJPeH1U0mtCxiqJHan4wtRSzMIDrKCxIbg6V6 29 | 1+3E4ZThoctpt6qw247XxkIPTFC+EdSCQe8ucjh8tr3cRSV7AoIBAQDQbIJSM6MA 30 | L9sh3QU5lmJZgt09BqwNkglkCRb/ra0lAfY5ZFN8vA61KBxRktUUy40y4QSZwsen 31 | M7jXPwDR7yzbl/o1kYC15979vEMvydSGKyWxTVHIYcuXMAqfeIKLtq7UDAKjxdUl 32 | fLQ2NLb+rn/Bt4tWHnBF64fdUvCjjYggOvKTNEa3VOPV107g6ZwKoQR9z4lHcZc9 33 | DGmGYuKkXOsBNmm5HySJ7eSh7LaCebtN7cQxOIqGgV5or3SNLspDghin9Svaq4E2 34 | ztZs61zhTitrvDUUH0FdlF0G/CaC+I/fwJqypi+LuDGpbmk0ralvSk52ev2MC7xy 35 | 7j02i/Wgy88xAoIBAH4nBhIaBMACUx3X01o8g1CFPA90gb2pBdMsST/kQu09u9oo 36 | 3UCH/hD+p0onkNORIHu1zn8WIiIVaJ3t93SyATkNmoly0Da27HvAFSmzxvZ8rxZK 37 | NgeyuRKvglPLDerh7LkFHIxOuNpH9z2lGOCLH6pjKjbUuy6aApbgnvWH0k8N8672 38 | VWrLBcRHrxbdNSopBqG9p8lL4NpiGFKy0C9ZNW0ahG+r4Q9nHg9GH8D9Mc8pCqfi 39 | BoSWDyYYf2vv9OT5JeuCkYSUzDHPj1z7NRNEUTwGF6JX7XmgQLkwHkg6CedF058e 40 | uoJ0cBIjAmtk5dlNV8UWKFt41C899Y1UOXTHW6cCggEAfzAIYxNhwAZ0KfkPbDIK 41 | OGd0jP4aVnmsw2AMqeAZTgEheapwjCjSrNgaV+lLoNIKi2bngNFtNuqIPMoUvQfA 42 | jwzyQmhVbCxgVuTg9zOqPmnsKYNuieKr88n8YY6P06SakYn2vmxGgwbTjlSi604f 43 | Zl6UZ+xRRUnS8kvfz17aGBkA2LXJBa2HD4LBftzwPUg/Tmssce2uhjGh38FOX1DY 44 | lDfZUn/fs0/5+ppSUdLpa0fSNtszJZuiui1/6XwJMCMe2rfxmBKa2pBkJ7mFR3SF 45 | aMxEc9AS+oFEN7P96GS4n6mQfb6OOywfGi7ngp8LS3/D2+d3/FNZH6Wkszm7nfFh 46 | sQKCAQBKo1PQG6G2NT2C8hRVXYO31nO6Tsi1mjfbXuJvehnKa4X1hxB+64KOInDG 47 | d6eKmIoLHG/UABn5ZQw2X+XwTVKetE4mp6akBRxY6tB0uZotNwjFX7XdaZJtgRB3 48 | UZov/gwysSS7MgSzBdKn6KdygByFPA8gvEKD2D53mGbHCJd9jxRt5Q4IhjJaJUMN 49 | Mj1xZ0TkfrTLXazo+jHaIm0rOkDjVsjSI4+6RRkbWn33fHQp+L3Ed6d/prGoV8Rf 50 | MPkrjRLbbM/jBA8uJjzwT+fnkJVFsXNbNyMnnHPQpK7ukTsLHDEcW+vBzSSeO7O5 51 | d0v4KbjW+5AKNLSbfwqJ6DYnBYU4 52 | -----END PRIVATE KEY----- 53 | --------------------------------------------------------------------------------