name: Rust CI
on:
push:
branches: [ main, 27-slh-dsa-sha-2-128s, wasm-tests ]
pull_request:
branches: [ main, 27-slh-dsa-sha-2-128s, wasm-tests ]
env:
CARGO_TERM_COLOR: always
EMSDK_VERSION: "6.0.2"
jobs:
vectors-in-sync:
name: Golden Vectors In Sync
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Regenerate golden vectors from fixtures
run: make sync-vectors
- name: Fail if generated artifacts differ from committed files
run: |
git diff --exit-code
test -z "$(git status --porcelain)"
git -C libbitcoinpqc diff --exit-code
test -z "$(git -C libbitcoinpqc status --porcelain)"
no-skipped-tests:
name: No Skipped Tests Gate
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Ensure ripgrep is available
run: |
if ! command -v rg >/dev/null 2>&1; then
sudo apt-get install -y ripgrep
fi
rg --version
- name: Fail if skipped/ignored tests remain in E2E test trees
run: |
set +e
rg '#\[ignore|it\.skip|describe\.skip|test\.skip|@unittest\.skip|@pytest\.mark\.skip' \
tests/ python/tests nodejs/tests wasm/test
code=$?
set -e
case "$code" in
0)
echo "Skipped/ignored tests found in E2E trees"
exit 1
;;
1)
echo "Gate passed: no skipped/ignored tests"
;;
*)
echo "ripgrep failed with exit code $code"
exit "$code"
;;
esac
test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake libssl-dev
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
components: clippy, rustfmt
- name: Cache dependencies
id: rust-cache
uses: Swatinem/rust-cache@v2
with:
shared-key: v2-${{ hashFiles('libbitcoinpqc/**', 'build.rs') }}
- name: Scrub stale cmake artifacts from rust-cache
run: |
rm -rf target/*/build/bitcoinpqc-*
rm -f target/*/deps/libbitcoinpqc*
rm -f target/*/deps/algorithm_tests-*
rm -f target/*/deps/serialization_tests-*
- name: Check code format
run: cargo fmt -- --check
- name: Clippy
run: cargo clippy -- -D warnings
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose -- --test-threads=1
- name: Run serde tests
run: cargo test --features serde --verbose -- --test-threads=1
- name: Check fuzz workspace
run: cargo check
working-directory: fuzz
build-matrix:
name: Build on ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
rust: [stable]
fail-fast: false
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake libssl-dev
- name: Install dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
brew install cmake
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
toolchain: ${{ matrix.rust }}
components: clippy, rustfmt
- name: Cache dependencies
id: rust-cache
uses: Swatinem/rust-cache@v2
with:
shared-key: v2-${{ hashFiles('libbitcoinpqc/**', 'build.rs') }}
- name: Scrub stale cmake artifacts from rust-cache
run: |
rm -rf target/*/build/bitcoinpqc-*
rm -f target/*/deps/libbitcoinpqc*
rm -f target/*/deps/algorithm_tests-*
rm -f target/*/deps/serialization_tests-*
- name: Check code format
run: cargo fmt -- --check
- name: Clippy
run: cargo clippy -- -D warnings
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose -- --test-threads=1
- name: Run serde tests
run: cargo test --features serde --verbose -- --test-threads=1
- name: Check fuzz workspace
run: cargo check
working-directory: fuzz
c-lib-test:
name: C Library Tests
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake libssl-dev
- name: Cache CMake build
uses: actions/cache@v4
with:
path: build
key: c-lib-test-${{ runner.os }}-${{ hashFiles('libbitcoinpqc/**') }}
restore-keys: |
c-lib-test-${{ runner.os }}-
- name: Configure and build C library
run: |
cmake -B build -S libbitcoinpqc -DBUILD_TESTS=ON -DCMAKE_BUILD_TYPE=Release
cmake --build build
- name: Run C tests
run: ctest --test-dir build --output-on-failure
python-test:
name: Python Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
fail-fast: false
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake libssl-dev
- name: Install dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
brew install cmake
- name: Cache CMake build
uses: actions/cache@v4
with:
path: build
key: python-test-${{ runner.os }}-${{ hashFiles('libbitcoinpqc/**') }}
restore-keys: |
python-test-${{ runner.os }}-
- name: Build C library
run: |
cmake -B build -S libbitcoinpqc -DCMAKE_BUILD_TYPE=Release
cmake --build build
- name: Run Python tests
run: python3 -m unittest discover -s tests -v
working-directory: python
wasm-test:
name: WASM Tests
runs-on: ubuntu-latest
timeout-minutes: 25
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install clang
run: sudo apt-get update && sudo apt-get install -y clang
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown
- name: Cache wasm-pack binary
uses: actions/cache@v4
with:
path: ~/.cargo/bin/wasm-pack
key: wasm-pack-${{ runner.os }}-locked
- name: Install wasm-pack
run: |
if ! command -v wasm-pack >/dev/null 2>&1; then
cargo install wasm-pack --locked
fi
wasm-pack --version
- name: Cache dependencies
id: rust-cache
uses: Swatinem/rust-cache@v2
with:
shared-key: v2-${{ hashFiles('libbitcoinpqc/**', 'build.rs') }}
- name: Scrub stale cmake artifacts from rust-cache
run: |
rm -rf target/*/build/bitcoinpqc-*
rm -f target/*/deps/libbitcoinpqc*
rm -f target/*/deps/algorithm_tests-*
rm -f target/*/deps/serialization_tests-*
- name: Check wasm32 build
run: cargo check --target wasm32-unknown-unknown
- name: Run wasm integration tests (3-algorithm E2E)
run: make wasm-test
emscripten-wasm-test:
name: Emscripten WASM Tests
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
cache-dependency-path: wasm/package-lock.json
- name: Cache Emscripten SDK
uses: actions/cache@v4
with:
path: ~/emsdk
key: emsdk-${{ env.EMSDK_VERSION }}-${{ runner.os }}
- name: Install Emscripten SDK
run: |
if [ ! -f "$HOME/emsdk/emsdk" ]; then
git clone https://github.com/emscripten-core/emsdk.git "$HOME/emsdk"
fi
cd "$HOME/emsdk"
./emsdk install "${{ env.EMSDK_VERSION }}"
./emsdk activate "${{ env.EMSDK_VERSION }}"
- name: Build and test Emscripten wasm package (3-algorithm E2E)
run: |
source "$HOME/emsdk/emsdk_env.sh"
cd wasm
npm ci
npm run build
npm test
nodejs-test:
name: NodeJS Tests (${{ matrix.os }})
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
fail-fast: false
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies (Ubuntu)
if: matrix.os == 'ubuntu-latest'
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake python3
- name: Install dependencies (macOS)
if: matrix.os == 'macos-latest'
run: |
brew install cmake python3
python3 -m pip install --break-system-packages setuptools
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: npm
cache-dependency-path: nodejs/package-lock.json
- name: Install, build, and test
run: |
npm ci --ignore-scripts
npm run build
npm test
working-directory: nodejs
benchmark:
name: Benchmark
runs-on: ubuntu-latest
timeout-minutes: 30
needs: test
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
continue-on-error: true
steps:
- uses: actions/checkout@v4
with:
submodules: recursive
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y build-essential cmake libssl-dev
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache dependencies
id: rust-cache
uses: Swatinem/rust-cache@v2
with:
shared-key: v2-${{ hashFiles('libbitcoinpqc/**', 'build.rs') }}
- name: Scrub stale cmake artifacts from rust-cache
run: |
rm -rf target/*/build/bitcoinpqc-*
rm -f target/*/deps/libbitcoinpqc*
rm -f target/*/deps/algorithm_tests-*
rm -f target/*/deps/serialization_tests-*
- name: Run benchmarks (informational)
env:
CI: true
run: cargo bench --features bench -- --noplot
- name: Upload criterion report
uses: actions/upload-artifact@v4
with:
name: criterion-report
path: target/criterion/
if-no-files-found: warn