# Changelog
All notable changes to this project are documented here. The format is based on
[Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres
to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
A change to the pinned `schnorrkel` version or to verification behavior is treated
as potentially breaking and versioned deliberately.
## [Unreleased]
## [0.1.0] - 2026-07-02
The first public release: the verification-only core, plus a pre-publish
security-hardening pass (no vulnerabilities found; all hardening changes are
defense-in-depth or supply-chain robustness).
### Added
- **Verification-only v0.1 core.**
- `Sr25519.verify_raw/4` — low-level schnorrkel verify over
`(message, signature, public_key, context)`; validates lengths, a
`max_message_bytes/0` cap on the message and a `max_context_bytes/0` cap on
the signing context (`{:error, :context_too_large}`), and maps every
fallible step to a typed result.
- `Sr25519.Substrate.verify_raw_message/3` — the `"substrate"` context, no wrapping.
- `Sr25519.Substrate.verify_wrapped_bytes/3` — the polkadot-js `signRaw`
convention, mirroring `u8aWrapBytes` exactly: wraps in `<Bytes>…</Bytes>`
unless the message is already wrapped or Ethereum-prefixed (passthrough,
vector-backed).
- Rust NIF over `schnorrkel = "=0.11.5"` with `#![forbid(unsafe_code)]` and
`panic = "unwind"`.
- Frozen cross-implementation vector corpus from four oracles —
`substrate-interface` (production Substrate/Bittensor signer),
`@polkadot/util-crypto` (the polkadot-js wasm signer + exact `signRaw` flow),
`@scure/sr25519` (independent lineage), and the `schnorrkel` crate itself —
and a single-command conformance ladder (`mix conformance`, rungs L0–L7).
- Concurrency and memory-stability tests (parallel verification from 64
processes; 20k-call sustained-load memory bound).
- NIF-safety suite: separate-process deliberate-panic survival test, input fuzzing,
and a p99 < 1 ms latency gate.
- Precompiled distribution via `rustler_precompiled` with a `SR25519_FORCE_BUILD`
source-build escape hatch.
- **`release-verify.yml`** — a pre-publish gate triggered by the checksum
commit: committed checksums must exactly match the GitHub release assets
(both directions), every asset's build-provenance attestation is verified
against `release.yml`, and the real consumer install path (precompiled
download + checksum verification + NIF load + known-answer verifies) is
exercised on Linux/macOS/Windows.
- **All GitHub Actions pinned to commit SHAs** (with dependabot-refreshed
version comments); `persist-credentials: false` on every checkout; `zizmor`
workflow linting and an OpenSSF Scorecard workflow.
- Elixir-side advisory scanning in CI (`mix hex.audit` + `mix deps.audit` via
`mix_audit`).
- Dependabot coverage for the vector-generator manifests
(`vectors/rust_oracle` cargo, `vectors/python` pip) and a pinned
`vectors/python/requirements.txt` matching the frozen corpus metadata.
- `.github/CODEOWNERS`; the release job targets a protectable `release`
environment; RELEASING.md documents the required one-time repository
settings and gates publishing on `Release verify` being green.
- README section **"Verifying release artifacts"** (trust chain,
`gh attestation verify` instructions, residual-trust statement).
- Tests: 1 MiB signature/public-key cheap rejection, `Sr25519.Substrate`
non-binary `:invalid_type` coverage, direct-NIF `ArgumentError` boundary
contract, and direct-NIF wrong-length backstop coverage.
### Changed
- **`verify_raw` now runs on a dirty CPU scheduler.** The 64 KiB cap-sized
transcript absorb could exceed the BEAM's ~1 ms regular-scheduler guideline
on slow release targets (armv7, riscv64); scheduler fairness no longer
depends on verify latency. The p99 < 1 ms benchmark stays as a
perf-regression gate. Verification behavior is unchanged.
- **schnorrkel is built with `default-features = false` (`alloc`)**: the OS-RNG
stack (`getrandom`, `rand`, `rand_chacha`, `ppv-lite86`, `zerocopy`, `aead`,
`wasi`) is no longer linked into the verify-only NIF — 8 fewer supply-chain
crates. Proven behavior-identical by the frozen vector corpus.
- `Sr25519.verify_raw/4` rejects wrong-length signatures/public keys before
calling the NIF (the Rust checks remain the authoritative backstop, still
covered by direct-NIF tests).
- The release profile builds with `overflow-checks = true` (an overflow panics
and unwinds into a typed error instead of silently wrapping).
- `cargo-deny` now **fails** on duplicate crate versions (was: warn).
### Fixed
- SECURITY.md claimed builds use `--locked`; the actual mechanism is a
`cargo metadata --locked` integrity gate in CI and release (rustler does not
pass `--locked` to cargo).
- README/moduledoc/package wording no longer reads as if this wrapper were
audited — `schnorrkel` is audited upstream; the wrapper is human-reviewed.
- Documented that legacy pre-0.8 unmarked schnorrkel signatures verify as
`{:ok, false}` (the deprecated `preaudit_deprecated` encoding is deliberately
not enabled).
[Unreleased]: https://github.com/VFe/sr25519/compare/v0.1.0...HEAD
[0.1.0]: https://github.com/VFe/sr25519/commits/v0.1.0