Initial Commit

This commit is contained in:
2026-05-27 23:29:53 +01:00
commit fbc70f96e6
10000 changed files with 1102152 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
## ADDED Requirements
### Requirement: Universal AEAD primitive surface
`@suaveplan/crypto-cipher` SHALL expose a stable public API for the AEAD primitives listed below, independent of the underlying implementation source.
#### Scenario: AEAD primitives available
- **WHEN** a consumer imports from `@suaveplan/crypto-cipher`
- **THEN** `aes256gcm`, `chacha20poly1305`, `xchacha20poly1305` are exported
- **AND** each primitive exposes `encrypt(key, nonce, plaintext, aad?)` and `decrypt(key, nonce, ciphertext, aad?)` returning / consuming `Uint8Array`
- **AND** each primitive is also exported from the subpath `@suaveplan/crypto-cipher/<id>` for tree-shaking
### Requirement: Per-primitive replaceability
Every AEAD in `@suaveplan/crypto-cipher` SHALL have both a vendor-forked `noble` implementation and a `native` implementation slot, selected per-primitive at build time via the root `crypto.config.ts`.
#### Scenario: Every AEAD has both impl files
- **WHEN** the package is inspected
- **THEN** every primitive id has both `src/primitives/<id>/impl/<id>.noble.ts` and `src/primitives/<id>/impl/<id>.native.ts`
- **AND** the `native.ts` file is either a working implementation or a stub that throws `PrimitiveNotImplemented('<id>')`
### Requirement: Vendored noble source (Phase 0.5)
From Phase 0.5 onward, the `noble` implementation for every AEAD SHALL come from a vendor-fork of `@noble/ciphers` stored inside this package, not from the `@noble/ciphers` npm package.
#### Scenario: No external runtime dependency on @noble/ciphers (post-0.5)
- **WHEN** `packages/universal/crypto-cipher/package.json` is inspected after Phase 0.5
- **THEN** `@noble/ciphers` does not appear in `dependencies` or `peerDependencies`
- **AND** `src/vendored/` contains the forked source with its original LICENSE preserved
- **AND** `NOBLE_UPSTREAM.md` records the pinned upstream commit SHA and sync date
### Requirement: Dangerous-tier CI gate
Every primitive in this package belongs to the **dangerous tier**. An AEAD's default SHALL NOT be changed from `'noble'` to `'native'` in `crypto.config.ts` unless the flip PR demonstrates all gates required by `crypto-hash`, **plus** a third-party cryptographic audit sign-off covering the specific native implementation being flipped.
#### Scenario: Audit required to flip
- **WHEN** a PR modifies `crypto.config.ts` to change an AEAD entry from `'noble'` to `'native'`
- **THEN** the flip PR template requires an audit report (PDF + auditor signature) attached to the PR
- **AND** the audit report references the exact commit SHA of the native impl being flipped
### Requirement: Constant-time block-cipher and MAC implementation
Native AES implementations SHALL be bitsliced or use hardware intrinsics — table-lookup AES is prohibited. Native Poly1305 and GHASH implementations SHALL NOT contain data-dependent branches.
#### Scenario: Constant-time lint enforces this
- **WHEN** any `impl/*.native.ts` in this package is modified
- **THEN** `scripts/ct-lint.ts` scans for prohibited patterns (secret-indexed array access, data-dependent branches, early returns on tag comparison)
- **AND** any match fails CI with a line-level diagnostic
### Requirement: Nonce handling is the caller's responsibility
Primitives in this package SHALL NOT generate nonces internally. All nonce inputs are supplied by the caller.
#### Scenario: No internal random nonce
- **WHEN** `encrypt(...)` is invoked
- **THEN** no call to a CSPRNG is made inside the primitive
- **AND** the nonce parameter is required and validated for length

View File

