Phase 8 B: real Ed25519 keygen/signing, verified against OpenSSL
Extends the previously verify-only ed25519.c with ed25519_keygen() and ed25519_sign() per RFC 8032 5.1.5/5.1.6, reusing every point-arithmetic primitive verify already had -- only seed expansion/clamping and per-message nonce derivation are new. Signing is deterministic; only keygen ever touches entropy, via a caller-supplied seed (virtio_rng, Phase A) -- keygen still generates nothing itself. New scalar_muladd() (scalar25519.c) for signing's S = (k*a + r) mod L, the one scalar op verify never needed. Schoolbook multiply into a u128 wide accumulator with one final carry pass -- deliberately the same shape as fe25519.c's existing multiply, which has a documented history of a real bug from carrying mid-accumulation instead of in one pass. Verified against an independent implementation, not self-consistency: a throwaway host harness against Python's cryptography library (OpenSSL- backed) across 6 trials (5 random seed/message pairs + the empty-message case) produced byte-for-byte identical pubkeys and signatures every time. Clean compile on all three architectures and a full 3-arch QEMU acceptance boot, conservation intact, no panics or guest errors. Nothing calls the new functions from the live kernel path yet -- that's Phase C (the MINT word itself), still open, documented in FABRIC-3.md. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01U14ET9CWAtbQMbYqomKgXd
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
309e792f07
commit
53e6c5709f
+39
@@ -393,6 +393,45 @@ decisions get added here, not to `FABRIC-2.md`. Follow the same discipline `FABR
|
||||
(the `MINT` word itself, cert format, and whether Zuse's own keypair needs to chain to the
|
||||
Milestone 6 offline root CA or is a self-sovereign instance-local root of trust).**
|
||||
|
||||
**Phase B — real Ed25519 keygen/signing, done 2026-08-26.** Extended
|
||||
`include/starkernel/ed25519.h`/`src/starkernel/crypto/ed25519.c` (previously verify-only)
|
||||
with `ed25519_keygen(seed, pubkey_out)` and `ed25519_sign(seed, msg, msg_len, sig_out)`, per
|
||||
RFC 8032 §5.1.5/5.1.6, reusing every point-arithmetic primitive verify already had
|
||||
(`scalar_mult`, `point_compress`, the base-point constants) — no new curve code, only the
|
||||
seed-expansion/clamping and per-message nonce derivation verify never needed. Signing is
|
||||
deterministic (nonce derived from seed+message, not fresh randomness): only keygen ever
|
||||
touches entropy, via a caller-supplied seed (`virtio_rng_get_bytes()`, Phase A) — keygen
|
||||
itself still generates nothing and trusts the caller for randomness quality, matching this
|
||||
file's original design philosophy exactly.
|
||||
|
||||
New `scalar_muladd()` (`scalar25519.c`/`.h`) for signing's `S = (k*a + r) mod L` step, the
|
||||
one piece of scalar arithmetic verify never needed (verify only ever reduced or compared,
|
||||
never multiplied scalars). Schoolbook 256×256-bit multiply into a `u128` wide accumulator
|
||||
with exactly one final carry-propagation pass — deliberately the same shape as `fe25519.c`'s
|
||||
existing field multiply, because that file's own history records a real bug from trying to
|
||||
carry mid-accumulation instead of in one final pass; structurally can't repeat that mistake
|
||||
this way. Reduces the result via the existing, already-proven `scalar_reduce512()` rather
|
||||
than writing new modular-reduction logic.
|
||||
|
||||
**Verified against an independent implementation, not self-consistency** — this project's
|
||||
own standing lesson (two real, invisible-by-inspection bugs in the original from-scratch
|
||||
field arithmetic, an off-by-one-hex-digit hand-transcribed SHA-512 vector) means a passing
|
||||
self-check proves nothing on its own. Built a throwaway host test harness (compiled, run,
|
||||
discarded — the crypto files have no `__STARKERNEL__` gate, so they link as an ordinary
|
||||
Linux binary) against Python's `cryptography` library (OpenSSL-backed). Six trials — five
|
||||
random seed/message pairs (message lengths 1, 32, 255, 1000 bytes) plus the empty-message
|
||||
case — every one produced a byte-for-byte identical public key and signature to the
|
||||
independent implementation, not just a signature this codebase's own verify accepted.
|
||||
**Verified on-target too:** clean zero-warning compile of the crypto files on all three
|
||||
architectures, and a full 3-arch QEMU acceptance boot (amd64/aarch64/riscv64) — all clean to
|
||||
`ok>`, Stadium conservation intact, no panics or guest errors. Nothing calls
|
||||
`ed25519_keygen()`/`ed25519_sign()` from the live kernel path yet (Phase C's job); this pass
|
||||
is compile/link/boot-regression verification for the crypto library itself.
|
||||
|
||||
**Still open: Phase C** — the `MINT` word itself, cert format, and whether Zuse's own
|
||||
keypair needs to chain to the Milestone 6 offline root CA or is a self-sovereign
|
||||
instance-local root of trust.
|
||||
|
||||
### From FABRIC-2.md §X, Milestone 5 — Console/VM key-match binding
|
||||
|
||||
- [ ] Settle the still-open question: reuse `ACL-PIN`/`acl_allow` directly, or build a
|
||||
|
||||
Reference in New Issue
Block a user