dcrypt 4.0.0

Rust APIs for classical, post-quantum, and hybrid cryptographic primitives
Documentation
name: Security validation

on:
  push:
  pull_request:
  workflow_dispatch:

permissions:
  contents: read

concurrency:
  group: security-validation-${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: "1"

jobs:
  assurance-ledger:
    name: Atomic public API assurance ledger
    runs-on: ubuntu-24.04
    timeout-minutes: 120
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 0
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
      - name: Verify v4 release profile and preserved certification foundations
        run: |
          PYTHONDONTWRITEBYTECODE=1 python3 -B assurance/release-profile/selftest.py
          PYTHONDONTWRITEBYTECODE=1 python3 -B assurance/release-profile/verify.py --phase foundation
          PYTHONDONTWRITEBYTECODE=1 python3 -B tools/replay-historical-advisories.py --check
          PYTHONDONTWRITEBYTECODE=1 python3 -B tools/generate-release-sboms.py --self-test
          PYTHONDONTWRITEBYTECODE=1 python3 -B tools/verify-repeatable-packages.py --self-test
          PYTHONDONTWRITEBYTECODE=1 python3 -B tools/run-v4-lab-simulation.py --self-test
          PYTHONDONTWRITEBYTECODE=1 python3 -B tools/generate-v4-assurance-report.py --self-test
          PYTHONDONTWRITEBYTECODE=1 python3 -B assurance/threat-models/generate-threat-models.py --check
          PYTHONDONTWRITEBYTECODE=1 python3 -B assurance/threat-models/verify-threat-models.py --self-test
          PYTHONDONTWRITEBYTECODE=1 python3 -B assurance/threat-models/verify-threat-models.py --mode ci
          set +e
          PYTHONDONTWRITEBYTECODE=1 python3 -B assurance/threat-models/verify-threat-models.py --mode release
          threat_model_release_rc=$?
          set -e
          test "$threat_model_release_rc" -eq 1
          bash tools/release-dcrypt.sh --self-test

  implementation-boundary:
    name: Zero unsafe / zero FFI implementation boundary
    runs-on: ubuntu-24.04
    timeout-minutes: 90
    env:
      DCRYPT_ASSEMBLY_TOOLCHAIN: 1.93.1
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 0
      - name: Install stable Rust and every supported compilation target
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: 1.93.1
          targets: aarch64-unknown-linux-gnu,wasm32-unknown-unknown,thumbv7em-none-eabihf
      - name: Audit compiled and packaged implementation boundaries
        run: |
          python3 tools/verify-implementation-boundary.py --self-test
          python3 tools/verify-remote-release-ready.py --self-test
          tools/verify-implementation-boundary.sh
      - name: Inspect optimized BLS secret-scalar assembly
        run: tools/verify-bls-secret-assembly.sh
      - name: Inspect optimized owned GHASH assembly
        run: tools/verify-ghash-assembly.sh

  format-and-check:
    name: Format and all-target workspace check
    runs-on: ubuntu-24.04
    timeout-minutes: 45
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - name: Install stable Rust
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: 1.93.1
          components: rustfmt
      - name: Check formatting
        run: |
          cargo fmt --all -- --check
          cargo fmt --manifest-path verification/Cargo.toml -- --check
          cargo fmt --manifest-path fuzz/Cargo.toml -- --check
          cargo fmt --manifest-path migration/legacy-xchacha20poly1305/Cargo.toml -- --check
          cargo fmt --manifest-path tools/bench-processor/Cargo.toml -- --check
      - name: Check every workspace target with every feature
        run: |
          cargo check --workspace --all-targets --all-features
          RUSTFLAGS="-Dunsafe-code" cargo check --locked --all-targets --all-features \
            --manifest-path migration/legacy-xchacha20poly1305/Cargo.toml
          cargo check --locked --all-targets --all-features \
            --manifest-path tools/bench-processor/Cargo.toml

  workspace-tests:
    name: Workspace crate tests
    runs-on: ubuntu-24.04
    timeout-minutes: 90
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - name: Install stable Rust
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: 1.93.1
      - name: Run workspace library and integration tests
        # dcrypt-tests integration targets are heavyweight and gated in dedicated jobs below.
        run: |
          cargo test --workspace --all-features --exclude dcrypt-tests --no-fail-fast
          cargo test -p dcrypt-tests --lib --all-features
          cargo test --locked --all-features \
            --manifest-path tools/bench-processor/Cargo.toml

  acvp-and-aes-cbc-properties:
    name: Complete ACVP and AES-CBC property gates
    runs-on: ubuntu-24.04
    timeout-minutes: 180
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - name: Install stable Rust
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: 1.93.1
      - name: Run every repository ACVP-format and regression-vector test
        run: >-
          cargo test --release -p dcrypt-tests --test acvp_tests
          -- --test-threads=1 --nocapture
      - name: Run the AES-CBC property suite
        run: >-
          cargo test --release -p dcrypt-tests --test property_aes_cbc
          -- --test-threads=1 --nocapture

  candidate-comparators:
    name: Candidate comparators (not independent assurance evidence)
    runs-on: ubuntu-24.04
    timeout-minutes: 90
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
        with:
          fetch-depth: 0
      - name: Install stable Rust
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: 1.93.1
      - name: Install the candidate replay sandbox tools
        run: |
          sudo apt-get update
          sudo apt-get install --yes bubblewrap strace
          sudo sysctl --write kernel.unprivileged_userns_clone=1
          sudo sysctl --write kernel.apparmor_restrict_unprivileged_userns=0
          test "$(sysctl --values kernel.unprivileged_userns_clone)" = 1
          test "$(sysctl --values kernel.apparmor_restrict_unprivileged_userns)" = 0
      - name: Acquire the exact verification closure without using Cargo's cache
        run: >-
          python3 -B verification/oracle-provisioning/acquire.py
          --manifest verification/oracle-provisioning/manifest.json
          --lock verification/Cargo.lock
          --output "$RUNNER_TEMP/oracle-archives"
      - name: Materialize and replay six exact candidate comparator targets offline
        run: |
          python3 -B verification/oracle-provisioning/selftest.py \
            --manifest verification/oracle-provisioning/manifest.json \
            --lock verification/Cargo.lock \
            --archives "$RUNNER_TEMP/oracle-archives" \
            --repo-root "$GITHUB_WORKSPACE"
          python3 -B verification/oracle-provisioning/materialize.py \
            --manifest verification/oracle-provisioning/manifest.json \
            --lock verification/Cargo.lock \
            --archives "$RUNNER_TEMP/oracle-archives" \
            --output "$RUNNER_TEMP/oracle-materialized" \
            --repo-root "$GITHUB_WORKSPACE"
          python3 -B verification/oracle-provisioning/replay.py \
            --manifest verification/oracle-provisioning/manifest.json \
            --lock verification/Cargo.lock \
            --archives "$RUNNER_TEMP/oracle-archives" \
            --materialized "$RUNNER_TEMP/oracle-materialized" \
            --toolchain-root "$HOME/.rustup/toolchains/1.93.1-x86_64-unknown-linux-gnu"
      - name: Test the isolated decrypt-only legacy migration tool
        run: |
          cargo fetch --locked --manifest-path migration/legacy-xchacha20poly1305/Cargo.toml
          cargo test --release --locked --offline --manifest-path \
            migration/legacy-xchacha20poly1305/Cargo.toml

  statistical-timing:
    name: Repository statistical timing regressions (not dudect or ctgrind)
    runs-on: ubuntu-24.04
    timeout-minutes: 60
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - name: Install stable Rust
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: 1.93.1
      - name: Run the in-repository statistical timing suite serially
        env:
          VERBOSE: "1"
        run: >-
          cargo test -p dcrypt-tests --test constant_time_tests
          -- --test-threads=1 --nocapture

  dependency-policy:
    name: RustSec and workspace dependency policy
    runs-on: ubuntu-24.04
    timeout-minutes: 45
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - name: Install stable Rust
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: 1.93.1
      - name: Install pinned security tools
        run: |
          cargo install --root "$RUNNER_TEMP/security-tools" cargo-audit --version 0.22.2 --locked
          cargo install --root "$RUNNER_TEMP/security-tools" cargo-deny --version 0.20.2 --locked
          echo "$RUNNER_TEMP/security-tools/bin" >> "$GITHUB_PATH"
      - name: Audit resolved dependencies against RustSec
        run: |
          cargo audit
          while IFS=$'\t' read -r category workspace; do
            test -n "$category" && test -n "$workspace"
            cargo audit --file "$workspace/Cargo.lock"
          done < <(python3 tools/verify-implementation-boundary.py --list-classified-workspaces)
          cargo audit --file tools/bench-processor/Cargo.lock
      - name: Enforce advisories, licenses, bans, and sources for all workspace roots
        run: |
          cargo deny --workspace --all-features check
          while IFS=$'\t' read -r category workspace; do
            test -n "$category" && test -n "$workspace"
            cargo deny --manifest-path "$workspace/Cargo.toml" \
              --all-features check
          done < <(python3 tools/verify-implementation-boundary.py --list-classified-workspaces)
          cargo deny --manifest-path tools/bench-processor/Cargo.toml \
            --all-features check

  miri:
    name: Miri (${{ matrix.crate }})
    runs-on: ubuntu-24.04
    timeout-minutes: 60
    strategy:
      fail-fast: false
      matrix:
        crate: [dcrypt-api, dcrypt-common]
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - name: Install nightly Rust with Miri
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: nightly-2026-08-07
          components: miri
      - name: Prepare Miri's sysroot
        run: cargo miri setup
      - name: Run the public memory-handling tests under Miri
        # Keep the standalone Loom scheduler model in the stable test job;
        # Miri runs the real registry and secret-buffer unit tests directly.
        run: cargo miri test -p ${{ matrix.crate }} --lib --all-features

  miri-crypto-boundaries:
    name: Miri cryptographic parser and key boundaries
    runs-on: ubuntu-24.04
    timeout-minutes: 90
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - name: Install nightly Rust with Miri
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: nightly-2026-08-07
          components: miri
      - name: Prepare Miri's sysroot
        run: cargo miri setup
      - name: Exercise ML-KEM canonical decoder boundaries
        run: cargo miri test -p dcrypt-kem --lib --all-features miri_
      - name: Exercise ML-DSA expanded-key coherence checks
        run: >-
          cargo miri test -p dcrypt-sign --lib --all-features
          expanded_key_decoder_rejects_malformed_or_incoherent_components
      - name: Exercise Ed25519 strict verification
        run: >-
          cargo miri test -p dcrypt-sign --lib --all-features
          rejects_identity_public_key_and_universal_forgery
      - name: Exercise the high-level BLS secret owner
        run: >-
          cargo miri test -p dcrypt-sign --lib --all-features
          secret_key_is_canonical_nonzero_and_debug_redacted
      - name: Exercise both protected BLS scalar bridges
        run: >-
          cargo miri test -p dcrypt-algorithms --lib --all-features
          secret_big_endian_bridge_matches_g1_and_g2_scalar_multiplication
      - name: Exercise RFC 9380 and BLS subgroup rejection
        run: |
          cargo miri test -p dcrypt-algorithms --lib --all-features rfc9380_g1_random_oracle_vectors
          cargo miri test -p dcrypt-algorithms --lib --all-features rfc9380_g2_random_oracle_vectors
          cargo miri test -p dcrypt-algorithms --lib --all-features checked_decoders_reject_on_curve_non_subgroup_point

  bounded-fuzz:
    name: Deterministic semantic fuzz smoke
    runs-on: ubuntu-24.04
    timeout-minutes: 90
    steps:
      - name: Check out the repository
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - name: Install nightly Rust
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          # Rust's dated channel is published the day after this rustc commit.
          toolchain: nightly-2026-08-08
      - name: Install pinned cargo-fuzz
        run: cargo +nightly-2026-08-08 install cargo-fuzz --version =0.13.2 --locked --force
      - name: Provision the exact locked fuzz dependency closure
        run: cargo +nightly-2026-08-08 fetch --locked --manifest-path fuzz/Cargo.toml
      - name: Build and run every classified fuzz target through the sealed private-corpus runner
        run: |
          classified_workspaces=$(mktemp)
          trap 'rm -f -- "$classified_workspaces"' EXIT
          python3 -B tools/verify-implementation-boundary.py \
            --list-classified-workspaces >"$classified_workspaces"
          test -s "$classified_workspaces"
          test "$(awk -F '\t' '$1 == "fuzz" { print }' "$classified_workspaces")" = \
            $'fuzz\tfuzz'
          python3 -B assurance/fuzzing/run-fuzz-smoke.py --mode pr --execute