@motebit/crypto 0.8.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/signing.d.ts CHANGED
@@ -2,8 +2,9 @@
2
2
  * Protocol signing primitives — Ed25519, encoding, canonical JSON, signed tokens.
3
3
  *
4
4
  * These are the cryptographic building blocks that any protocol participant
5
- * needs to produce valid Motebit artifacts. Moved from BSL @motebit/crypto
6
- * to MIT @motebit/crypto so the protocol's signing format is open.
5
+ * needs to produce valid Motebit artifacts. Moved from BSL @motebit/encryption
6
+ * to the permissive floor in @motebit/crypto (Apache-2.0) so the protocol's
7
+ * signing format is open.
7
8
  *
8
9
  * Zero monorepo dependencies — only @noble/ed25519 for cryptography.
9
10
  */
@@ -20,7 +21,20 @@ export interface SignedTokenPayload {
20
21
  jti: string;
21
22
  /** Audience claim — binds token to a specific endpoint/operation. Prevents cross-endpoint replay. */
22
23
  aud: string;
24
+ /**
25
+ * Cryptosuite identifier. Always `"motebit-jwt-ed25519-v1"` for this
26
+ * token shape today. Present in the signed payload so verifiers
27
+ * dispatch primitive verification through `verifyBySuite` rather
28
+ * than assuming Ed25519. Missing or unknown values are rejected
29
+ * fail-closed — no legacy-no-suite path.
30
+ */
31
+ suite: "motebit-jwt-ed25519-v1";
23
32
  }
33
+ /** The one suite this token shape uses. Exported as a const so the
34
+ * signer emits exactly this value and the verifier checks for exactly
35
+ * this value — no string drift risk.
36
+ */
37
+ export declare const SIGNED_TOKEN_SUITE: "motebit-jwt-ed25519-v1";
24
38
  /**
25
39
  * Deterministic JSON serialization with sorted keys (recursive).
26
40
  * Produces identical output regardless of insertion order.
@@ -53,30 +67,51 @@ export declare function didKeyToPublicKey(did: string): Uint8Array;
53
67
  export declare function publicKeyToDidKey(publicKey: Uint8Array): string;
54
68
  export declare function hexPublicKeyToDidKey(hexPublicKey: string): string;
55
69
  export declare function hash(data: Uint8Array): Promise<string>;
56
- /** SHA-256 returning raw bytes (used by credential signing). */
57
- export declare function sha256(data: Uint8Array): Promise<Uint8Array>;
58
- export declare function generateKeypair(): Promise<KeyPair>;
59
70
  /**
60
- * Sign a message with an Ed25519 private key.
71
+ * Canonical-bytes hash. Convenience wrapper over `canonicalJson` + SHA-256
72
+ * for diagnostic and audit use: lets a producer and a verifier deterministically
73
+ * agree on (or disagree about) the exact bytes a signature was computed over,
74
+ * without re-implementing the canonicalization recipe at the call site.
61
75
  *
62
- * Named `ed25519Sign` to avoid conflict with the artifact-level `verify()`
63
- * function exported from this package. Crypto re-exports as `sign`.
64
- */
65
- export declare function ed25519Sign(message: Uint8Array, privateKey: Uint8Array): Promise<Uint8Array>;
66
- /**
67
- * Verify an Ed25519 signature.
76
+ * Returns the hex SHA-256 of the UTF-8 bytes of `canonicalJson(obj)`. Stable
77
+ * across processes, machines, and Node versions same input ⇒ same output,
78
+ * always. The only requirement on `obj` is that it be a JSON-serializable
79
+ * value (no functions, no symbols, no cycles).
68
80
  *
69
- * Named `ed25519Verify` to avoid conflict with the artifact-level `verify()`
70
- * function exported from this package. Crypto re-exports as `verify`.
81
+ * Primary use case: when a signed-artifact verification fails, both ends of
82
+ * the pipeline can log `canonicalSha256(body)` and the producer can confirm
83
+ * whether the bytes the verifier reproduced match the bytes the producer
84
+ * signed. A hash mismatch localizes the bug to the wire path; a hash match
85
+ * localizes it to the signature primitive (which is far less likely).
71
86
  */
