/** * Test-only fake `Authority` that signs with a fresh ed25519 keypair and * exposes the matching `KeySlotPublic` for verification. Avoids the * full-keychain construction machinery in `@suaveplan/crypto`'s test surface * which would require a deep import on every primitive's tests. * * Only the fields actually touched by `verifyAuthoritySignature` are * populated correctly (`algorithm` + `publicKey`). All other slot fields * carry placeholder values that satisfy the type but are not checked at * runtime by the verify path. */ import { ed25519 } from "@suaveplan/crypto-core/sign"; import type { Authority, DomainTag, KeySlotPublic, SlotId, } from "@suaveplan/types"; /** * Inline copy of `buildSigningInput` from `@suaveplan/crypto/domain-tags`. * Reproduced here to keep this test helper free of any `@suaveplan/crypto` * runtime dep (which would induce a cycle now that `@suaveplan/crypto` * itself depends on this package via `chain-bundle`'s `EnvelopeSchema` * adoption). Byte layout is identical: `tag-bytes ‖ 0x00 ‖ payload`. */ function buildSigningInput(domain: DomainTag, payload: Uint8Array): Uint8Array { const tag = new TextEncoder().encode(domain); const out = new Uint8Array(tag.length + 1 + payload.length); out.set(tag, 0); out[tag.length] = 0; out.set(payload, tag.length + 1); return out; } const ED25519_ALGORITHM_ID = 0; export interface FakeAuthorityHandle { readonly authority: Authority; readonly publicSlot: KeySlotPublic; readonly secretKey: Uint8Array; readonly publicKey: Uint8Array; } function makePlaceholderSlot(publicKey: Uint8Array): KeySlotPublic { return { coordinate: { application: "test" as never, purpose: "sign" as never, layoutId: 0 as never, layoutFields: {} as never, } as never, algorithm: ED25519_ALGORITHM_ID as never, notBefore: 0, notAfter: Number.MAX_SAFE_INTEGER, publicKey, hasPublic: true, }; } /** * Build a fake `Authority` backed by a fresh ed25519 keypair. The returned * `publicSlot` matches the secretKey and is suitable for passing to * `verifyAuthoritySignature` or any consumer of `KeySlotPublic`. */ export function createFakeAuthority(): FakeAuthorityHandle { const keypair = ed25519.generateKeypair(); const secretKey = keypair.secretKey; const publicKey = keypair.publicKey; let disposed = false; const publicSlot = makePlaceholderSlot(publicKey); const authority: Authority = { async sign( domain: DomainTag, _slot: SlotId, payload: Uint8Array, signal?: AbortSignal ): Promise { if (disposed) { throw new Error("authority disposed"); } if (signal?.aborted === true) { throw new Error("aborted"); } const message = buildSigningInput(domain, payload); return Promise.resolve(ed25519.sign(secretKey, message)); }, getPublicSlot(_slot: SlotId): KeySlotPublic | undefined { if (disposed) return undefined; return publicSlot; }, hasSlot(_slot: SlotId): boolean { return !disposed; }, dispose(): void { disposed = true; }, get disposed(): boolean { return disposed; }, }; return { authority, publicSlot, secretKey, publicKey }; }