fips204 0.5.0

FIPS 204: Module-Lattice-Based Digital Signature Standard
Documentation
name: test


on: [ push, pull_request ]


permissions:
  contents: read


env:
  CARGO_INCREMENTAL: 0
  RUSTFLAGS: "-Dwarnings"
  RUSTDOCFLAGS: "-Dwarnings"


jobs:

  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        rust:
          - 1.85  # MSRV
          - stable
        target:
          - thumbv7em-none-eabi
          - wasm32-unknown-unknown
          - s390x-unknown-linux-gnu
          - powerpc64-unknown-linux-gnu
          - riscv64gc-unknown-none-elf
          - x86_64-pc-windows-gnu
          - x86_64-apple-darwin
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: ${{ matrix.rust }}
          targets: ${{ matrix.target }}
      - run: cargo build --target ${{ matrix.target }} --release --no-default-features --features "ml-dsa-44 ml-dsa-65 ml-dsa-87"


  cargo_audit:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      checks: write  # audit-check creates a "Security audit" check run when it finds advisories
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      # audit-check v2 reads Cargo.lock but no longer creates it, and this repo does not commit one
      - run: cargo generate-lockfile
      - uses: rustsec/audit-check@69366f33c96575abad1ee0dba8212993eecbe998 # v2.0.0
        with:
          token: ${{ secrets.GITHUB_TOKEN }}


  cargo_deny:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: EmbarkStudios/cargo-deny-action@3c6349835b2b7b196a839186cb8b78e02f7b5f25 # v2.1.1


  cargo_outdated:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: stable
      - name: Install cargo outdated
        run: cargo install --locked cargo-outdated
      - name: Run cargo outdated
        # Exclude rand_core: Latest 0.10 drops `os_rng`, which breaks resolution while we stay on 0.6
        run: cargo outdated -R -x rand_core


  clippy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: stable
          components: clippy
      - name: Run Clippy
        run: cargo clippy --all-targets --all-features


  coverage:
    runs-on: ubuntu-latest
    env:
      CARGO_TERM_COLOR: always
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: stable
      - name: Install cargo-llvm-cov
        uses: taiki-e/install-action@1168f6810a3cb30a3514bf5756a3b7f0422c6df8 # v2.87.28
        with:
          tool: cargo-llvm-cov
      # The FFI is tested from C and Python (the `ffi` job), which llvm-cov cannot see.
      # Including it would only add a 0% crate to the total.
      - name: Generate code coverage
        run: cargo llvm-cov --all-features --workspace --exclude fips204-ffi
    # No codecov account, so stop here for now
    #  - name: Upload coverage to Codecov
    #    uses: codecov/codecov-action@v3
    #      with:
    #        files: lcov.info
    #        fail_ci_if_error: true


  cross:
    strategy:
      matrix:
        include:
          # ARM32
          - target: armv7-unknown-linux-gnueabihf
            rust: 1.85  # MSRV
          - target: armv7-unknown-linux-gnueabihf
            rust: stable
          # ARM64
          - target: aarch64-unknown-linux-gnu
            rust: 1.85  # MSRV
          - target: aarch64-unknown-linux-gnu
            rust: stable
          # PPC32
          - target: powerpc-unknown-linux-gnu
            rust: 1.85  # MSRV
          - target: powerpc-unknown-linux-gnu
            rust: stable
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - run: ${{ matrix.deps }}
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: ${{ matrix.rust }}
          targets: ${{ matrix.target }}
      - uses: RustCrypto/actions/cross-install@efc9b5d1c965d13258baa76a080e85a7c495c658 # master 2026-08-04
      # Release profile, all three parameter sets. No OS RNG, and not the dudect feature.
      - run: cross test --release --target ${{ matrix.target }} --no-default-features --features "ml-dsa-44 ml-dsa-65 ml-dsa-87"


  doc:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: RustCrypto/actions/cargo-cache@efc9b5d1c965d13258baa76a080e85a7c495c658 # master 2026-08-04
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: stable
      - run: cargo doc --all-features


  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        include:
          # 32-bit Linux
          - target: i686-unknown-linux-gnu
            rust: 1.85 # MSRV
            deps: sudo apt update && sudo apt install gcc-multilib
          - target: i686-unknown-linux-gnu
            rust: stable
            deps: sudo apt update && sudo apt install gcc-multilib
          # 64-bit Linux
          - target: x86_64-unknown-linux-gnu
            rust: 1.85 # MSRV
          - target: x86_64-unknown-linux-gnu
            rust: stable
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: ${{ matrix.rust }}
          targets: ${{ matrix.target }}
      - run: ${{ matrix.deps }}
      - run: cargo check --target ${{ matrix.target }} --all-features
      - run: cargo test --release --target ${{ matrix.target }}
      # Debian's 32-bit autopkgtest compiles every target in the dev profile with -C debuginfo=2, and a
      # 32-bit rustc gets only about 3-4 GB. Cap memory the same way (Debian bug #1148395).
      - name: 32-bit compile memory (Debian autopkgtest settings)
        if: matrix.target == 'i686-unknown-linux-gnu' && matrix.rust == 'stable'
        run: (ulimit -v 3500000; cargo test --no-run --all-targets --all-features --target ${{ matrix.target }})
        env:
          RUSTFLAGS: "-C debuginfo=2"


  ffi:
    # The macOS leg covers Apple clang and linker, BSD tools, GNU make 3.81, and a .dylib
    # with an @rpath install name.
    strategy:
      fail-fast: false
      matrix:
        os: [ubuntu-latest, macos-latest]
    runs-on: ${{ matrix.os }}
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: stable
      - name: Build shared library and run C tests
        run: |
          cargo build -p fips204-ffi
          make -C ffi/tests check
      - name: Python NIST vectors
        run: |
          case "$RUNNER_OS" in macOS) ext=dylib ;; *) ext=so ;; esac
          cd ffi/python
          FIPS204_PYTHON_TESTING_LIBRARY=../../target/debug/libfips204.$ext \
            PYTHONPATH=. python3 test/nist.py


  # Breadth over depth: the default-feature tests, then the C library and the Python NIST vectors
  # through it, on each GitHub-hosted OS and CPU. `test` covers x86_64 and i686 Linux, and `ffi`
  # adds the C tests on Linux and macOS.
  native:
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-24.04-arm     # Linux, arm64
          - os: macos-latest         # macOS, Apple silicon
          - os: macos-15-intel       # macOS, x86_64
          - os: windows-latest       # Windows, x86_64 (MSVC)
          - os: windows-11-arm       # Windows, arm64 (MSVC)
          - os: windows-latest       # Windows, 32-bit x86: Rust tests only
            target: i686-pc-windows-msvc
          - os: ubuntu-latest        # static musl, as on Alpine: Rust tests only
            target: x86_64-unknown-linux-musl
    runs-on: ${{ matrix.os }}
    defaults:
      run:
        shell: bash
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: stable
          targets: ${{ matrix.target }}
      - name: Rust tests
        run: cargo test --release ${TARGET:+--target $TARGET}
        env:
          TARGET: ${{ matrix.target }}
      - name: C library and Python NIST vectors
        if: ${{ !matrix.target }}
        run: |
          cargo build --release -p fips204-ffi
          case "$RUNNER_OS" in
            Windows) lib=fips204.dll; py=python ;;
            macOS) lib=libfips204.dylib; py=python3 ;;
            *) lib=libfips204.so; py=python3 ;;
          esac
          if ! command -v "$py" > /dev/null; then
            echo "::warning::no $py on this runner; the Python NIST test is skipped"
            exit 0
          fi
          cd ffi/python
          export FIPS204_PYTHON_TESTING_LIBRARY=../../target/release/$lib PYTHONPATH=.
          "$py" test/nist.py


  # Breadth: type-check the default features (including the OS random number source) and the C
  # library crate for more operating systems and CPUs. Nothing is linked.
  targets:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        target:
          - aarch64-apple-ios
          - aarch64-linux-android
          - armv7-linux-androideabi
          - x86_64-unknown-freebsd
          - x86_64-unknown-netbsd
          - x86_64-unknown-illumos
          - riscv64gc-unknown-linux-gnu
          - loongarch64-unknown-linux-gnu
          - powerpc64le-unknown-linux-gnu
          - wasm32-wasip1
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - uses: dtolnay/rust-toolchain@683b588c487a69d01f6c6ddf40f036ff682cc2c8 # master 2026-10-01
        with:
          toolchain: stable
          targets: ${{ matrix.target }}
      - run: cargo check --target ${{ matrix.target }}
      - if: matrix.target != 'wasm32-wasip1'
        run: cargo check -p fips204-ffi --target ${{ matrix.target }}