Files
suaveplan/openspec/archive/2026-04-19-crypto-primitive-replaceability/specs/crypto-utils/spec.md
2026-05-27 23:29:53 +01:00

68 lines
3.5 KiB
Markdown

## ADDED Requirements
### Requirement: Pure-composition utility surface
`@suaveplan/crypto-utils` SHALL expose encoding, byte, constant-time, and test-harness utilities that are safe to author from scratch (no field arithmetic, no secret-data side channels beyond constant-time equality).
#### Scenario: Encoding utilities available
- **WHEN** a consumer imports from `@suaveplan/crypto-utils`
- **THEN** `hex`, `base64`, `base64url`, `base58` encoders/decoders are exported, each with `encode(bytes): string` and `decode(text): Uint8Array`
- **AND** decoders throw a `SuaveplanError` subclass with stable code `CRYPTO.UTILS.INVALID_ENCODING` on malformed input
#### Scenario: Byte utilities available
- **WHEN** a consumer imports from `@suaveplan/crypto-utils`
- **THEN** `concatBytes(...arrays: Uint8Array[]): Uint8Array`, `xor(a: Uint8Array, b: Uint8Array): Uint8Array`, `i2osp(n: bigint, len: number): Uint8Array`, `os2ip(bytes: Uint8Array): bigint` are exported
#### Scenario: Constant-time, random, and zeroize utilities available
- **WHEN** a consumer imports from `@suaveplan/crypto-utils`
- **THEN** `constantTimeEqual(a: Uint8Array, b: Uint8Array): boolean` is exported and implemented without early return
- **AND** `randomBytes(n: number): Uint8Array` is exported, sourcing from `globalThis.crypto.getRandomValues`
- **AND** `zeroize(bytes: Uint8Array): void` is exported
### Requirement: Test-vector and fuzz harness
`@suaveplan/crypto-utils` SHALL expose harness functions that `crypto-hash`, `crypto-curve`, and `crypto-cipher` use to run KATs and differential fuzz against their primitive impls.
#### Scenario: KAT harness
- **WHEN** a primitive test imports `runVectors` from `@suaveplan/crypto-utils/testing`
- **THEN** it can pass a vector list and a set of impls, and receive a per-impl pass/fail/pending report
- **AND** pending impls (throwing `PrimitiveNotImplemented`) are distinguished from failing impls
#### Scenario: Differential fuzz harness
- **WHEN** a primitive test imports `diffFuzz` from `@suaveplan/crypto-utils/testing`
- **THEN** it can pass two impls, an input generator, and an iteration count, and receive a mismatch report
- **AND** any byte-level divergence in outputs is reported with the reproducing input
### Requirement: Primitive id registry
`@suaveplan/crypto-utils` SHALL export the `PrimitiveId` union type enumerating every hash, curve, and AEAD primitive across the crypto family, and a `PRIMITIVE_IDS` const array for runtime iteration.
#### Scenario: Registry available
- **WHEN** a consumer imports `PrimitiveId` and `PRIMITIVE_IDS` from `@suaveplan/crypto-utils/primitive-id`
- **THEN** `PRIMITIVE_IDS` contains every id supported by `crypto-hash`, `crypto-curve`, and `crypto-cipher`
- **AND** `PrimitiveId` narrows to the same union at compile time
### Requirement: No vendored code
`@suaveplan/crypto-utils` SHALL contain only original code authored in this monorepo. No `src/vendored/` directory.
#### Scenario: No vendored directory
- **WHEN** the package tree is inspected
- **THEN** no path matches `packages/universal/crypto-utils/src/vendored/**`
### Requirement: Merkle helpers
`@suaveplan/crypto-utils` SHALL expose Merkle tree construction and inclusion-proof helpers generic over any hash primitive from `@suaveplan/crypto-hash`.
#### Scenario: Merkle helpers available
- **WHEN** a consumer imports `merkleRoot` and `merkleProof` from `@suaveplan/crypto-utils/merkle`
- **THEN** they accept a hash function parameter and a list of leaves, returning a root and an inclusion proof respectively