Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
# `sign`
## Purpose
`COSE_Sign` (RFC 9052 §4.1) — multi-signer COSE message in CBOR tag 98.
Use when a payload needs to be co-signed by multiple parties (e.g. multi-
party attestation, escrowed signing). Each signer carries its own protected
header (typically with its own `alg`) and produces an independent signature
over the canonical `Sig_structure` for context `"Signature"`.
## Features
- `encodeCoseSign` builds the 4-tuple `[bodyProtected, bodyUnprotected,
payload, signatures]` with deterministic encoding and per-signer
`[sigProtected, sigUnprotected, signature]` triples.
- `decodeCoseSign` recovers the typed `CoseSign` view, including
`protectedRaw` byte strings on every level needed to recompute the
five-element `Sig_structure`.
- `verifyCoseSignAny` walks the signers in order against a 1:1 candidate-
key array. Returns the first index whose signature verifies, or `-1` on
no match. Caller decides whether one valid signer is enough or whether all
signers must verify (loop the array).
- Currently dispatches to ES256 + EdDSA via `@suaveplan/crypto-curve`;
unsupported algs return `false` (signer is skipped) rather than throwing
so the helper can scan a heterogeneous array without aborting.
## Usage
```ts
import { encodeCoseSign, decodeCoseSign, verifyCoseSignAny } from "@suaveplan/cbor/cose";
const wire = encodeCoseSign({
payload,
signatures: [
{ protectedHeader: { alg: "ES256" }, signature: sig1 },
{ protectedHeader: { alg: "EdDSA" }, signature: sig2 },
],
});
const msg = decodeCoseSign(wire);
const matchIndex = verifyCoseSignAny(msg, [keyA, keyB]);
```
## API
- `encodeCoseSign(input)` / `decodeCoseSign(bytes)`.
- `verifyCoseSignAny(msg, keys, options?): number` — returns matching index
or `-1`. Length mismatch between `keys` and `msg.signatures` throws
`UNEXPECTED_TYPE`.
- `COSE_SIGN_TAG = 98`.
## Notes
Sig_structure for multi-signer is 5-element:
`[context, body_protected, sign_protected, external_aad, payload]` — the
extra `sign_protected` discriminates the signer's own protected header from
the message-wide one. Both must be the SERIALISED byte strings, not the
inner maps.