dcrypt 3.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:
  implementation-boundary:
    name: Zero unsafe / zero FFI implementation boundary
    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 and every supported compilation target
        uses: dtolnay/rust-toolchain@6c977a6ca4077a0ceb28ffbe03f59d46e9ac8772
        with:
          toolchain: stable
          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: stable
          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
      - 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

  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: stable
      - 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

  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: stable
      - name: Run every official ACVP 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

  independent-oracles:
    name: Excluded independent interoperability oracles
    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: stable
      - name: Run the non-published differential verification workspace
        run: cargo test --release --locked --manifest-path verification/Cargo.toml
      - name: Test the isolated decrypt-only legacy migration tool
        run: >-
          cargo test --release --locked --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: stable
      - 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: stable
      - 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)
      - 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)

  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: Build and exercise externally controlled decoder fuzz targets
    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:
          toolchain: nightly-2026-08-07
      - name: Install pinned cargo-fuzz
        run: cargo install cargo-fuzz --version 0.13.2 --locked
      - name: Build and run every classified fuzz target
        run: |
          while IFS=$'\t' read -r category workspace; do
            test -n "$category" && test -n "$workspace"
            test "$category" = fuzz || continue
            (
              cd "$workspace"
              mapfile -t fuzz_targets < <(cargo fuzz list)
              test "${#fuzz_targets[@]}" -gt 0
              for fuzz_target in "${fuzz_targets[@]}"; do
                test -n "$fuzz_target"
                cargo fuzz build "$fuzz_target"
                cargo fuzz run "$fuzz_target" -- -runs=1000 -seed=424242
              done
            )
          done < <(python3 tools/verify-implementation-boundary.py --list-classified-workspaces)