72
- export declare function ed25519Verify(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): Promise<boolean>;
87
+ export declare function canonicalSha256(obj: unknown): Promise<string>;
88
+ /** SHA-256 returning raw bytes (used by credential signing). */
89
+ export declare function sha256(data: Uint8Array): Promise<Uint8Array>;
90
+ export { ed25519Sign, ed25519Verify, generateEd25519Keypair, getPublicKeyBySuite, signBySuite, verifyBySuite, } from "./suite-dispatch.js";
91
+ export declare function generateKeypair(): Promise<KeyPair>;
73
92
  /**
74
93
  * Create a signed token: base64url(payload) + "." + base64url(signature).
75
94
  * Default expiry: 5 minutes from now.
95
+ *
96
+ * The payload includes a fixed `suite` field (`SIGNED_TOKEN_SUITE`) so
97
+ * the verifier can dispatch primitive verification explicitly rather
98
+ * than implicitly assuming Ed25519. Callers MUST supply every other
99
+ * required payload field; this function does not fill defaults for
100
+ * `mid` / `did` / `iat` / `exp` / `jti` / `aud`.
76
101
  */
77
- export declare function createSignedToken(payload: SignedTokenPayload, privateKey: Uint8Array): Promise<string>;
102
+ export declare function createSignedToken(payload: Omit<SignedTokenPayload, "suite">, privateKey: Uint8Array): Promise<string>;
78
103
  /**
79
- * Verify a signed token. Returns the parsed payload if valid and not expired, null otherwise.
104
+ * Verify a signed token. Returns the parsed payload if valid and not
105
+ * expired, null otherwise.
106
+ *
107
+ * Rejects fail-closed on:
108
+ * - malformed token string (no dot separator, invalid base64url),
109
+ * - missing `suite` field,
110
+ * - `suite` value other than `SIGNED_TOKEN_SUITE`,
111
+ * - signature mismatch,
112
+ * - expired token,
113
+ * - missing `jti` (replay defense),
114
+ * - missing `aud` (cross-endpoint replay defense).
80
115
  */
81
116
  export declare function verifySignedToken(token: string, publicKey: Uint8Array): Promise<SignedTokenPayload | null>;
