first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
# `LogChainSigner`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Append-only signed log chain. Each entry carries the SHA-256 hash of the previous entry's bytes plus the current payload, signed under an Ed25519 key. `verify()` walks the chain from suaveplan and raises `CHAIN_TAMPERED` on the first hash mismatch or signature failure — guaranteeing that any tamper to a leaf is detectable as a chain break.
## Features
- suaveplan hash is 32 zero bytes; the signature on the first entry covers the zero hash plus the suaveplan payload.
- `verify()` reports the offending sequence number in `error.context.seq` so consumers locate the corruption without re-walking the chain.
- `chain()` returns a copy of the entry buffer so subscribers cannot mutate the in-memory chain by side-effect.
- Injectable clock for deterministic tests.
## Usage: Basic Example
```ts
import { ed25519 } from "@suaveplan/crypto-curve";
import { LogChainSigner } from "@suaveplan/network-plugin-crypto-messages";
const priv = ed25519.randomPrivateKey();
const pub = ed25519.getPublicKey(priv);
const signer = new LogChainSigner();
signer.append({ event: "join", peer: "alice" }, { publicKey: pub, privateKey: priv });
signer.append({ event: "leave", peer: "bob" }, { publicKey: pub, privateKey: priv });
signer.verify(); // ok
```
## Usage: Advanced Example
```ts
import { LogChainSigner } from "@suaveplan/network-plugin-crypto-messages";
const signer = new LogChainSigner({ clock: () => 1_700_000_000_000 });
for (const event of events) {
signer.append(event, hostKeyPair);
}
const replicated = signer.chain();
// Ship `replicated` to a sibling host; receiver replays via a fresh
// LogChainSigner-equivalent verifier.
signer.verify();
```
## API Reference
- `class LogChainSigner(config?)`
- `append(payload, keyPair): LogChainEntry<TPayload>`.
- `chain(): ReadonlyArray<LogChainEntry>`.
- `verify(): void` — throws `CHAIN_TAMPERED` on first inconsistency.
- `reset(): void` — clears the chain (test helper).
- `interface LogChainEntry<TPayload>` — `{ seq, previousHash, payload, signature, signerPublicKey, recordedAt }`.
## Implementation Notes
- `previousHash` is the SHA-256 of the previous entry's `(previousHash || canonicalSerialise(payload))` bytes — NOT the previous signature. Hashing the bytes covered by the signature is sufficient for tamper-evidence and avoids a circular dependency where the next entry's hash depends on the current entry's signature.
- `signerPublicKey` is recorded per entry so verifiers can roll signing keys mid-chain (multiple hosts contributing to the same chain) without breaking earlier entries.
- The signer never zeroizes or persists `keyPair` — that is the caller's responsibility. Production deployments wire a secure-key manager.
- `entryBytes` returns the canonical bytes for both signing and hash recomputation so signers and verifiers agree.