Skip to content

ci: test suite + GitHub Actions on the Nettle build#23

Open
matthew-levan wants to merge 27 commits into
jb/close-sslfrom
ml/tests
Open

ci: test suite + GitHub Actions on the Nettle build#23
matthew-levan wants to merge 27 commits into
jb/close-sslfrom
ml/tests

Conversation

@matthew-levan
Copy link
Copy Markdown
Collaborator

@matthew-levan matthew-levan commented Jun 3, 2026

Brings the ml/tests test suite onto the jb/close-ssl (OpenSSL→Nettle + vendored aes-siv) base and replaces the stale CI with one that matches the current dependencies.

What's here

Merge jb/close-ssl into ml/tests — conflicts resolved in favour of the Nettle / vendored aes_siv/ implementation. Makefile.am's test_runner now links Nettle + the vendored libaes_siv.la (dropping the OpenSSL LIBCRYPTO_*, external -laes_siv, and /usr/local rpath). README install notes updated.

New CI (.github/workflows/ci.yml):

  • Triggers on push/PR to jb/close-ssl and master.
  • build & test matrix on ubuntu-latest + macos-latest.
  • AddressSanitizer + UBSan job (Ubuntu).
  • cppcheck over urcrypt/ + aes_siv/ (non-blocking).

.github/actions/setup-crypto-deps — composite action that builds & caches the two dependencies the runners' package managers can't provide:

  • nettle 4.0 from ftp.gnu.org (--enable-mini-gmp),
  • libsecp256k1 v0.7.1 with --enable-module-recovery --enable-module-schnorrsig --enable-module-ecdh.

Heads-up: requires nettle 4.0

jb/close-ssl calls the 2-argument *_digest() interface and relies on deprecated symbols (e.g. struct aes_ctx) being gone — both are nettle 4.0 changes (released 2026-02-05). It does not compile against nettle 3.x. Homebrew ships 3.10.2 and Ubuntu ships 3.7–3.9, so ./configure fails on stock installs; CI therefore builds nettle 4.0 from source.

Verification

Built nettle 4.0 from source locally and ran make check: all 11 suites, 198/198 checks pass.

Tests and test vectors

The suite (tests/, 11 modules, 198 checks) uses a small custom harness (tests/test_common.h) run as a single test_runner via make check. The vectors are, wherever a standard publishes them, the official reference/standards vectors — each test_*.c cites its source in the file header:

Suite Vector source
AES ECB/CBC NIST FIPS 197, Appendix C
AES-SIV RFC 5297, Appendix A
SHA-1/256/512 NIST CAVP (Secure Hashing)
RIPEMD-160 Official RIPEMD-160 page (Bosselaers, KU Leuven)
BLAKE3 (hash / keyed / derive_key) Official BLAKE3 test_vectors.json
BLAKE2b Argon2 reference implementation
Argon2i Argon2 reference implementation (test.c)
Ed25519 (sign/verify, X25519) RFC 8032 (TEST 1–3)
Keccak-256 Ethereum js-ethereum-cryptography vectors (Keccak 0x01 padding, distinct from NIST SHA-3/FIPS 202)
ChaCha20 draft-strombergson-chacha-test-vectors-01 (DJB original, 8-byte nonce)
HChaCha20 / XChaCha20 draft-irtf-cfrg-xchacha-03
scrypt RFC 7914
PBKDF2-SHA256 RFC 6070
secp256k1 ECDSA + recovery Bitcoin Core secp256k1
secp256k1 Schnorr BIP-340

The one exception is test_ge_additions.c (extra Ed25519 group-element operations like scalarmult): these have no single published vector set, so they are structural/round-trip and algebraic-identity checks built on RFC 8032 scalars rather than canonical vectors.

CI issues found and fixed

  1. macOS build — scrypt/b64.c K&R errors. The macos-latest runner's clang defaults to C23, which removes K&R function definitions; vendored libscrypt still uses them. Fixed by pinning the scrypt library to -std=gnu17 (Makefile.am). Reproduced and verified locally by forcing a C23 build.
  2. ASan/UBSan — ed25519/src/fe.c:721 left shift of negative value. A benign UBSan finding in the vendored ed25519 reference code (validated by its own test vectors), not urcrypt's code. Fixed by building the sanitizer job with clang and an -fsanitize-ignorelist (ci/sanitizer-ignorelist.txt) that excludes the vendored libraries from UBSan while keeping AddressSanitizer on everything — mirroring the cppcheck scope. Verified locally that the error reproduces without the list and disappears with it.

Dependency sourcing

Nettle is built from the canonical ftp.gnu.org release tarball (nettle-4.0.tar.gz), pinned and verified by sha256 (3addbc00...f5094) before use. secp256k1 is built from its pinned git tag (v0.7.1).

We deliberately use the GNU tarball rather than the gnutls/nettle GitHub mirror:

  • The GNU tarball is the official, GPG-signed release artifact and ships a generated configure (no ./.bootstrap/autoconf step).
  • The GitHub mirror is a third-party mirror whose auto-generated archive checksums are not guaranteed byte-stable, so a hash pin against it is fragile; it could also lag, be renamed, or be removed.