82
117
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAYH,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAC;IACZ,qGAAqG;IACrG,GAAG,EAAE,MAAM,CAAC;CACb;AAID;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAclD;AAID,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAMlD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAMpD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAQrD;AAMD,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAczD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAoBvD;AAID;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAezD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAS/D;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEjE;AAID,wBAAsB,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAM5D;AAED,gEAAgE;AAChE,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAGlE;AAID,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAGxD;AAED;;;;;GAKG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,UAAU,CAAC,CAErB;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,SAAS,EAAE,UAAU,EACrB,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,OAAO,CAAC,CAMlB;AAID;;;GAGG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,kBAAkB,EAC3B,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,CAMjB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAmCpC;AAID;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAQxD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAehF"}
1
+ {"version":3,"file":"signing.d.ts","sourceRoot":"","sources":["../src/signing.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAYH,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,wFAAwF;IACxF,GAAG,EAAE,MAAM,CAAC;IACZ,qGAAqG;IACrG,GAAG,EAAE,MAAM,CAAC;IACZ;;;;;;OAMG;IACH,KAAK,EAAE,wBAAwB,CAAC;CACjC;AAED;;;GAGG;AACH,eAAO,MAAM,kBAAkB,EAAG,wBAAiC,CAAC;AAIpE;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAclD;AAID,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIpD;AAED,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAMlD;AAED,wBAAgB,WAAW,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAMpD;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAQrD;AAMD,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAczD;AAED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAoBvD;AAID;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAezD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,UAAU,GAAG,MAAM,CAS/D;AAED,wBAAgB,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAEjE;AAID,wBAAsB,IAAI,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,MAAM,CAAC,CAM5D;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAEnE;AAED,gEAAgE;AAChE,wBAAsB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAGlE;AAaD,OAAO,EACL,WAAW,EACX,aAAa,EACb,sBAAsB,EACtB,mBAAmB,EACnB,WAAW,EACX,aAAa,GACd,MAAM,qBAAqB,CAAC;AAE7B,wBAAsB,eAAe,IAAI,OAAO,CAAC,OAAO,CAAC,CAExD;AAID;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,IAAI,CAAC,kBAAkB,EAAE,OAAO,CAAC,EAC1C,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,MAAM,CAAC,CAOjB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAoCpC;AAID;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CAQxD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAehF"}
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Cryptosuite dispatch — the single entry point for signature primitive
3
+ * verification in @motebit/crypto.
4
+ *
5
+ * Every `verify*` function that checks a signed motebit artifact MUST
6
+ * route through `verifyBySuite`. Direct calls to `ed.verifyAsync`,
7
+ * `ed.signAsync`, or any other primitive outside this file are a
8
+ * drift-gate violation — see `scripts/check-suite-dispatch.ts`.
9
+ *
10
+ * Rationale: the suite value on a wire artifact names a complete
11
+ * verification recipe (algorithm + canonicalization + encoding). The
12
+ * dispatcher's job is to map `suite` → primitive. Encoding of the
13
+ * signature and public key stays at the artifact layer (every artifact
14
+ * already has its own encoding convention — see `spec/<artifact>-v1.md`
15
+ * `#### Wire format (foundation law)` subsections); the dispatcher
16
+ * receives already-decoded bytes and returns already-produced bytes.
17
+ * This keeps the Ed25519 switch arm honest: it does one thing, and the
18
+ * PQ switch arms that follow in 2026+ will do the same one thing for
19
+ * ML-DSA / SLH-DSA.
20
+ *
21
+ * Fail-closed throughout:
22
+ * - unknown `SuiteId` → `verifyBySuite` returns `false`, `signBySuite` throws.
23
+ * - unsupported algorithm in the switch (PQ placeholder) → throws with
24
+ * a clear message so the call site doesn't silently succeed.
25
+ * - primitive-level exception → `verifyBySuite` returns `false`.
26
+ *
27
+ * No legacy-no-suite path. A caller that reaches this function without
28
+ * a valid `SuiteId` has already lost; the function enforces that
29
+ * contract at the boundary.
30
+ */
31
+ import type { SuiteId } from "@motebit/protocol";
32
+ /**
33
+ * Verify an already-decoded signature over `canonicalBytes` using the
34
+ * primitive named by `suite`. The caller is responsible for:
35
+ * 1. canonicalization (the bytes are already the signing input per
36
+ * the suite's canonicalization rule);
37
+ * 2. signature and public-key decoding (hex → Uint8Array, base64url
38
+ * → Uint8Array, multibase → Uint8Array per the suite's
39
+ * `signatureEncoding` / `publicKeyEncoding`).
40
+ *
41
+ * Returns `false` on unknown or unsupported suite, on primitive-level
42
+ * exception, and on signature mismatch. Never throws in the Ed25519
43
+ * path. Throws only on PQ suites (placeholder until implementation
44
+ * lands), because a misconfigured dispatcher there would silently
45
+ * pass every verification.
46
+ */
47
+ export declare function verifyBySuite(suite: SuiteId, canonicalBytes: Uint8Array, signatureBytes: Uint8Array, publicKeyBytes: Uint8Array): Promise<boolean>;
48
+ /**
49
+ * Produce a signature over `canonicalBytes` using the primitive named
50
+ * by `suite`. Mirrors `verifyBySuite`: caller provides already-
51
+ * canonicalized bytes; caller encodes the returned `Uint8Array` per
52
+ * the suite's `signatureEncoding` at the artifact boundary.
53
+ *
54
+ * Throws on unknown or unsupported suite (fail-closed). Signers that
55
+ * catch and swallow this exception would ship unsigned artifacts,
56
+ * which is a worse failure mode than a loud throw.
57
+ */
58
+ export declare function signBySuite(suite: SuiteId, canonicalBytes: Uint8Array, privateKeyBytes: Uint8Array): Promise<Uint8Array>;
59
+ /**
60
+ * Lowest-level Ed25519 primitives. These are the functions callers
61
+ * should use when they genuinely need the primitive — for example,
62
+ * generating a keypair at identity bootstrap, or computing a
63
+ * succession-chain signature where the caller has already dispatched
64
+ * by suite. Exported from this file so the drift gate's scan rule is
65
+ * simple: "`ed.*` lives only in `suite-dispatch.ts`."
66
+ */
67
+ export declare function ed25519Sign(message: Uint8Array, privateKey: Uint8Array): Promise<Uint8Array>;
68
+ export declare function ed25519Verify(signature: Uint8Array, message: Uint8Array, publicKey: Uint8Array): Promise<boolean>;
69
+ export declare function generateEd25519Keypair(): Promise<{
70
+ publicKey: Uint8Array;
71
+ privateKey: Uint8Array;
72
+ }>;
73
+ /**
74
+ * Derive the matching public key from a private key, dispatched by suite.
75
+ *
76
+ * For Ed25519 suites this is deterministic seed expansion (hash the seed,
77
+ * derive the curve point). Callers that have a private key in hand and
78
+ * need the public key — sovereign delegation paths, identity bootstrap
79
+ * after a seed import, recovery flows — go through here so the noble
80
+ * call doesn't escape the dispatcher.
81
+ *
82
+ * Throws on unknown or unsupported suite (fail-closed). PQ arms will
83
+ * land alongside their `verifyBySuite` / `signBySuite` counterparts.
84
+ */
85
+ export declare function getPublicKeyBySuite(privateKey: Uint8Array, suite: SuiteId): Promise<Uint8Array>;
86
+ /**
87
+ * Verify a P-256 ECDSA-SHA256 signature.
88
+ *
89
+ * - `publicKeyCompressedHex` — P-256 public key in compressed-point
90
+ * hex encoding (33 bytes, `02`/`03` prefix). Uncompressed keys
91
+ * (65 bytes, `04` prefix) also accepted — noble handles both.
92
+ * - `messageBytes` — the bytes that were signed. noble internally
93
+ * SHA-256 hashes before verification, so callers pass the
94
+ * un-pre-hashed payload.
95
+ * - `signatureDerBytes` — DER-encoded ECDSA signature as emitted by
96
+ * Apple SE / Security.framework.
97
+ *
98
+ * Returns `false` on any failure (bad key, bad DER, bad signature,
99
+ * mismatch). Never throws — matches the `verifyBySuite` contract so
100
+ * callers don't need a try/catch.
101
+ */
102
+ export declare function verifyP256EcdsaSha256(publicKeyCompressedHex: string, messageBytes: Uint8Array, signatureDerBytes: Uint8Array): boolean;
103
+ //# sourceMappingURL=suite-dispatch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suite-dispatch.d.ts","sourceRoot":"","sources":["../src/suite-dispatch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAkBH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AASjD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,aAAa,CACjC,KAAK,EAAE,OAAO,EACd,cAAc,EAAE,UAAU,EAC1B,cAAc,EAAE,UAAU,EAC1B,cAAc,EAAE,UAAU,GACzB,OAAO,CAAC,OAAO,CAAC,CAgBlB;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,KAAK,EAAE,OAAO,EACd,cAAc,EAAE,UAAU,EAC1B,eAAe,EAAE,UAAU,GAC1B,OAAO,CAAC,UAAU,CAAC,CASrB;AAED;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,UAAU,EACnB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,UAAU,CAAC,CAErB;AAED,wBAAsB,aAAa,CACjC,SAAS,EAAE,UAAU,EACrB,OAAO,EAAE,UAAU,EACnB,SAAS,EAAE,UAAU,GACpB,OAAO,CAAC,OAAO,CAAC,CAMlB;AAED,wBAAsB,sBAAsB,IAAI,OAAO,CAAC;IACtD,SAAS,EAAE,UAAU,CAAC;IACtB,UAAU,EAAE,UAAU,CAAC;CACxB,CAAC,CAGD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,mBAAmB,CACvC,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,OAAO,GACb,OAAO,CAAC,UAAU,CAAC,CASrB;AAeD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,qBAAqB,CACnC,sBAAsB,EAAE,MAAM,EAC9B,YAAY,EAAE,UAAU,EACxB,iBAAiB,EAAE,UAAU,GAC5B,OAAO,CAQT"}