Skip to content
Minerva. Post-quantum, proof of work.

Documentation · Releases

Release process: reproducible builds, signing, verification

network/docs/release-process.md · commit e561109 · 2026-10-23

Reproducible node builds

scripts/release/build-node.sh [out-dir] builds minerva-geth so that two builds of the same commit, with the same Go toolchain (go1.22.12) and C compiler, are byte-identical:

  • GOFLAGS=-trimpath -buildvcs=false, GOTOOLCHAIN=local, -ldflags "-buildid= ...";
  • the commit hash and commit date are the only version inputs (no clock);
  • cgo objects (blst, secp256k1) are compiled without -g and with -ffile-prefix-map/-fdebug-prefix-map, so no local path reaches the binary;
  • the tarball is built with sorted names, numeric uid/gid 0, SOURCE_DATE_EPOCH from the commit and gzip -n.

scripts/release/check-reproducible.sh builds twice into separate directories and fails unless the SHA-256 of binary and archive match. Evidence (2026-10-20, commit 73a7404, linux/amd64, go1.22.12, GCC 15):

[minerva-release] reproducible: 0250c223c8b4ffacdda57567913250af7e6c4f2ebe7b22c3e512ac7787700f09  minerva-geth-1.12.22-73a74044-linux-amd64

A release note lists: source commit, Go version, C compiler version, SHA256SUMS, the genesis hashes per profile (minerva doctor --genesis verifies them), the system-contract code hashes (contracts/deployments/<profile>/deployments.json), and the test commands that ran.

Signing

SHA256SUMS is signed with an SSH key (ssh-keygen -Y sign, namespace minerva-release) when MINERVA_RELEASE_KEY is set. Operators verify with scripts/release/verify-release.sh <dir> allowed_signers, where allowed_signers lists the maintainers' public keys:

release@minerva namespaces="minerva-release" ssh-ed25519 AAAA...

Why SSH signatures: every operator machine already has ssh-keygen; no GPG keyring, no web of trust. This is classical signing.

Alongside it, SHA256SUMS.mldsa65.json carries an ML-DSA-65 (FIPS 204) signature over the same file, context MINERVA_RELEASE_V1, produced with the same library the accounts use:

pnpm --filter @minerva/pq-native-tx release:pq keygen release.seed release.pub   # once, offline
MINERVA_RELEASE_PQ_SEED_FILE=release.seed pnpm release:build                     # signs
MINERVA_RELEASE_PQ_PUBLIC_KEY_FILE=release.pub pnpm release:verify build/release # verifies

The signature file records the algorithm, context, the file's SHA-256 and the signer's public key; verification trusts only the public key given on the command line and fails on any byte change of SHA256SUMS (tamper test in the release tooling). Publish release.pub next to the SSH allowed_signers; a release is valid only when both signatures verify.

Container images, when published, must be referenced by digest (image@sha256:...), never by a mutable tag.

Networking plan (Phase 4, design only)

What a public Minerva network needs beyond the devnet, in order:

  1. Bootnodes and ports. Each profile publishes its bootnode enodes in clients/minerva-node/config/<profile>/bootnodes.txt; nodes open TCP/UDP 30303, keep RPC on 127.0.0.1 unless fronted by a reverse proxy, and minerva doctor warns on zero peers outside the devnet.
  2. Node identity. The devp2p node key is the operator's identity today (secp256k1). An authenticated identity scheme that does not depend on ECDSA is a separate reviewed design: the candidate is an ML-DSA-65 node certificate bound to the enode id, exchanged in the RLPx hello as a capability, with peers refusing unauthenticated connections once a fork block passes.
  3. Transport. RLPx key agreement is ECDH over secp256k1. A hybrid ML-KEM-768 + ECDH handshake is the planned upgrade; it is a protocol change for every client and is not scheduled before the account layer ships. Until then, the security claim stays: PQ signatures protect authorization, PoW protects ordering; transport confidentiality is classical.
  4. Operator communications. Release announcements carry the signed SHA256SUMS, genesis hashes and the fork schedule; minerva doctor --genesis is the operator's check. Emergency changes are announced with the same signature.
  5. Update verification. Operators verify a release before installing it (verify-release.sh), and the node refuses to start on a genesis whose hash differs from the profile's published hash once the profile table ships in the binary.