Skip to content

[L1-6] (Phase A) ed25519 signing + 8-event contract chain primitives#1447

Closed
joelteply wants to merge 2 commits into
feat/l1-1-event-class-registryfrom
feat/l1-6-contract-event-chain
Closed

[L1-6] (Phase A) ed25519 signing + 8-event contract chain primitives#1447
joelteply wants to merge 2 commits into
feat/l1-1-event-class-registryfrom
feat/l1-6-contract-event-chain

Conversation

@joelteply
Copy link
Copy Markdown
Contributor

Summary

L1-6 Phase A — pure Rust primitives. The verifier-side integration (Phase B) lands after L1-4 (presence:peer-manifest) merges.

  • Closes roadmap item L1-6 (Phase A) — primitives + types + registration + tests
  • Depends on: L1-1 PR #1445 (pending review — this PR targets that branch as base so it auto-rebases onto canary when L1-1 merges)
  • Composes with: L1-2 (feat(airc): add typed event transport seam #1443 AircEventTransport, already merged) — Phase B will subscribe its replay() for audit-reproducible chain verification
  • Defers: L1-4 (presence:peer-manifest, in flight by claude-tab-1) — Phase B uses its per-peer pubkey index for cross-check
  • Spec: GRID-BUS-ARCHITECTURE §4.4 + MULTI-PEER-COMMANDS §7

Why Phase A / Phase B split

Phase A is pure crypto + types + declarations. Zero runtime deps on L1-4 or L1-2 transports. Shipping it now means review can focus on the cryptographic substance before transport plumbing layers on top.

Phase B wires:

  • Pulls signer pubkeys from L1-4's presence:peer-manifest index at verify time
  • Hooks into L1-2's AircEventTransport.replay() for audit-reproducible chain verification

What this lands

Rust truth (continuum-core::contracts)

signing.rs — ed25519 primitives matching airc-protocol's pinned ed25519-dalek = "2".

  • ContractSigningKey / ContractVerifyingKey wrappers — gives future migration room (HSM, secure enclave) without touching call sites
  • Deterministic ed25519 → replay-equivalent signatures across peers
  • canonical_hash() uses serde_json's BTreeMap-backed Value to produce key-sorted SHA-256 input — same bytes regardless of build, the keystone for cross-peer verify-equality
  • verify() returns Err (NOT Ok(false)) so callers can't accidentally treat a failed verify as success

event_classes.rs — the 8 contract event class names + typed payload structs (ts-rs export to shared/generated/contracts/)

  • Each payload carries contract_id for chain correlation
  • declare_contract_event_classes() registers all 8 with the L1-1 registry — broadcast: true, channel: Global, schemaVersion: v1

envelope.rs — generic SignedContractEvent<P> wrapper

  • Signature pins (event_name, payload) together so relabeling attacks (presenting a bid sig as proposed) fail verification
  • Hex-encoded pubkey + signature on the wire (no JSON-binary-string ambiguity)

Crypto choices

Choice Why
ed25519-dalek = "2" Matches airc-protocol's pinned version — peer signing keys advertised through L1-4's presence:peer-manifest use the SAME byte layout this module verifies. No re-encoding, no protocol bridging.
Deterministic ed25519 Replay-equivalence: two signs of the same payload by the same key produce byte-identical signatures.
SHA-256 canonical hash Pin the signed bytes to key-sorted JSON — eliminates serializer-flavor drift between peer builds.
verify() -> Result<> not Result<bool> Force callers to handle the failure path explicitly; never accidentally treat a failed verify as success.

Tests (31 pass via cargo test --features metal,accelerate contracts)

  • signing (10): keygen→sign→verify roundtrip; pubkey roundtrip-through-bytes; bad-signature-fails-loud; wrong-payload-fails-loud; cross-key-verify-fails; ed25519-determinism; canonical-hash-stable-across-field-order; signature/pubkey length validation
  • event_classes (3 + 8 ts-rs exports): all-8-names-distinct; all-use-contract-prefix; declare-registers-all-eight (dogfoods the L1-1 registry)
  • envelope (8): sign-then-verify roundtrip; relabeling-attack-fails; payload-mutation-fails; signature-mutation-fails; pubkey-swap-fails; JSON-round-trips-bit-exact; hex-helpers roundtrip + reject-bad-input
  • chain_tests (3): full 8-event proposed → bid → accepted → executing → delivered → verified → paid worked example (zero-LP household tier "ping grid dispatch"); disputed-event signs + verifies; JSON-bit-exact round trip on the full chain

Out of scope (Phase B follow-up)

  • Pull signer pubkeys from L1-4's presence:peer-manifest index at verify time
  • Subscribe to airc-cursor replay over L1-2's AircEventTransport for audit-reproducible chain verification
  • TS thin SDK wrapper (parallel to @system/events/shared/EventClass.ts). Deferred until a TS consumer materializes — Phase A consumers are Rust-side (router daemon, persona admission)

Test plan

  • cd src/workers/continuum-core && cargo test --features metal,accelerate contracts (31 tests)
  • Cryptographer review of the wire-format pinning + canonical-hash discipline

🤖 Generated with Claude Code

joelteply and others added 2 commits May 25, 2026 20:24
* feat(commands): add typed execution scope

* chore: lower linux eslint baseline

---------

Co-authored-by: Test <test@test.com>
…n primitives

Roadmap item L1-6 — Phase A. Builds on L1-1 (#1445) for the event-class
registry. Phase B (verify-on-replay via L1-4's peer-manifest + airc-cursor
replay over L1-2 transport) lands in a follow-up once L1-4 merges.

Closes roadmap item L1-6 (Phase A — primitives + types + registration + tests)
Depends on: L1-1 (PR #1445, pending review)
Defers: L1-4 (presence:peer-manifest, in flight by claude-tab-1) +
         L1-2 (AircEventTransport trait, already merged as #1443)
Spec: GRID-BUS-ARCHITECTURE §4.4 + MULTI-PEER-COMMANDS §7

Why split Phase A vs B
- Phase A is pure crypto + types + declarations — zero runtime deps on
  L1-4 or L1-2 transports.
- Phase B wires the verifier-side: pulls signer pubkeys from L1-4's
  peer-manifest index, hooks into L1-2's AircEventTransport.replay()
  for audit-replayable chain verification.
- Shipping A now means review can focus on the cryptographic substance
  before transport plumbing layers on top.

What this lands

Rust truth (continuum-core::contracts):
- signing.rs — ed25519 primitives matching airc-protocol's pinned
  ed25519-dalek = "2". Wrappers ContractSigningKey + ContractVerifyingKey
  give future migration room (HSM, secure enclave) without touching
  call sites. Deterministic ed25519 → replay-equivalent signatures
  across peers. canonical_hash() uses serde_json's BTreeMap-backed
  Value for key-sorted SHA-256 input — same bytes regardless of build,
  the keystone for cross-peer verify-equality. Verify returns Err on
  failure (NOT Ok(false)) so callers can't accidentally treat a failed
  verify as success.
- event_classes.rs — the 8 contract event class names (constants) +
  typed payload structs (ts-rs export to shared/generated/contracts/).
  Each payload carries contract_id for chain correlation.
  declare_contract_event_classes() registers all 8 with the L1-1
  registry, broadcast=true, channel=Global, schemaVersion=v1.
- envelope.rs — generic SignedContractEvent<P> wrapper. Signature pins
  (event_name, payload) together so relabeling attacks (presenting a
  bid sig as proposed) fail verification. Hex-encoded pubkey +
  signature on the wire.

Tests (31 pass via cargo test --features metal,accelerate contracts)
- signing: keygen→sign→verify roundtrip, pubkey roundtrip-through-bytes,
  bad-signature-fail-loud, wrong-payload-fail-loud, cross-key-verify-fail,
  ed25519-determinism, canonical-hash-stable-across-field-order,
  signature/pubkey length validation.
- event_classes: all-8-names-distinct, all-use-contract-prefix,
  declare-registers-all-eight (dogfoods the L1-1 registry).
- envelope: sign-then-verify roundtrip, relabeling-attack-fails,
  payload-mutation-fails, signature-mutation-fails, pubkey-swap-fails,
  JSON-round-trips-bit-exact, hex-helpers roundtrip + reject-bad-input.
- chain_tests: full 8-event proposed→bid→accepted→executing→delivered→
  verified→paid worked example (zero-LP household tier "ping grid
  dispatch"), disputed-event-signs-and-verifies, JSON-bit-exact round
  trip on the full chain.

What this does NOT do (Phase B follow-up)
- Pull signer pubkeys from L1-4's presence:peer-manifest index at
  verify time. Today verify returns the pubkey-that-signed; callers
  must cross-check against an external trust source.
- Subscribe to airc-cursor replay over L1-2's AircEventTransport
  for audit-reproducible chain verification.
- TS thin SDK wrapper (parallel to @system/events/shared/EventClass.ts).
  Deferred until a TS consumer materializes — Phase A consumers are
  Rust-side (router daemon, persona admission).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@joelteply joelteply force-pushed the feat/l1-6-contract-event-chain branch from 06957a5 to 25156a5 Compare May 26, 2026 01:25
@joelteply joelteply deleted the branch feat/l1-1-event-class-registry May 26, 2026 01:27
@joelteply joelteply closed this May 26, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant