Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5777f5b
gitignore build and lsp artifacts
matthew-levan Oct 21, 2025
edd1727
add testing framework
matthew-levan Oct 22, 2025
9c81953
add argon2 tests
matthew-levan Oct 22, 2025
4da676c
add blake3 tests
matthew-levan Oct 22, 2025
80f2f45
add ed25519 w/ ge-additions tests
matthew-levan Oct 23, 2025
6f89cfc
cleanup build, tests, and instructions
matthew-levan Oct 23, 2025
7b02a07
add keccak tests
matthew-levan Oct 27, 2025
f5f5349
add chacha tests
matthew-levan Oct 27, 2025
3a14355
add scrypt tests
matthew-levan Oct 27, 2025
424cd37
cleanup tests
matthew-levan Oct 27, 2025
d0006f1
add urcrypt tests
matthew-levan Oct 28, 2025
435f528
cleanup test running
matthew-levan Oct 28, 2025
f474eb8
cleanup readmes and rm murmur3 tests (not in this repo)
matthew-levan Oct 29, 2025
b260235
do not ignore test runner
matthew-levan Oct 29, 2025
4d619fc
cleanup comments
matthew-levan Oct 30, 2025
5a3abed
add ci
matthew-levan Nov 5, 2025
af7f207
fix point addition ed25519 test on linux
matthew-levan Nov 5, 2025
662d056
factor `test_urcrypt.c` into separate suite files
matthew-levan Nov 7, 2025
46e296b
exports `urcrypt_reverse` (delete one cab) and use it
matthew-levan Nov 7, 2025
7f6dbde
Merge branch 'ml/tests' of https://github.com/urbit/urcrypt into ml/t…
matthew-levan Nov 7, 2025
387536d
re-privatizes `urcrypt__reverse` and links directly to `.o` file for …
matthew-levan Nov 9, 2025
680fc61
vendors libaes-siv v1.0.1 (9681279cfaa6e6399bb7ca3afbbc27fc2e19df4b)
joemfb May 29, 2026
75706c9
replaces openssl with nettle (including in vendored libaes-siv)
joemfb May 29, 2026
802b32b
refactors aes-siv, removing dynamic ctx allocation
joemfb May 29, 2026
08a0b29
Merge jb/close-ssl into ml/tests
matthew-levan Jun 3, 2026
99e48e8
ci: rebuild workflow for the Nettle / vendored-aes-siv build
matthew-levan Jun 3, 2026
0e6b434
scrypt: pin -std=gnu17 to allow K&R definitions under C23 compilers
matthew-levan Jun 3, 2026
01fdeb6
ci: scope UBSan to urcrypt's own code; build sanitizer job with clang
matthew-levan Jun 3, 2026
4e26d74
ci: fetch nettle from gnutls/nettle mirror; build statically on Linux
matthew-levan Jun 3, 2026
f327ea6
ci: fetch nettle from the signed GNU release tarball, verified by sha256
matthew-levan Jun 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions .github/actions/setup-crypto-deps/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
name: 'Set up crypto dependencies'
description: >
Build and install GNU Nettle and libsecp256k1 (with the recovery and Schnorr
modules that urcrypt's configure requires) from source into a cached prefix,
then export the NETTLE_*/LIBSECP256K1_* and runtime library-path variables
that ./configure and the test runner need.

inputs:
prefix:
description: 'Install prefix for the built dependencies.'
required: true
nettle-version:
description: 'GNU Nettle release to build from the ftp.gnu.org tarball (e.g. 4.0).'
required: true
nettle-sha256:
description: 'Expected sha256 of nettle-<version>.tar.gz, verified before use.'
required: true
secp256k1-ref:
description: 'libsecp256k1 git tag/ref to build (e.g. v0.7.1).'
required: true

runs:
using: composite
steps:
# Distro/Homebrew packages are too old (nettle < 4.0) or omit the secp256k1
# recovery/Schnorr modules, so both are built from source and cached. The
# cache key pins the exact versions, so a bump invalidates it automatically.
- name: Restore cached dependencies
id: cache
uses: actions/cache@v4
with:
path: ${{ inputs.prefix }}
key: cryptodeps-${{ runner.os }}-${{ runner.arch }}-nettle${{ inputs.nettle-version }}-secp${{ inputs.secp256k1-ref }}-v3

- name: Build GNU Nettle ${{ inputs.nettle-version }}
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: |
set -euo pipefail
# nettle >= 4.0 introduced the 2-argument *_digest() interface urcrypt uses.
# Use the signed GNU release tarball (canonical, ships a generated
# configure) and verify its sha256 before building.
cd "$RUNNER_TEMP"
tarball="nettle-${{ inputs.nettle-version }}.tar.gz"
curl -fsSLO "https://ftp.gnu.org/gnu/nettle/${tarball}"
if command -v sha256sum >/dev/null 2>&1; then
echo "${{ inputs.nettle-sha256 }} ${tarball}" | sha256sum -c -
else
echo "${{ inputs.nettle-sha256 }} ${tarball}" | shasum -a 256 -c -
fi
tar xzf "${tarball}"
cd "nettle-${{ inputs.nettle-version }}"
# On Linux build static libraries (urcrypt links them statically, the
# way urbit/vere consumes it); -fPIC so they still link into PIE binaries.
# macOS can't fully static-link, so build shared there.
if [ "$RUNNER_OS" = "Linux" ]; then
LINKAGE="--enable-static --disable-shared"
export CFLAGS="${CFLAGS:-} -fPIC"
else
LINKAGE="--disable-static"
fi
# --enable-mini-gmp avoids needing libgmp; urcrypt only links libnettle.
./configure --prefix="${{ inputs.prefix }}" --enable-mini-gmp \
--disable-documentation $LINKAGE
make -j"$(getconf _NPROCESSORS_ONLN)"
make install

- name: Build libsecp256k1 ${{ inputs.secp256k1-ref }}
if: steps.cache.outputs.cache-hit != 'true'
shell: bash
run: |
set -euo pipefail
cd "$RUNNER_TEMP"
git clone --depth 1 --branch "${{ inputs.secp256k1-ref }}" \
https://github.com/bitcoin-core/secp256k1.git
cd secp256k1
./autogen.sh
# Static (with PIC) on Linux to match the static urcrypt link; shared on macOS.
if [ "$RUNNER_OS" = "Linux" ]; then
LINKAGE="--enable-static --disable-shared --with-pic"
else
LINKAGE="--disable-static"
fi
./configure --prefix="${{ inputs.prefix }}" \
--enable-module-recovery --enable-module-schnorrsig --enable-module-ecdh \
--disable-benchmark --disable-tests --disable-exhaustive-tests $LINKAGE
make -j"$(getconf _NPROCESSORS_ONLN)"
make install

- name: Export dependency environment
shell: bash
run: |
set -euo pipefail
prefix="${{ inputs.prefix }}"
# Set the *_CFLAGS/*_LIBS that PKG_CHECK_MODULES honours directly, so the
# build is deterministic regardless of any system pkg-config files.
{
echo "NETTLE_CFLAGS=-I${prefix}/include"
echo "NETTLE_LIBS=-L${prefix}/lib -lnettle"
echo "LIBSECP256K1_CFLAGS=-I${prefix}/include"
echo "LIBSECP256K1_LIBS=-L${prefix}/lib -lsecp256k1"
echo "PKG_CONFIG_PATH=${prefix}/lib/pkgconfig"
} >> "$GITHUB_ENV"
# On macOS the deps are shared, so the test runner needs the loader path.
# On Linux they are linked statically, so no runtime path is required.
if [ "$RUNNER_OS" = "macOS" ]; then
echo "DYLD_LIBRARY_PATH=${prefix}/lib" >> "$GITHUB_ENV"
fi
145 changes: 145 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
name: CI

on:
push:
branches: [jb/close-ssl, master]
pull_request:
branches: [jb/close-ssl, master]

# Cancel an in-progress run when a newer commit is pushed to the same ref.
concurrency:
group: ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

env:
# urcrypt requires nettle >= 4.0 (2-argument *_digest() interface) and a
# libsecp256k1 built with the recovery + Schnorr modules. Neither is available
# from the runners' package managers, so both are built from source (cached).
NETTLE_VERSION: "4.0"
NETTLE_SHA256: "3addbc00da01846b232fb3bc453538ea5468da43033f21bb345cb1e9073f5094"
SECP256K1_REF: "v0.7.1"

jobs:
build-test:
name: build & test (${{ matrix.os }})
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest]
steps:
- uses: actions/checkout@v4

- name: Install build tools (Ubuntu)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y \
autoconf automake libtool pkg-config autoconf-archive m4 build-essential

- name: Install build tools (macOS)
if: runner.os == 'macOS'
run: |
brew install autoconf automake libtool pkg-config autoconf-archive

- name: Set up crypto dependencies
uses: ./.github/actions/setup-crypto-deps
with:
prefix: ${{ github.workspace }}/.deps
nettle-version: ${{ env.NETTLE_VERSION }}
nettle-sha256: ${{ env.NETTLE_SHA256 }}
secp256k1-ref: ${{ env.SECP256K1_REF }}

- name: Build
run: |
./autogen.sh
# Build statically on Linux (the deps are static there, matching how
# urbit/vere links urcrypt); macOS can't fully static-link, so shared.
if [ "$RUNNER_OS" = "Linux" ]; then
./configure --enable-static --disable-shared
else
./configure
fi
make -j"$(getconf _NPROCESSORS_ONLN)"

- name: Test
run: make check

- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: logs-${{ matrix.os }}
path: |
config.log
test-suite.log
test_runner.log
if-no-files-found: ignore

sanitizers:
name: ASan + UBSan (Ubuntu)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install build tools
run: |
sudo apt-get update
sudo apt-get install -y \
autoconf automake libtool pkg-config autoconf-archive m4 build-essential clang