For a dependency this security-sensitive, a checksum-pinned signed tarball is the stronger supply chain. The nettle-version/nettle-sha256 pair lives at the top of the workflow, so bumping the version is a one-line change plus the new hash.

🤖 Generated with Claude Code

matthew-levan and others added 23 commits October 21, 2025 10:25
Brings the test suite (tests/, make check) onto the OpenSSL->Nettle base.

Conflicts resolved in favour of jb/close-ssl's Nettle + vendored aes_siv/
implementation; the test wiring in Makefile.am is rewritten to link Nettle
and the vendored libaes_siv.la (dropping the OpenSSL LIBCRYPTO_* / external
-laes_siv references and the /usr/local rpath). configure.ac keeps the
nettle >= 4.0 / secp256k1 recovery+Schnorr checks; README dependency and
install notes updated for Nettle + building secp256k1 with the required
modules.

Verified: all 11 suites (198 checks) pass against nettle 4.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replaces the stale OpenSSL-era CI (libssl-dev + cloning libaes_siv) with a
workflow matching the current dependencies:

- Triggers on push/PR to jb/close-ssl and master.
- build & test matrix on ubuntu-latest and macos-latest.
- A reusable composite action (.github/actions/setup-crypto-deps) builds the
  two dependencies the runners' package managers can't provide and caches
  them: nettle 4.0 (needed for the 2-argument *_digest() interface) from
  ftp.gnu.org, and libsecp256k1 v0.7.1 with the recovery + Schnorr modules.
- An AddressSanitizer + UBSan job, and a non-blocking cppcheck job over
  urcrypt/ and aes_siv/.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@matthew-levan matthew-levan requested a review from a team as a code owner June 3, 2026 21:51
Vendored libscrypt (b64.c, crypto_scrypt-nosse.c, sha256.c) uses K&R-style
function definitions, which C23 removes. Recent Apple clang on the macos-latest
runner defaults to C23 and rejected them ("unknown type name 'src'"), while
gcc and older clang (defaulting to gnu17) compiled fine. Pin the scrypt library
to -std=gnu17 so the build is deterministic across compilers.
The ASan+UBSan job failed on a benign UBSan finding in the vendored ed25519
reference code (ed25519/src/fe.c:721: "left shift of negative value"), which is
exercised via its own test vectors and is not urcrypt's code to fix.

Build the sanitizer job with clang and pass an -fsanitize-ignorelist (a clang
feature gcc lacks) that excludes the vendored libraries from UBSan, mirroring
the cppcheck scope. AddressSanitizer still instruments everything.

Verified locally: without the ignore list the ed25519 shift error reproduces
and `make check` fails; with it, all 11 suites (198 checks) pass clean.
- Nettle is now cloned from the gnutls/nettle GitHub mirror at the 4.0 release
  tag (nettle_4.0_release_20260205) and bootstrapped (./.bootstrap runs
  autoconf, since the mirror ships no generated configure) instead of pulling
  the ftp.gnu.org tarball. jb/close-ssl only requires nettle >= 4.0 with no
  pinned version, and 4.0 is the sole 4.x release, so this matches.

- On Linux the dependencies (nettle, secp256k1) are built as static libraries
  with -fPIC, and urcrypt is configured --enable-static --disable-shared, so the
  test runner links them statically -- matching how urbit/vere links urcrypt
  statically. macOS keeps shared/dynamic linking (it can't fully static-link).

- README updated: build nettle 4.0 from the mirror, point configure at it, and
  run the tests.

Verified locally: a static build (static nettle + static secp256k1, urcrypt
--enable-static --disable-shared) passes all 11 suites (198 checks), and
otool -L confirms no dynamic nettle/secp linkage in the test runner.
Switch nettle back from the gnutls/nettle GitHub mirror to the canonical
ftp.gnu.org release tarball, pinned and verified by sha256
(3addbc00...f5094 for nettle-4.0.tar.gz).

Rationale: the GNU tarball is the official, GPG-signed release artifact and
ships a generated configure (no ./.bootstrap / autoconf needed). The GitHub
mirror is a third-party mirror whose auto-generated archive checksums are not
guaranteed byte-stable, making a hash pin fragile. For a dependency this
security-sensitive, a checksum-pinned signed tarball is the stronger supply
chain. The sha256 is verified before the tarball is used; a mismatch aborts.

README updated to match (build nettle 4.0 from the tarball).
@matthew-levan matthew-levan mentioned this pull request Jun 3, 2026
Comment thread .github/workflows/ci.yml
Comment on lines +5 to +7
branches: [jb/close-ssl, master]
pull_request:
branches: [jb/close-ssl, master]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's get my branch out of here.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Including jb/close-ssl temporarily is necessary for CI to run. Once this PR is merged to master, we can remove it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants