Files
suaveplan/packages/foundation/bitpacker/bitpacker-crypto/tests/helpers/fake-authority.ts
2026-05-27 23:47:53 +01:00

107 lines
3.5 KiB
TypeScript

/**
* 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<unknown>;
readonly secretKey: Uint8Array;
readonly publicKey: Uint8Array;
}
function makePlaceholderSlot(publicKey: Uint8Array): KeySlotPublic<unknown> {
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<Uint8Array> {
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<unknown> | 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 };
}