- name: Set up crypto dependencies
uses: ./.github/actions/setup-crypto-deps
with:
prefix: ${{ github.workspace }}/.deps
nettle-version: ${{ env.NETTLE_VERSION }}
nettle-sha256: ${{ env.NETTLE_SHA256 }}
secp256k1-ref: ${{ env.SECP256K1_REF }}

# Built with clang so UBSan can be scoped to urcrypt's own code via an
# ignore list (an -fsanitize-ignorelist= feature gcc lacks). ASan still
# covers everything, including the vendored libraries.
- name: Build & test with sanitizers
env:
# Leak detection is off: the one-shot test runner intentionally does
# not free every allocation, which is not a defect under test.
ASAN_OPTIONS: detect_leaks=0:abort_on_error=1
UBSAN_OPTIONS: print_stacktrace=1:halt_on_error=1
run: |
./autogen.sh
./configure --enable-static --disable-shared CC=clang \
CFLAGS="-fsanitize=address,undefined -fno-sanitize-recover=all -fsanitize-ignorelist=${{ github.workspace }}/ci/sanitizer-ignorelist.txt -g -O1" \
LDFLAGS="-fsanitize=address,undefined"
make -j"$(getconf _NPROCESSORS_ONLN)"
make check

- name: Upload logs on failure
if: failure()
uses: actions/upload-artifact@v4
with:
name: logs-sanitizers
path: |
config.log
test-suite.log
test_runner.log
if-no-files-found: ignore

static-analysis:
name: cppcheck (non-blocking)
runs-on: ubuntu-latest
# Advisory only: findings are surfaced but do not fail the workflow.
continue-on-error: true
steps:
- uses: actions/checkout@v4

- name: Install cppcheck
run: |
sudo apt-get update
sudo apt-get install -y cppcheck

- name: Run cppcheck on urcrypt sources
# Analyse only urcrypt's own code, not the bulk-vendored libraries.
run: |
cppcheck --enable=warning,portability --inline-suppr --error-exitcode=1 \
--std=c11 --suppress=missingInclude --suppress=missingIncludeSystem \
-I urcrypt -I aes_siv urcrypt aes_siv
23 changes: 20 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ autom4te.cache
/aclocal.m4
build-aux/compile
/config.cache
build-aux/config.guess
build-aux/config.guess*
/config.h.in
/config.h.in~
build-aux/config.log
build-aux/config.status
build-aux/config.sub
build-aux/config.sub*
/configure
/configure~
/configure.scan
build-aux/depcomp
build-aux/install-sh
build-aux/install-sh*
build-aux/missing
/stamp-h1

Expand All @@ -57,3 +57,20 @@ build-aux/m4/lt~obsolete.m4
# (which is called by configure script))
Makefile

# clangd
compile_commands.json
**/*.cache
**/*.libs
config.log

# build artifacts
**/*.o
**/*.la
**/*.lo

# tests
build-aux/test-driver
test_runner
test_runner.log
test_runner.trs
test-suite.log
Loading
Loading