@@ -0,0 +1,54 @@
## ADDED Requirements
### Requirement: Universal curve primitive surface
`@suaveplan/crypto-curve` SHALL expose a stable public API for the curves listed below, independent of the underlying implementation source.
#### Scenario: Curves available
- **WHEN** a consumer imports from `@suaveplan/crypto-curve`
- **THEN** `secp256k1`, `ed25519`, `x25519`, `p256` are exported
- **AND** each curve exposes the operations it supports: `getPublicKey`, `sign`, `verify`, `getSharedSecret` (ECDH), `utils.randomPrivateKey`, as appropriate
- **AND** each curve is also exported from the subpath `@suaveplan/crypto-curve/<id>` for tree-shaking
### Requirement: Per-primitive replaceability
Every curve in `@suaveplan/crypto-curve` SHALL have both a vendor-forked `noble` implementation and a `native` implementation slot, selected per-primitive at build time via the root `crypto.config.ts`.
#### Scenario: Every curve has both impl files
- **WHEN** the package is inspected
- **THEN** every curve id has both `src/primitives/<id>/impl/<id>.noble.ts` and `src/primitives/<id>/impl/<id>.native.ts`
- **AND** the `native.ts` file is either a working implementation or a stub that throws `PrimitiveNotImplemented('<id>')`
### Requirement: Vendored noble source (Phase 0.5)
From Phase 0.5 onward, the `noble` implementation for every curve SHALL come from a vendor-fork of `@noble/curves` stored inside this package, not from the `@noble/curves` npm package.
#### Scenario: No external runtime dependency on @noble/curves (post-0.5)
- **WHEN** `packages/universal/crypto-curve/package.json` is inspected after Phase 0.5 completes
- **THEN** `@noble/curves` does not appear in `dependencies` or `peerDependencies`
- **AND** `src/vendored/` contains the forked source with its original LICENSE preserved
- **AND** `NOBLE_UPSTREAM.md` records the pinned upstream commit SHA and sync date
### Requirement: Dangerous-tier CI gate
Every primitive in this package belongs to the **dangerous tier**. A curve's default SHALL NOT be changed from `'noble'` to `'native'` in `crypto.config.ts` unless the flip PR demonstrates all gates required by `crypto-hash`, **plus** a third-party cryptographic audit sign-off covering the specific native implementation being flipped.
#### Scenario: Audit required to flip
- **WHEN** a PR modifies `crypto.config.ts` to change a curve entry from `'noble'` to `'native'`
- **THEN** the flip PR template requires an audit report (PDF + auditor signature) attached to the PR
- **AND** the audit report references the exact commit SHA of the native impl
- **AND** the merge is blocked without a valid audit attachment
### Requirement: Constant-time curve math
Native curve implementations SHALL NOT contain data-dependent branches on private-key material, scalar values, or intermediate field elements derived from secrets. Array indexing on secret values is prohibited.
#### Scenario: Constant-time lint enforces this
- **WHEN** any `impl/*.native.ts` in this package is modified
- **THEN** `scripts/ct-lint.ts` scans for the prohibited patterns
- **AND** any match fails CI with a line-level diagnostic

View File

@@ -0,0 +1,70 @@
## MODIFIED Requirements
### Requirement: Package identity
`@suaveplan/hash` SHALL be renamed to `@suaveplan/crypto-hash` to share the `crypto-*` prefix with the `crypto-curve`, `crypto-cipher`, and `crypto-utils` sibling packages. Every in-tree import of `@suaveplan/hash` SHALL be updated in the same change.
#### Scenario: Package name updated
- **WHEN** `packages/universal/crypto-hash/package.json` is inspected
- **THEN** `name` is `@suaveplan/crypto-hash`
- **AND** no other workspace `package.json` lists `@suaveplan/hash` as a dependency
- **AND** no source file in the repo contains the string `"@suaveplan/hash"` as an import specifier
### Requirement: Per-primitive replaceability layout
Every hash, MAC, and KDF primitive in `@suaveplan/crypto-hash` SHALL live under `src/primitives/<id>/` with both a vendor-forked `noble` implementation and a `native` implementation slot, with the active implementation selected per-primitive at build time via the repo-root `crypto.config.ts`.
#### Scenario: Every primitive has both impl files
- **WHEN** the package is inspected
- **THEN** every primitive id — `sha256`, `sha384`, `sha512`, `hmac`, `hkdf`, `pbkdf2`, `argon2id` — has both `src/primitives/<id>/impl/<id>.noble.ts` and `src/primitives/<id>/impl/<id>.native.ts`
- **AND** the `native.ts` file is either a working implementation or a stub that throws `PrimitiveNotImplemented('<id>')`
#### Scenario: Selection driven by crypto.config.ts
- **WHEN** the root `crypto.config.ts` maps `<id>` to `'noble'` or `'native'`
- **THEN** `src/primitives/<id>/<id>.select.ts` is regenerated to re-export from the chosen impl
- **AND** the build fails if any `*.select.ts` was hand-edited (generated banner check)
### Requirement: Shared test vectors and differential equivalence
Every primitive SHALL have an `<id>.vectors.ts` file containing RFC / NIST / Wycheproof known-answer vectors, executed against every present implementation with cross-impl equivalence asserted.
#### Scenario: KATs pass on every impl
- **WHEN** `bunx turbo test --filter=@suaveplan/crypto-hash` runs
- **THEN** each primitive's vector suite runs against its `noble` and `native` impls
- **AND** native impls that throw `PrimitiveNotImplemented` are reported as `pending`, not failing
#### Scenario: Cross-impl equivalence
- **WHEN** a primitive has both a working `noble` and `native` impl
- **THEN** the test suite executes a differential-equivalence check on the shared vectors
- **AND** any byte-level divergence fails the test
### Requirement: Public API stability
The public API surface of `@suaveplan/crypto-hash` SHALL be identical to the surface that `@suaveplan/hash` exposed at the point of rename. All subpath exports (`./hash`, `./mac`, `./kdf`, `./encoding`, `./errors`) remain available with identical signatures.
#### Scenario: Subpath exports preserved
- **WHEN** a consumer imports from any subpath previously exposed by `@suaveplan/hash`
- **THEN** the exported functions have identical signatures and behaviour as before the rename
## ADDED Requirements
### Requirement: CI gate for flipping default to native
A primitive's default SHALL NOT be changed from `'noble'` to `'native'` in `crypto.config.ts` unless the flip PR demonstrates:
1. Full KAT suite passes on the native impl.
2. Nightly differential fuzz (≥ 1M inputs over 7 days) has zero mismatches.
3. Constant-time lint passes and `dudect` statistical test shows no measurable secret-dependent timing.
4. For `hmac` and any primitive in the **dangerous tier** (defined in `crypto-curve` and `crypto-cipher` specs), a third-party audit sign-off is attached to the PR, referencing the exact commit SHA of the native impl.
#### Scenario: Flip PR blocked without evidence
- **WHEN** a PR modifies `crypto.config.ts` to change a `crypto-hash` entry from `'noble'` to `'native'`
- **THEN** CI requires the flip PR template with links to the KAT run, 7-day fuzz history, timing report, and (for HMAC) audit document
- **AND** the merge is blocked if any evidence link is missing or red

View File

@@ -0,0 +1,67 @@
## 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

View File

@@ -0,0 +1,26 @@
## MODIFIED Requirements
### Requirement: Primitive source
`@suaveplan/crypto` SHALL source every curve and cipher primitive from `@suaveplan/crypto-curve` and `@suaveplan/crypto-cipher` respectively, not from `@noble/*` directly. Every hash primitive is sourced from `@suaveplan/crypto-hash`. Every byte / encoding / random utility is sourced from `@suaveplan/crypto-utils`.
#### Scenario: No @noble/* imports in @suaveplan/crypto source
- **WHEN** `packages/universal/crypto/src/**/*.ts` is grepped
- **THEN** no occurrence of the string `@noble/` remains
#### Scenario: No @noble/* in @suaveplan/crypto direct dependencies
- **WHEN** `packages/universal/crypto/package.json` is inspected
- **THEN** none of `@noble/hashes`, `@noble/curves`, `@noble/ciphers` appear under `dependencies` or `peerDependencies`
- **AND** `@suaveplan/crypto-hash`, `@suaveplan/crypto-curve`, `@suaveplan/crypto-cipher`, `@suaveplan/crypto-utils` appear under `dependencies` with `workspace:^`
### Requirement: Public API surface unchanged
`@suaveplan/crypto` SHALL preserve its existing public API across the primitive-rewiring. All subpath exports declared in `package.json` at the start of this change remain available with identical signatures.
#### Scenario: Subpath exports preserved
- **WHEN** a consumer imports `@suaveplan/crypto/aead`, `@suaveplan/crypto/sign`, `@suaveplan/crypto/agree`, `@suaveplan/crypto/sealed-box`, `@suaveplan/crypto/auth-box`, `@suaveplan/crypto/engines`, `@suaveplan/crypto/primitives/random-bytes`, `@suaveplan/crypto/primitives/constant-time-equal`, `@suaveplan/crypto/primitives/zeroize`, or `@suaveplan/crypto/errors`
- **THEN** the exported functions have identical signatures and behaviour as before this change
- **AND** all existing `@suaveplan/crypto` tests pass unchanged