@real-life/trust-protocol 0.3.2 → 0.5.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/CHANGELOG.md +97 -0
- package/README.md +209 -78
- package/dist/ack.d.ts +84 -0
- package/dist/ack.d.ts.map +1 -0
- package/dist/ack.js +114 -0
- package/dist/ack.js.map +1 -0
- package/dist/adapters/vti-mediator.d.ts +169 -0
- package/dist/adapters/vti-mediator.d.ts.map +1 -0
- package/dist/adapters/vti-mediator.js +659 -0
- package/dist/adapters/vti-mediator.js.map +1 -0
- package/dist/anchor.d.ts +226 -0
- package/dist/anchor.d.ts.map +1 -0
- package/dist/anchor.js +347 -0
- package/dist/anchor.js.map +1 -0
- package/dist/{holder.d.ts → carrier-holder.d.ts} +1 -1
- package/dist/carrier-holder.d.ts.map +1 -0
- package/dist/{holder.js → carrier-holder.js} +5 -4
- package/dist/carrier-holder.js.map +1 -0
- package/dist/carrier-identity.js +4 -4
- package/dist/carrier-identity.js.map +1 -1
- package/dist/carrier.d.ts.map +1 -1
- package/dist/carrier.js +4 -3
- package/dist/carrier.js.map +1 -1
- package/dist/ceremony.d.ts +3 -2
- package/dist/ceremony.d.ts.map +1 -1
- package/dist/ceremony.js +16 -26
- package/dist/ceremony.js.map +1 -1
- package/dist/codec.d.ts +54 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/codec.js +494 -0
- package/dist/codec.js.map +1 -0
- package/dist/continuity.d.ts +67 -0
- package/dist/continuity.d.ts.map +1 -0
- package/dist/continuity.js +110 -0
- package/dist/continuity.js.map +1 -0
- package/dist/core.d.ts +4 -0
- package/dist/core.d.ts.map +1 -1
- package/dist/core.js.map +1 -1
- package/dist/crypto.d.ts +23 -7
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +54 -20
- package/dist/crypto.js.map +1 -1
- package/dist/delivery.d.ts +31 -3
- package/dist/delivery.d.ts.map +1 -1
- package/dist/delivery.js +75 -28
- package/dist/delivery.js.map +1 -1
- package/dist/encounter/ceremony.d.ts +37 -0
- package/dist/encounter/ceremony.d.ts.map +1 -0
- package/dist/encounter/ceremony.js +662 -0
- package/dist/encounter/ceremony.js.map +1 -0
- package/dist/encounter.d.ts +91 -1
- package/dist/encounter.d.ts.map +1 -1
- package/dist/encounter.js +191 -12
- package/dist/encounter.js.map +1 -1
- package/dist/engine.d.ts +303 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +1509 -0
- package/dist/engine.js.map +1 -0
- package/dist/entropy.d.ts +28 -0
- package/dist/entropy.d.ts.map +1 -0
- package/dist/entropy.js +96 -0
- package/dist/entropy.js.map +1 -0
- package/dist/events.d.ts +198 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +2 -0
- package/dist/events.js.map +1 -0
- package/dist/fixtures.d.ts +30 -0
- package/dist/fixtures.d.ts.map +1 -0
- package/dist/fixtures.js +155 -0
- package/dist/fixtures.js.map +1 -0
- package/dist/forge.d.ts +47 -0
- package/dist/forge.d.ts.map +1 -0
- package/dist/forge.js +20 -0
- package/dist/forge.js.map +1 -0
- package/dist/group-star.d.ts +251 -0
- package/dist/group-star.d.ts.map +1 -0
- package/dist/group-star.js +348 -0
- package/dist/group-star.js.map +1 -0
- package/dist/holder-api.d.ts +165 -0
- package/dist/holder-api.d.ts.map +1 -0
- package/dist/holder-api.js +142 -0
- package/dist/holder-api.js.map +1 -0
- package/dist/holder-state-v1.d.ts +801 -0
- package/dist/holder-state-v1.d.ts.map +1 -0
- package/dist/holder-state-v1.js +2 -0
- package/dist/holder-state-v1.js.map +1 -0
- package/dist/holder-state-v2.d.ts +858 -0
- package/dist/holder-state-v2.d.ts.map +1 -0
- package/dist/holder-state-v2.js +2 -0
- package/dist/holder-state-v2.js.map +1 -0
- package/dist/identity-state.d.ts +43 -0
- package/dist/identity-state.d.ts.map +1 -0
- package/dist/identity-state.js +345 -0
- package/dist/identity-state.js.map +1 -0
- package/dist/identity.d.ts +24 -2
- package/dist/identity.d.ts.map +1 -1
- package/dist/identity.js +70 -11
- package/dist/identity.js.map +1 -1
- package/dist/index.d.ts +27 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +81 -29
- package/dist/index.js.map +1 -1
- package/dist/internal.d.ts +37 -0
- package/dist/internal.d.ts.map +1 -0
- package/dist/internal.js +22 -0
- package/dist/internal.js.map +1 -0
- package/dist/introduction/holder.d.ts +18 -0
- package/dist/introduction/holder.d.ts.map +1 -0
- package/dist/introduction/holder.js +764 -0
- package/dist/introduction/holder.js.map +1 -0
- package/dist/introduction.d.ts +101 -0
- package/dist/introduction.d.ts.map +1 -0
- package/dist/introduction.js +132 -0
- package/dist/introduction.js.map +1 -0
- package/dist/invariants.d.ts +43 -0
- package/dist/invariants.d.ts.map +1 -0
- package/dist/invariants.js +953 -0
- package/dist/invariants.js.map +1 -0
- package/dist/keys-seed.d.ts +7 -0
- package/dist/keys-seed.d.ts.map +1 -0
- package/dist/keys-seed.js +133 -0
- package/dist/keys-seed.js.map +1 -0
- package/dist/log-memory.d.ts +12 -0
- package/dist/log-memory.d.ts.map +1 -0
- package/dist/log-memory.js +101 -0
- package/dist/log-memory.js.map +1 -0
- package/dist/membership/holder.d.ts +33 -0
- package/dist/membership/holder.d.ts.map +1 -0
- package/dist/membership/holder.js +929 -0
- package/dist/membership/holder.js.map +1 -0
- package/dist/membership.d.ts +123 -0
- package/dist/membership.d.ts.map +1 -0
- package/dist/membership.js +180 -0
- package/dist/membership.js.map +1 -0
- package/dist/message/holder.d.ts +49 -0
- package/dist/message/holder.d.ts.map +1 -0
- package/dist/message/holder.js +290 -0
- package/dist/message/holder.js.map +1 -0
- package/dist/message.d.ts +43 -0
- package/dist/message.d.ts.map +1 -0
- package/dist/message.js +51 -0
- package/dist/message.js.map +1 -0
- package/dist/ports.d.ts +237 -0
- package/dist/ports.d.ts.map +1 -0
- package/dist/ports.js +2 -0
- package/dist/ports.js.map +1 -0
- package/dist/profile.d.ts +56 -0
- package/dist/profile.d.ts.map +1 -0
- package/dist/profile.js +193 -0
- package/dist/profile.js.map +1 -0
- package/dist/prompts.d.ts +14 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +69 -0
- package/dist/prompts.js.map +1 -0
- package/dist/receive.d.ts +134 -0
- package/dist/receive.d.ts.map +1 -0
- package/dist/receive.js +317 -0
- package/dist/receive.js.map +1 -0
- package/dist/results.d.ts +173 -0
- package/dist/results.d.ts.map +1 -0
- package/dist/results.js +21 -0
- package/dist/results.js.map +1 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +45 -38
- package/dist/schemas.js.map +1 -1
- package/dist/sha256.d.ts +3 -0
- package/dist/sha256.d.ts.map +1 -0
- package/dist/sha256.js +69 -0
- package/dist/sha256.js.map +1 -0
- package/dist/star.d.ts +31 -0
- package/dist/star.d.ts.map +1 -0
- package/dist/star.js +56 -0
- package/dist/star.js.map +1 -0
- package/dist/state-builder.d.ts +42 -0
- package/dist/state-builder.d.ts.map +1 -0
- package/dist/state-builder.js +100 -0
- package/dist/state-builder.js.map +1 -0
- package/dist/state.d.ts +914 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +37 -0
- package/dist/state.js.map +1 -0
- package/dist/store-contract.d.ts +11 -0
- package/dist/store-contract.d.ts.map +1 -0
- package/dist/store-contract.js +189 -0
- package/dist/store-contract.js.map +1 -0
- package/dist/store-memory.d.ts +8 -0
- package/dist/store-memory.d.ts.map +1 -0
- package/dist/store-memory.js +17 -0
- package/dist/store-memory.js.map +1 -0
- package/dist/testing.d.ts +22 -0
- package/dist/testing.d.ts.map +1 -0
- package/dist/testing.js +21 -0
- package/dist/testing.js.map +1 -0
- package/dist/trust/continuity.d.ts +71 -0
- package/dist/trust/continuity.d.ts.map +1 -0
- package/dist/trust/continuity.js +1222 -0
- package/dist/trust/continuity.js.map +1 -0
- package/dist/trust/duties.d.ts +67 -0
- package/dist/trust/duties.d.ts.map +1 -0
- package/dist/trust/duties.js +179 -0
- package/dist/trust/duties.js.map +1 -0
- package/dist/trust/entries.d.ts +139 -0
- package/dist/trust/entries.d.ts.map +1 -0
- package/dist/trust/entries.js +795 -0
- package/dist/trust/entries.js.map +1 -0
- package/dist/trust/group-star.d.ts +43 -0
- package/dist/trust/group-star.d.ts.map +1 -0
- package/dist/trust/group-star.js +188 -0
- package/dist/trust/group-star.js.map +1 -0
- package/dist/trust/mapping.d.ts +56 -0
- package/dist/trust/mapping.d.ts.map +1 -0
- package/dist/trust/mapping.js +584 -0
- package/dist/trust/mapping.js.map +1 -0
- package/dist/trust/profile.d.ts +25 -0
- package/dist/trust/profile.d.ts.map +1 -0
- package/dist/trust/profile.js +249 -0
- package/dist/trust/profile.js.map +1 -0
- package/dist/trust/star.d.ts +208 -0
- package/dist/trust/star.d.ts.map +1 -0
- package/dist/trust/star.js +588 -0
- package/dist/trust/star.js.map +1 -0
- package/dist/trust/state.d.ts +83 -0
- package/dist/trust/state.d.ts.map +1 -0
- package/dist/trust/state.js +154 -0
- package/dist/trust/state.js.map +1 -0
- package/dist/util-freeze.d.ts +3 -0
- package/dist/util-freeze.d.ts.map +1 -0
- package/dist/util-freeze.js +11 -0
- package/dist/util-freeze.js.map +1 -0
- package/dist/views.d.ts +179 -0
- package/dist/views.d.ts.map +1 -0
- package/dist/views.js +286 -0
- package/dist/views.js.map +1 -0
- package/dist/visibility.d.ts +5 -5
- package/dist/visibility.d.ts.map +1 -1
- package/dist/visibility.js +22 -28
- package/dist/visibility.js.map +1 -1
- package/dist/wire.d.ts +218 -83
- package/dist/wire.d.ts.map +1 -1
- package/dist/wire.js.map +1 -1
- package/package.json +60 -10
- package/schemas/holder-state-v1.schema.json +3880 -0
- package/schemas/holder-state-v2.schema.json +4123 -0
- package/dist/holder.d.ts.map +0 -1
- package/dist/holder.js.map +0 -1
- package/dist/probe/acks.d.ts +0 -27
- package/dist/probe/acks.d.ts.map +0 -1
- package/dist/probe/acks.js +0 -152
- package/dist/probe/acks.js.map +0 -1
- package/dist/probe/continuity.d.ts +0 -20
- package/dist/probe/continuity.d.ts.map +0 -1
- package/dist/probe/continuity.js +0 -805
- package/dist/probe/continuity.js.map +0 -1
- package/dist/probe/deps.d.ts +0 -61
- package/dist/probe/deps.d.ts.map +0 -1
- package/dist/probe/deps.js +0 -54
- package/dist/probe/deps.js.map +0 -1
- package/dist/probe/encounter.d.ts +0 -26
- package/dist/probe/encounter.d.ts.map +0 -1
- package/dist/probe/encounter.js +0 -938
- package/dist/probe/encounter.js.map +0 -1
- package/dist/probe/introduce.d.ts +0 -62
- package/dist/probe/introduce.d.ts.map +0 -1
- package/dist/probe/introduce.js +0 -306
- package/dist/probe/introduce.js.map +0 -1
- package/dist/probe/membership.d.ts +0 -96
- package/dist/probe/membership.d.ts.map +0 -1
- package/dist/probe/membership.js +0 -467
- package/dist/probe/membership.js.map +0 -1
- package/dist/probe/trust.d.ts +0 -156
- package/dist/probe/trust.d.ts.map +0 -1
- package/dist/probe/trust.js +0 -1233
- package/dist/probe/trust.js.map +0 -1
- package/dist/probe.d.ts +0 -7
- package/dist/probe.d.ts.map +0 -1
- package/dist/probe.js +0 -42
- package/dist/probe.js.map +0 -1
package/dist/crypto.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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","sourcesContent":["// crypto — the primitives, and nothing above them.\n//\n// Byte helpers, hashes, HKDF, key pairs (Ed25519 signing, X25519\n// agreement), the did:key / multikey renderings, ECDH — plus the\n// eddsa-jcs-2022 Data Integrity proof, which every layer signs with.\n//\n// This module answers \"how\", never \"what\": what a proof MEANS is decided\n// by the layer that issues it. Runs on globalThis.crypto.subtle in\n// browsers, Node >= 20, Deno and Bun alike.\n//\n// Determinism: every construction takes its entropy from the CALLER\n// (nonces, ephemeral seeds). Random helpers exist, but nothing here\n// calls them implicitly — that is what makes the whole stack replayable\n// and vector-testable.\nimport { jcs, base58, fromBase58, b64uOf, fromB64u, calOK } from './core.js'\nexport { b64uOf, fromB64u, base58, fromBase58 }\n\nconst te = new TextEncoder()\nconst S = globalThis.crypto.subtle\n\n// ── bytes ───────────────────────────────────────────────────────────────\nexport const cat = (...bs: Uint8Array[]): Uint8Array => {\n const o = new Uint8Array(bs.reduce((n, b) => n + b.length, 0))\n let i = 0; for (const b of bs) { o.set(b, i); i += b.length }\n return o\n}\nexport const rand = (n: number): Uint8Array => globalThis.crypto.getRandomValues(new Uint8Array(n))\n\n// ── hashes, KDF, digests ────────────────────────────────────────────────\nexport const sha = async (bytes: Uint8Array): Promise<Uint8Array> => new Uint8Array(await S.digest('SHA-256', bytes))\nexport const hkdf = async (ikm: Uint8Array, info: string, len = 32): Promise<Uint8Array> => {\n const k = await S.importKey('raw', ikm, 'HKDF', false, ['deriveBits'])\n return new Uint8Array(await S.deriveBits({ name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(0), info: te.encode(info) }, k, len * 8))\n}\n// multibase multihash (u, sha2-256) over raw BYTES — pair labels digest the nonce bytes\nexport const digestBytes = async (bytes: Uint8Array): Promise<string> => 'u' + b64uOf(cat(Uint8Array.from([0x12, 0x20]), await sha(bytes)))\n// …and over the JCS of a document — the document digest of the stack\nexport const digestDoc = async (obj: unknown): Promise<string> => digestBytes(te.encode(jcs(obj)))\n\n// ── keys (Ed25519 signing, X25519 agreement; did:key / multikey) ────────\nconst ED_PKCS8 = Uint8Array.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20])\nconst X_PKCS8 = Uint8Array.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20])\nconst jwkX = async (priv: CryptoKey): Promise<Uint8Array> => fromB64u((await S.exportKey('jwk', priv)).x!)\n/** A key pair as this library carries it: the private CryptoKey plus the raw public bytes. */\nexport interface KeyPair { priv: CryptoKey, pubRaw: Uint8Array }\n\nexport async function edFromSeed (seed: Uint8Array): Promise<KeyPair> {\n const priv = await S.importKey('pkcs8', cat(ED_PKCS8, seed), { name: 'Ed25519' }, true, ['sign'])\n return { priv, pubRaw: await jwkX(priv) }\n}\nexport async function xFromSeed (seed: Uint8Array): Promise<KeyPair> {\n const priv = await S.importKey('pkcs8', cat(X_PKCS8, seed), { name: 'X25519' }, true, ['deriveBits'])\n return { priv, pubRaw: await jwkX(priv) }\n}\nexport const anchorOfEd = (pubRaw: Uint8Array): string => 'did:key:z' + base58(cat(Uint8Array.from([0xed, 0x01]), pubRaw))\nexport const mkOfX = (pubRaw: Uint8Array): string => 'z' + base58(cat(Uint8Array.from([0xec, 0x01]), pubRaw))\nexport const edRawOfAnchor = (did: unknown): Uint8Array | null => {\n if (typeof did !== 'string' || !did.startsWith('did:key:z')) return null\n const b = fromBase58(did.slice('did:key:z'.length))\n return (b && b.length === 34 && b[0] === 0xed && b[1] === 0x01) ? b.subarray(2) : null\n}\nexport const xRawOfMk = (mk: unknown): Uint8Array | null => {\n if (typeof mk !== 'string' || mk[0] !== 'z') return null\n const b = fromBase58(mk.slice(1))\n return (b && b.length === 34 && b[0] === 0xec && b[1] === 0x01) ? b.subarray(2) : null\n}\nexport const ecdh = async (xPriv: CryptoKey, theirPubRaw: Uint8Array): Promise<Uint8Array> => {\n const pub = await S.importKey('raw', theirPubRaw, { name: 'X25519' }, false, [])\n return new Uint8Array(await S.deriveBits({ name: 'X25519', public: pub }, xPriv, 256))\n}\n\n// ── eddsa-jcs-2022 Data Integrity (W3C-true; Encounter §2.3) ──────────\n// hashData = SHA256(JCS(proofConfig incl. @context where the document has\n// one)) || SHA256(JCS(document without proof)); Ed25519 over hashData;\n// proofValue = z-base58btc of the exactly-64-byte signature.\n/** What a signer must offer: its anchor and its Ed25519 key. A full identity Context satisfies this. */\nexport interface Signer { anchor: string, ed: { priv: CryptoKey } }\n\nexport async function diSign<T extends Record<string, any>> (ctx: Signer, doc: T, created: string): Promise<T & { proof: Record<string, any> }> {\n const cfg: Record<string, any> = { type: 'DataIntegrityProof', cryptosuite: 'eddsa-jcs-2022', created, verificationMethod: ctx.anchor + '#' + ctx.anchor.slice(8), proofPurpose: 'assertionMethod' }\n if ('@context' in doc) cfg['@context'] = doc['@context']\n const hashData = cat(await sha(te.encode(jcs(cfg))), await sha(te.encode(jcs(doc))))\n const sig = new Uint8Array(await S.sign({ name: 'Ed25519' }, ctx.ed.priv, hashData))\n return { ...doc, proof: { ...cfg, proofValue: 'z' + base58(sig) } }\n}\nexport async function diVerify (doc: any, expectedAnchor?: string): Promise<boolean> {\n const { proof, ...rest } = doc ?? {}\n if (typeof proof?.proofValue !== 'string' || typeof proof?.verificationMethod !== 'string') return false\n // M-3 (review 1): this predicate verifies THE RLTP proof, not any\n // signature that happens to be valid under the key — a config with a\n // foreign type, suite, purpose or timestamp form is false here, whether\n // or not a schema runs first.\n if (proof.type !== 'DataIntegrityProof' || proof.cryptosuite !== 'eddsa-jcs-2022') return false\n if (proof.proofPurpose !== 'assertionMethod') return false\n if (typeof proof.created !== 'string' || !calOK(proof.created)) return false\n const vmDid = proof.verificationMethod.split('#')[0] as string\n if (proof.verificationMethod !== vmDid + '#' + vmDid.slice(8)) return false\n if (expectedAnchor && vmDid !== expectedAnchor) return false\n if ('@context' in rest && jcs(proof['@context'] ?? null) !== jcs(rest['@context'])) return false\n const raw = edRawOfAnchor(vmDid)\n if (!raw) return false\n const zsig = proof.proofValue\n if (typeof zsig !== 'string' || zsig[0] !== 'z') return false\n const sig = fromBase58(zsig.slice(1))\n // exactly 64 bytes, canonical base58btc — no left-pad repair (Encounter 2.3)\n if (!sig || sig.length !== 64 || 'z' + base58(sig) !== zsig) return false\n const { proofValue, ...cfg } = proof\n const hashData = cat(await sha(te.encode(jcs(cfg))), await sha(te.encode(jcs(rest))))\n const pub = await S.importKey('raw', raw, { name: 'Ed25519' }, false, ['verify'])\n return S.verify({ name: 'Ed25519' }, pub, sig, hashData)\n}\n\n"]}
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"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","sourcesContent":["// crypto — the primitives, and nothing above them.\n//\n// Byte helpers, hashes, HKDF, key pairs (Ed25519 signing, X25519\n// agreement), the did:key / multikey renderings, ECDH — plus the\n// eddsa-jcs-2022 Data Integrity proof, which every layer signs with.\n//\n// This module answers \"how\", never \"what\": what a proof MEANS is decided\n// by the layer that issues it. Runs on globalThis.crypto.subtle in\n// browsers, Node >= 20, Deno and Bun alike.\n//\n// Every primitive below runs on the platform's SubtleCrypto unless the\n// caller hands its own (the holder passes the handle it resolved at\n// construction, note §3 Crypto).\n//\n// Determinism: every construction takes its entropy from the CALLER\n// (nonces, ephemeral seeds). Random helpers exist, but nothing here\n// calls them implicitly — that is what makes the whole stack replayable\n// and vector-testable.\nimport { jcs, base58, fromBase58, b64uOf, fromB64u, calOK } from './core.js'\nimport { CryptoUnavailableError } from './results.js'\nexport { b64uOf, fromB64u, base58, fromBase58 }\n\nconst te = new TextEncoder()\n/** The platform's SubtleCrypto, read at call time — never at import, so\n * the library loads in a runtime without WebCrypto and fails only where\n * it is used (note §3 Crypto). */\nexport const platformSubtle = (): SubtleCrypto => {\n const s = globalThis.crypto?.subtle\n if (!s) throw new CryptoUnavailableError(['subtle'])\n return s\n}\nconst S = platformSubtle\n\n// ── bytes ───────────────────────────────────────────────────────────────\nexport const cat = (...bs: Uint8Array[]): Uint8Array => {\n const o = new Uint8Array(bs.reduce((n, b) => n + b.length, 0))\n let i = 0; for (const b of bs) { o.set(b, i); i += b.length }\n return o\n}\nexport const rand = (n: number): Uint8Array => globalThis.crypto.getRandomValues(new Uint8Array(n))\n\n// ── hashes, KDF, digests ────────────────────────────────────────────────\nexport const sha = async (bytes: Uint8Array, subtle: SubtleCrypto = S()): Promise<Uint8Array> => new Uint8Array(await subtle.digest('SHA-256', bytes))\nexport const hkdf = async (ikm: Uint8Array, info: string, len = 32, subtle: SubtleCrypto = S()): Promise<Uint8Array> => {\n const k = await subtle.importKey('raw', ikm, 'HKDF', false, ['deriveBits'])\n return new Uint8Array(await subtle.deriveBits({ name: 'HKDF', hash: 'SHA-256', salt: new Uint8Array(0), info: te.encode(info) }, k, len * 8))\n}\n// multibase multihash (u, sha2-256) over raw BYTES — pair labels digest the nonce bytes\nexport const digestBytes = async (bytes: Uint8Array, subtle?: SubtleCrypto): Promise<string> => 'u' + b64uOf(cat(Uint8Array.from([0x12, 0x20]), await sha(bytes, subtle)))\n// …and over the JCS of a document — the document digest of the stack\nexport const digestDoc = async (obj: unknown, subtle?: SubtleCrypto): Promise<string> => digestBytes(te.encode(jcs(obj)), subtle)\n\n// ── keys (Ed25519 signing, X25519 agreement; did:key / multikey) ────────\nconst ED_PKCS8 = Uint8Array.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04, 0x20])\nconst X_PKCS8 = Uint8Array.from([0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x6e, 0x04, 0x22, 0x04, 0x20])\nconst jwkX = async (priv: CryptoKey, subtle: SubtleCrypto = S()): Promise<Uint8Array> => fromB64u((await subtle.exportKey('jwk', priv)).x!)\n/** A key pair as this library carries it: the private CryptoKey plus the raw public bytes. */\nexport interface KeyPair { priv: CryptoKey, pubRaw: Uint8Array }\n\nexport async function edFromSeed (seed: Uint8Array): Promise<KeyPair> {\n const priv = await S().importKey('pkcs8', cat(ED_PKCS8, seed), { name: 'Ed25519' }, true, ['sign'])\n return { priv, pubRaw: await jwkX(priv) }\n}\nexport async function xFromSeed (seed: Uint8Array, subtle: SubtleCrypto = S()): Promise<KeyPair> {\n const priv = await subtle.importKey('pkcs8', cat(X_PKCS8, seed), { name: 'X25519' }, true, ['deriveBits'])\n return { priv, pubRaw: await jwkX(priv, subtle) }\n}\nexport const anchorOfEd = (pubRaw: Uint8Array): string => 'did:key:z' + base58(cat(Uint8Array.from([0xed, 0x01]), pubRaw))\nexport const mkOfX = (pubRaw: Uint8Array): string => 'z' + base58(cat(Uint8Array.from([0xec, 0x01]), pubRaw))\nexport const edRawOfAnchor = (did: unknown): Uint8Array | null => {\n if (typeof did !== 'string' || !did.startsWith('did:key:z')) return null\n const b = fromBase58(did.slice('did:key:z'.length))\n return (b && b.length === 34 && b[0] === 0xed && b[1] === 0x01) ? b.subarray(2) : null\n}\nexport const xRawOfMk = (mk: unknown): Uint8Array | null => {\n if (typeof mk !== 'string' || mk[0] !== 'z') return null\n const b = fromBase58(mk.slice(1))\n return (b && b.length === 34 && b[0] === 0xec && b[1] === 0x01) ? b.subarray(2) : null\n}\nexport const ecdh = async (xPriv: CryptoKey, theirPubRaw: Uint8Array, subtle: SubtleCrypto = S()): Promise<Uint8Array> => {\n const pub = await subtle.importKey('raw', theirPubRaw, { name: 'X25519' }, false, [])\n return new Uint8Array(await subtle.deriveBits({ name: 'X25519', public: pub }, xPriv, 256))\n}\n\n// ── eddsa-jcs-2022 Data Integrity (W3C-true; Encounter §2.3) ──────────\n// hashData = SHA256(JCS(proofConfig incl. @context where the document has\n// one)) || SHA256(JCS(document without proof)); Ed25519 over hashData;\n// proofValue = z-base58btc of the exactly-64-byte signature.\n/** What a signer must offer: its anchor and its Ed25519 key. A full identity Context satisfies this. */\nexport interface Signer { anchor: string, ed: { priv: CryptoKey } }\n\nexport async function diSign<T extends Record<string, any>> (ctx: Signer, doc: T, created: string): Promise<T & { proof: Record<string, any> }> {\n const cfg: Record<string, any> = { type: 'DataIntegrityProof', cryptosuite: 'eddsa-jcs-2022', created, verificationMethod: ctx.anchor + '#' + ctx.anchor.slice(8), proofPurpose: 'assertionMethod' }\n if ('@context' in doc) cfg['@context'] = doc['@context']\n const hashData = cat(await sha(te.encode(jcs(cfg))), await sha(te.encode(jcs(doc))))\n const sig = new Uint8Array(await S().sign({ name: 'Ed25519' }, ctx.ed.priv, hashData))\n return { ...doc, proof: { ...cfg, proofValue: 'z' + base58(sig) } }\n}\n/**\n * The same eddsa-jcs-2022 proof as diSign, with the signature from a\n * signing function instead of a private key: the holder signs through\n * its KeyProvider (`keys.sign(label, bytes)`, raw Ed25519 over the\n * hashData), so modules never hold a key. Ed25519 is deterministic: for\n * the same key, document and `created` the result is byte-identical to\n * diSign's.\n */\nexport async function diSignWith<T extends Record<string, any>> (\n anchor: string, sign: (hashData: Uint8Array) => Promise<Uint8Array>, doc: T, created: string, subtle?: SubtleCrypto,\n): Promise<T & { proof: Record<string, any> }> {\n const cfg: Record<string, any> = { type: 'DataIntegrityProof', cryptosuite: 'eddsa-jcs-2022', created, verificationMethod: anchor + '#' + anchor.slice(8), proofPurpose: 'assertionMethod' }\n if ('@context' in doc) cfg['@context'] = doc['@context']\n const hashData = cat(await sha(te.encode(jcs(cfg)), subtle), await sha(te.encode(jcs(doc)), subtle))\n const sig = await sign(hashData)\n if (!(sig instanceof Uint8Array) || sig.length !== 64) throw new Error('diSignWith: the signer must answer a 64-byte Ed25519 signature')\n return { ...doc, proof: { ...cfg, proofValue: 'z' + base58(sig) } }\n}\n/** `subtle`: the holder's resolved handle; without one the platform's, at call time. */\nexport async function diVerify (doc: any, expectedAnchor?: string, subtle?: SubtleCrypto): Promise<boolean> {\n const { proof, ...rest } = doc ?? {}\n if (typeof proof?.proofValue !== 'string' || typeof proof?.verificationMethod !== 'string') return false\n // M-3 (review 1): this predicate verifies THE RLTP proof, not any\n // signature that happens to be valid under the key — a config with a\n // foreign type, suite, purpose or timestamp form is false here, whether\n // or not a schema runs first.\n if (proof.type !== 'DataIntegrityProof' || proof.cryptosuite !== 'eddsa-jcs-2022') return false\n if (proof.proofPurpose !== 'assertionMethod') return false\n if (typeof proof.created !== 'string' || !calOK(proof.created)) return false\n const vmDid = proof.verificationMethod.split('#')[0] as string\n if (proof.verificationMethod !== vmDid + '#' + vmDid.slice(8)) return false\n if (expectedAnchor && vmDid !== expectedAnchor) return false\n if ('@context' in rest && jcs(proof['@context'] ?? null) !== jcs(rest['@context'])) return false\n const raw = edRawOfAnchor(vmDid)\n if (!raw) return false\n const zsig = proof.proofValue\n if (typeof zsig !== 'string' || zsig[0] !== 'z') return false\n const sig = fromBase58(zsig.slice(1))\n // exactly 64 bytes, canonical base58btc — no left-pad repair (Encounter 2.3)\n if (!sig || sig.length !== 64 || 'z' + base58(sig) !== zsig) return false\n const { proofValue, ...cfg } = proof\n const SS = subtle ?? S()\n const hashData = cat(await sha(te.encode(jcs(cfg)), SS), await sha(te.encode(jcs(rest)), SS))\n const pub = await SS.importKey('raw', raw, { name: 'Ed25519' }, false, ['verify'])\n return SS.verify({ name: 'Ed25519' }, pub, sig, hashData)\n}\n\n"]}
|
package/dist/delivery.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ export interface SealEntropy {
|
|
|
11
11
|
ephSeed?: Uint8Array;
|
|
12
12
|
nonce?: Uint8Array;
|
|
13
13
|
}
|
|
14
|
-
export declare function seal(document: Json, recipientKeyAgreement: string, { ephSeed, nonce }?: SealEntropy): Promise<Envelope>;
|
|
14
|
+
export declare function seal(document: Json, recipientKeyAgreement: string, { ephSeed, nonce }?: SealEntropy, subtle?: SubtleCrypto): Promise<Envelope>;
|
|
15
15
|
/** Opening an envelope never throws: every failure is a named reason. */
|
|
16
16
|
export type Unsealed = {
|
|
17
17
|
document: Json;
|
|
@@ -20,7 +20,7 @@ export type Unsealed = {
|
|
|
20
20
|
document?: undefined;
|
|
21
21
|
error: 'malformed' | 'oversize' | 'decryption-failed';
|
|
22
22
|
};
|
|
23
|
-
export declare function unseal(env: Envelope, xPriv: CryptoKey): Promise<Unsealed>;
|
|
23
|
+
export declare function unseal(env: Envelope, xPriv: CryptoKey, subtle?: SubtleCrypto): Promise<Unsealed>;
|
|
24
24
|
export interface ReceiveStage {
|
|
25
25
|
stage: 1 | 2 | 3 | 4;
|
|
26
26
|
label: string;
|
|
@@ -33,7 +33,28 @@ export interface Received {
|
|
|
33
33
|
/** present when the chain passed stage 4 (also on duplicate-known) */
|
|
34
34
|
document?: Json;
|
|
35
35
|
digest?: string;
|
|
36
|
+
/** why the key failed: 'unknown' at stage 2 (an rkid never issued),
|
|
37
|
+
* 'retired' at stage 3 (a tombstone). Local diagnosis only: the
|
|
38
|
+
* disposition stays the one Delivery §6.2 names. */
|
|
39
|
+
key?: 'unknown' | 'retired';
|
|
36
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* What a receiver's key agreement answers for an envelope's rkid and
|
|
43
|
+
* ephemeral key (Delivery §5, §6.2 stages 2–3): the raw X25519 shared
|
|
44
|
+
* secret; `retired` for a tombstone (known, the key destroyed: the
|
|
45
|
+
* envelope dies at stage 3); `unknown` for an rkid never issued (stage 2);
|
|
46
|
+
* `invalid` for an ephemeral key that yields no usable secret (stage 3).
|
|
47
|
+
*/
|
|
48
|
+
export type KeyAnswer = {
|
|
49
|
+
status: 'available';
|
|
50
|
+
shared: Uint8Array;
|
|
51
|
+
} | {
|
|
52
|
+
status: 'retired';
|
|
53
|
+
} | {
|
|
54
|
+
status: 'unknown';
|
|
55
|
+
} | {
|
|
56
|
+
status: 'invalid';
|
|
57
|
+
};
|
|
37
58
|
/**
|
|
38
59
|
* The generic stages every delivery passes before its layer sees it.
|
|
39
60
|
* World-neutral: keys come from the caller's resolver, the
|
|
@@ -47,5 +68,12 @@ export interface Received {
|
|
|
47
68
|
* as decryption-failed, indistinguishable from any other undecryptable
|
|
48
69
|
* envelope); undefined means "unknown rkid" and fails stage 2.
|
|
49
70
|
*/
|
|
50
|
-
export declare function receive(env: unknown, keyForRkid: (rkid: string) => CryptoKey | null | undefined, completedEffects?: Set<string
|
|
71
|
+
export declare function receive(env: unknown, keyForRkid: (rkid: string) => CryptoKey | null | undefined, completedEffects?: Set<string>, subtle?: SubtleCrypto): Promise<Received>;
|
|
72
|
+
/**
|
|
73
|
+
* The same stages over a key agreement: `agree(rkid, epk)` is asked once,
|
|
74
|
+
* after the envelope's closed form passed, and its answer decides stage 2
|
|
75
|
+
* (unknown) and feeds stage 3. `completed(digest)` is the completed-effect
|
|
76
|
+
* cache, read only.
|
|
77
|
+
*/
|
|
78
|
+
export declare function receiveByAgreement(env: unknown, agree: (rkid: string, epk: Uint8Array) => Promise<KeyAnswer>, completed?: (digest: string) => boolean, subtle?: SubtleCrypto): Promise<Received>;
|
|
51
79
|
//# sourceMappingURL=delivery.d.ts.map
|
package/dist/delivery.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAsBrC,kGAAkG;AAClG,MAAM,WAAW,QAAQ;IAAG,IAAI,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE;AAC1F,wFAAwF;AACxF,MAAM,WAAW,WAAW;IAAG,OAAO,CAAC,EAAE,UAAU,CAAC;IAAC,KAAK,CAAC,EAAE,UAAU,CAAA;CAAE;AAEzE,wBAAsB,IAAI,CACxB,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,GAAE,WAAgB,EAAE,MAAM,CAAC,EAAE,YAAY,GACzG,OAAO,CAAC,QAAQ,CAAC,CAenB;AAED,yEAAyE;AACzE,MAAM,MAAM,QAAQ,GAAG;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,KAAK,CAAC,EAAE,SAAS,CAAA;CAAE,GAAG;IAAE,QAAQ,CAAC,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,WAAW,GAAG,UAAU,GAAG,mBAAmB,CAAA;CAAE,CAAA;AAiB9I,wBAAsB,MAAM,CAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,CAWvG;AAGD,MAAM,WAAW,YAAY;IAAG,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,OAAO,CAAA;CAAE;AAClF,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,mBAAmB,GAAG,2BAA2B,CAAA;AAC/H,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,YAAY,EAAE,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,sEAAsE;IACtE,QAAQ,CAAC,EAAE,IAAI,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;yDAEqD;IACrD,GAAG,CAAC,EAAE,SAAS,GAAG,SAAS,CAAA;CAC5B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GACjB;IAAE,MAAM,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,GAC3C;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,CAAA;AAEzB;;;;;;;;;;;;GAYG;AACH,wBAAsB,OAAO,CAC3B,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,EAC1D,gBAAgB,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,EAC9B,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,QAAQ,CAAC,CAQnB;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,UAAU,KAAK,OAAO,CAAC,SAAS,CAAC,EAC5D,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,EACvC,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,QAAQ,CAAC,CA+CnB"}
|
package/dist/delivery.js
CHANGED
|
@@ -15,10 +15,17 @@
|
|
|
15
15
|
// rejection is not an effect and stays repeatable); a cached digest
|
|
16
16
|
// answers 'duplicate-known' forever after, and a second delivery never
|
|
17
17
|
// produces a second effect. receive() honors such a cache when given one.
|
|
18
|
+
//
|
|
19
|
+
// Two ways to name the receiver's key: receive() takes a resolver to the
|
|
20
|
+
// private CryptoKey (an identity Context's); receiveByAgreement()
|
|
21
|
+
// takes an asynchronous key agreement that answers with the shared secret
|
|
22
|
+
// or why not (the holder's KeyProvider, which never hands out a key).
|
|
23
|
+
// Both run the same stages. Every function here takes an optional
|
|
24
|
+
// SubtleCrypto; without one it uses the platform's at call time.
|
|
18
25
|
import { jcs, b64uOf, fromB64u } from './core.js';
|
|
19
26
|
import { hkdf, xFromSeed, xRawOfMk, ecdh, digestDoc, rand } from './crypto.js';
|
|
27
|
+
import { platformSubtle } from './crypto.js';
|
|
20
28
|
const te = new TextEncoder();
|
|
21
|
-
const S = globalThis.crypto.subtle;
|
|
22
29
|
// canonical base64url or nothing — a second spelling of the same bytes
|
|
23
30
|
// is a different string, and dedup digests are computed over strings
|
|
24
31
|
const canonicalB64u = (s) => {
|
|
@@ -36,23 +43,24 @@ const canonicalB64u = (s) => {
|
|
|
36
43
|
// ── sealed envelope (Delivery §5) ───────────────────────────────────────
|
|
37
44
|
// X25519 ephemeral → HKDF('rltp/v1/seal') → AES-256-GCM (12-byte nonce,
|
|
38
45
|
// 16-byte tag appended). Entropy is caller-suppliable for replay.
|
|
39
|
-
const aesKey = async (shared, usage) => {
|
|
46
|
+
const aesKey = async (shared, usage, S) => {
|
|
40
47
|
if (shared.every((b) => b === 0))
|
|
41
48
|
throw new Error('all-zero shared secret');
|
|
42
|
-
return S.importKey('raw', await hkdf(shared, 'rltp/v1/seal'), { name: 'AES-GCM' }, false, [usage]);
|
|
49
|
+
return S.importKey('raw', await hkdf(shared, 'rltp/v1/seal', 32, S), { name: 'AES-GCM' }, false, [usage]);
|
|
43
50
|
};
|
|
44
|
-
export async function seal(document, recipientKeyAgreement, { ephSeed, nonce } = {}) {
|
|
51
|
+
export async function seal(document, recipientKeyAgreement, { ephSeed, nonce } = {}, subtle) {
|
|
45
52
|
// a producer API never emits what the contract rejects (B-3): the only
|
|
46
53
|
// envelope nonce is 96 bits, the only ephemeral seed 32 bytes
|
|
47
54
|
if (ephSeed !== undefined && !(ephSeed instanceof Uint8Array && ephSeed.length === 32))
|
|
48
55
|
throw new Error('ephSeed must be exactly 32 bytes');
|
|
49
56
|
if (nonce !== undefined && !(nonce instanceof Uint8Array && nonce.length === 12))
|
|
50
57
|
throw new Error('envelope nonce must be exactly 12 bytes (Delivery §5)');
|
|
51
|
-
const
|
|
58
|
+
const S = subtle ?? platformSubtle();
|
|
59
|
+
const eph = await xFromSeed(ephSeed ?? rand(32), S);
|
|
52
60
|
const theirRaw = xRawOfMk(recipientKeyAgreement);
|
|
53
61
|
if (!theirRaw)
|
|
54
62
|
throw new Error('malformed recipient keyAgreement');
|
|
55
|
-
const key = await aesKey(await ecdh(eph.priv, theirRaw), 'encrypt');
|
|
63
|
+
const key = await aesKey(await ecdh(eph.priv, theirRaw, S), 'encrypt', S);
|
|
56
64
|
const n = nonce ?? rand(12);
|
|
57
65
|
const plaintext = te.encode(jcs(document));
|
|
58
66
|
if (plaintext.length > 65536)
|
|
@@ -60,19 +68,11 @@ export async function seal(document, recipientKeyAgreement, { ephSeed, nonce } =
|
|
|
60
68
|
const ct = new Uint8Array(await S.encrypt({ name: 'AES-GCM', iv: n }, key, plaintext));
|
|
61
69
|
return { rkid: recipientKeyAgreement, epk: b64uOf(eph.pubRaw), nonce: b64uOf(n), ciphertext: b64uOf(ct) };
|
|
62
70
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
// non-canonical base64url is 'malformed', never an exception
|
|
66
|
-
const nonce = canonicalB64u(env?.nonce), epkRaw = canonicalB64u(env?.epk), raw = canonicalB64u(env?.ciphertext);
|
|
67
|
-
if (!nonce || !epkRaw || !raw)
|
|
68
|
-
return { error: 'malformed' };
|
|
69
|
-
if (nonce.length !== 12 || epkRaw.length !== 32 || raw.length < 16)
|
|
70
|
-
return { error: 'malformed' };
|
|
71
|
-
if (raw.length - 16 > 65536)
|
|
72
|
-
return { error: 'oversize' }; // size bound BEFORE decryption
|
|
71
|
+
/** Decrypt and parse under an agreed shared secret; never throws. */
|
|
72
|
+
async function openShared(nonce, raw, shared, S) {
|
|
73
73
|
let key;
|
|
74
74
|
try {
|
|
75
|
-
key = await aesKey(
|
|
75
|
+
key = await aesKey(shared, 'decrypt', S);
|
|
76
76
|
}
|
|
77
77
|
catch {
|
|
78
78
|
return { error: 'decryption-failed' };
|
|
@@ -101,6 +101,26 @@ export async function unseal(env, xPriv) {
|
|
|
101
101
|
return { error: 'malformed' };
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
|
+
export async function unseal(env, xPriv, subtle) {
|
|
105
|
+
// total over ARBITRARY input (B-4): a foreign envelope with invalid or
|
|
106
|
+
// non-canonical base64url is 'malformed', never an exception
|
|
107
|
+
const nonce = canonicalB64u(env?.nonce), epkRaw = canonicalB64u(env?.epk), raw = canonicalB64u(env?.ciphertext);
|
|
108
|
+
if (!nonce || !epkRaw || !raw)
|
|
109
|
+
return { error: 'malformed' };
|
|
110
|
+
if (nonce.length !== 12 || epkRaw.length !== 32 || raw.length < 16)
|
|
111
|
+
return { error: 'malformed' };
|
|
112
|
+
if (raw.length - 16 > 65536)
|
|
113
|
+
return { error: 'oversize' }; // size bound BEFORE decryption
|
|
114
|
+
const S = subtle ?? platformSubtle();
|
|
115
|
+
let shared;
|
|
116
|
+
try {
|
|
117
|
+
shared = await ecdh(xPriv, epkRaw, S);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
return { error: 'decryption-failed' };
|
|
121
|
+
}
|
|
122
|
+
return openShared(nonce, raw, shared, S);
|
|
123
|
+
}
|
|
104
124
|
/**
|
|
105
125
|
* The generic stages every delivery passes before its layer sees it.
|
|
106
126
|
* World-neutral: keys come from the caller's resolver, the
|
|
@@ -114,7 +134,30 @@ export async function unseal(env, xPriv) {
|
|
|
114
134
|
* as decryption-failed, indistinguishable from any other undecryptable
|
|
115
135
|
* envelope); undefined means "unknown rkid" and fails stage 2.
|
|
116
136
|
*/
|
|
117
|
-
export async function receive(env, keyForRkid, completedEffects) {
|
|
137
|
+
export async function receive(env, keyForRkid, completedEffects, subtle) {
|
|
138
|
+
const resolve = async (rkid, epk) => {
|
|
139
|
+
const key = keyForRkid(rkid);
|
|
140
|
+
if (key === undefined)
|
|
141
|
+
return { status: 'unknown' };
|
|
142
|
+
if (key === null)
|
|
143
|
+
return { status: 'retired' };
|
|
144
|
+
try {
|
|
145
|
+
return { status: 'available', shared: await ecdh(key, epk, subtle ?? platformSubtle()) };
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
return { status: 'invalid' };
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
return receiveByAgreement(env, resolve, completedEffects ? (d) => completedEffects.has(d) : undefined, subtle);
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The same stages over a key agreement: `agree(rkid, epk)` is asked once,
|
|
155
|
+
* after the envelope's closed form passed, and its answer decides stage 2
|
|
156
|
+
* (unknown) and feeds stage 3. `completed(digest)` is the completed-effect
|
|
157
|
+
* cache, read only.
|
|
158
|
+
*/
|
|
159
|
+
export async function receiveByAgreement(env, agree, completed, subtle) {
|
|
160
|
+
const S = subtle ?? platformSubtle();
|
|
118
161
|
const stages = [];
|
|
119
162
|
const step = (stage, label, ok) => { stages.push({ stage, label, ok }); return ok; };
|
|
120
163
|
const e = env;
|
|
@@ -127,20 +170,24 @@ export async function receive(env, keyForRkid, completedEffects) {
|
|
|
127
170
|
// canonical; the rkid a decodable multikey the resolver knows
|
|
128
171
|
const isObj = e !== null && typeof e === 'object' && !Array.isArray(e);
|
|
129
172
|
const ctBytes = isObj ? canonicalB64u(e.ciphertext) : null;
|
|
173
|
+
const epkRaw = isObj ? canonicalB64u(e.epk) : null;
|
|
174
|
+
const nonce = isObj ? canonicalB64u(e.nonce) : null;
|
|
130
175
|
const closedForm = isObj && Object.keys(e).length === 4
|
|
131
|
-
&&
|
|
176
|
+
&& epkRaw?.length === 32 && nonce?.length === 12
|
|
132
177
|
&& ctBytes !== null && ctBytes.length >= 17 // tag + at least one byte (schema lower bound)
|
|
133
178
|
&& typeof e.rkid === 'string' && xRawOfMk(e.rkid) !== null;
|
|
134
|
-
const
|
|
135
|
-
if (!step(2, 'envelope: closed form · base64url canonical · epk 32 B · nonce 12 B · rkid known', closedForm &&
|
|
136
|
-
return { stages, disposition: 'failed(malformed)' };
|
|
179
|
+
const answer = closedForm ? await agree(e.rkid, new Uint8Array(epkRaw)) : { status: 'unknown' };
|
|
180
|
+
if (!step(2, 'envelope: closed form · base64url canonical · epk 32 B · nonce 12 B · rkid known', closedForm && answer.status !== 'unknown')) {
|
|
181
|
+
return { stages, disposition: 'failed(malformed)', ...(closedForm ? { key: 'unknown' } : {}) };
|
|
182
|
+
}
|
|
137
183
|
// 3 — decryption: X25519 + HKDF(rltp/v1/seal) + the AES-256-GCM tag.
|
|
138
|
-
// A tombstoned rkid
|
|
139
|
-
const opened =
|
|
184
|
+
// A tombstoned rkid dies HERE, not at stage 2.
|
|
185
|
+
const opened = answer.status === 'available' ? await openShared(nonce, ctBytes, answer.shared, S) : { error: 'decryption-failed' };
|
|
140
186
|
// only CRYPTO failures belong to stage 3; an authenticated plaintext
|
|
141
187
|
// that defeats UTF-8 or JSON is a stage-4 malformed (review 3, M-2)
|
|
142
|
-
if (!step(3, 'decryption: X25519 + HKDF(rltp/v1/seal) + AES-256-GCM tag', opened.error !== 'decryption-failed' && opened.error !== 'oversize'))
|
|
143
|
-
return { stages, disposition: `failed(${opened.error})
|
|
188
|
+
if (!step(3, 'decryption: X25519 + HKDF(rltp/v1/seal) + AES-256-GCM tag', opened.error !== 'decryption-failed' && opened.error !== 'oversize')) {
|
|
189
|
+
return { stages, disposition: `failed(${opened.error})`, ...(answer.status === 'retired' ? { key: 'retired' } : {}) };
|
|
190
|
+
}
|
|
144
191
|
if (opened.error === 'malformed') {
|
|
145
192
|
step(4, 'parse — invalid UTF-8 or not JSON', false);
|
|
146
193
|
return { stages, disposition: 'failed(malformed)' };
|
|
@@ -156,14 +203,14 @@ export async function receive(env, keyForRkid, completedEffects) {
|
|
|
156
203
|
}
|
|
157
204
|
let digest;
|
|
158
205
|
try {
|
|
159
|
-
digest = await digestDoc(doc);
|
|
206
|
+
digest = await digestDoc(doc, S);
|
|
160
207
|
}
|
|
161
208
|
catch {
|
|
162
209
|
step(4, 'parse — no canonical form (non-finite number)', false);
|
|
163
210
|
return { stages, disposition: 'failed(malformed)' };
|
|
164
211
|
}
|
|
165
212
|
step(4, `parse + digest ${digest.slice(0, 14)}… · completed-effect cache`, true);
|
|
166
|
-
if (
|
|
213
|
+
if (completed?.(digest))
|
|
167
214
|
return { stages, disposition: 'duplicate-known', document: doc, digest };
|
|
168
215
|
return { stages, disposition: 'unique', document: doc, digest };
|
|
169
216
|
}
|
package/dist/delivery.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"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","sourcesContent":["// delivery — the Delivery Contract: how documents travel, and what a\n// receiver must check before anything takes effect.\n//\n// The sealed envelope (X25519 ephemeral -> HKDF -> AES-256-GCM) and the\n// generic receive chain in its declared ORDER: the size bound holds\n// BEFORE decryption, the envelope form before that, and the digest is\n// taken over the canonical form of the PARSED document — never over the\n// raw bytes. Each stage names the disposition it produces, so a\n// rejection can always say where it happened.\n//\n// What this module deliberately does NOT carry: the type-specific stages\n// (proofs, bindings, effects) — those belong to the artifact's layer —\n// and the completed-effect CACHE itself. The cache contract is the\n// caller's to keep: only a COMPLETED effect's digest goes in (a\n// rejection is not an effect and stays repeatable); a cached digest\n// answers 'duplicate-known' forever after, and a second delivery never\n// produces a second effect. receive() honors such a cache when given one.\nimport { jcs, b64uOf, fromB64u } from './core.js'\nimport type { Json } from './core.js'\nimport { hkdf, xFromSeed, xRawOfMk, ecdh, digestDoc, rand } from './crypto.js'\n\nconst te = new TextEncoder()\nconst S = globalThis.crypto.subtle\n\n// canonical base64url or nothing — a second spelling of the same bytes\n// is a different string, and dedup digests are computed over strings\nconst canonicalB64u = (s: unknown): Uint8Array | null => {\n if (typeof s !== 'string') return null\n let b: Uint8Array\n try { b = fromB64u(s) } catch { return null }\n return b64uOf(b) === s ? b : null\n}\n\n// ── sealed envelope (Delivery §5) ───────────────────────────────────────\n// X25519 ephemeral → HKDF('rltp/v1/seal') → AES-256-GCM (12-byte nonce,\n// 16-byte tag appended). Entropy is caller-suppliable for replay.\nconst aesKey = async (shared: Uint8Array, usage: 'encrypt' | 'decrypt'): Promise<CryptoKey> => {\n if (shared.every((b) => b === 0)) throw new Error('all-zero shared secret')\n return S.importKey('raw', await hkdf(shared, 'rltp/v1/seal'), { name: 'AES-GCM' }, false, [usage])\n}\n/** A sealed envelope as it travels: recipient key id, ephemeral public key, nonce, ciphertext. */\nexport interface Envelope { rkid: string, epk: string, nonce: string, ciphertext: string }\n/** Caller-supplied entropy — the invariant that makes every construction replayable. */\nexport interface SealEntropy { ephSeed?: Uint8Array, nonce?: Uint8Array }\n\nexport async function seal (\n document: Json, recipientKeyAgreement: string, { ephSeed, nonce }: SealEntropy = {},\n): Promise<Envelope> {\n // a producer API never emits what the contract rejects (B-3): the only\n // envelope nonce is 96 bits, the only ephemeral seed 32 bytes\n if (ephSeed !== undefined && !(ephSeed instanceof Uint8Array && ephSeed.length === 32)) throw new Error('ephSeed must be exactly 32 bytes')\n if (nonce !== undefined && !(nonce instanceof Uint8Array && nonce.length === 12)) throw new Error('envelope nonce must be exactly 12 bytes (Delivery §5)')\n const eph = await xFromSeed(ephSeed ?? rand(32))\n const theirRaw = xRawOfMk(recipientKeyAgreement)\n if (!theirRaw) throw new Error('malformed recipient keyAgreement')\n const key = await aesKey(await ecdh(eph.priv, theirRaw), 'encrypt')\n const n = nonce ?? rand(12)\n const plaintext = te.encode(jcs(document))\n if (plaintext.length > 65536) throw new Error('oversize')\n const ct = new Uint8Array(await S.encrypt({ name: 'AES-GCM', iv: n }, key, plaintext))\n return { rkid: recipientKeyAgreement, epk: b64uOf(eph.pubRaw), nonce: b64uOf(n), ciphertext: b64uOf(ct) }\n}\n\n/** Opening an envelope never throws: every failure is a named reason. */\nexport type Unsealed = { document: Json, error?: undefined } | { document?: undefined, error: 'malformed' | 'oversize' | 'decryption-failed' }\n\nexport async function unseal (env: Envelope, xPriv: CryptoKey): Promise<Unsealed> {\n // total over ARBITRARY input (B-4): a foreign envelope with invalid or\n // non-canonical base64url is 'malformed', never an exception\n const nonce = canonicalB64u(env?.nonce), epkRaw = canonicalB64u(env?.epk), raw = canonicalB64u(env?.ciphertext)\n if (!nonce || !epkRaw || !raw) return { error: 'malformed' }\n if (nonce.length !== 12 || epkRaw.length !== 32 || raw.length < 16) return { error: 'malformed' }\n if (raw.length - 16 > 65536) return { error: 'oversize' } // size bound BEFORE decryption\n let key\n try { key = await aesKey(await ecdh(xPriv, epkRaw), 'decrypt') } catch { return { error: 'decryption-failed' } }\n let bytes\n try { bytes = await S.decrypt({ name: 'AES-GCM', iv: nonce }, key, raw) } catch { return { error: 'decryption-failed' } }\n // from here the cryptography has SPOKEN — everything below is form:\n // authenticated invalid UTF-8 and unparseable JSON are 'malformed'\n // (stage 4 in the receive chain), never a crypto failure (review 3, M-2)\n let plaintext\n try { plaintext = new TextDecoder('utf-8', { fatal: true }).decode(bytes) } catch { return { error: 'malformed' } }\n try { return { document: JSON.parse(plaintext) } }\n catch { return { error: 'malformed' } }\n}\n\n// ── the generic receive chain (Delivery §4: stages 1–4) ─────────────────\nexport interface ReceiveStage { stage: 1 | 2 | 3 | 4, label: string, ok: boolean }\nexport type Disposition = 'unique' | 'duplicate-known' | 'failed(oversize)' | 'failed(malformed)' | 'failed(decryption-failed)'\nexport interface Received {\n stages: ReceiveStage[]\n disposition: Disposition\n /** present when the chain passed stage 4 (also on duplicate-known) */\n document?: Json\n digest?: string\n}\n\n/**\n * The generic stages every delivery passes before its layer sees it.\n * World-neutral: keys come from the caller's resolver, the\n * completed-effect cache is the caller's set of digests. This function\n * only READS the cache — the caller adds a digest after (and only\n * after) the type-specific effect completed.\n *\n * The resolver speaks three words (Delivery §4, stage 2/3): a CryptoKey\n * means \"known, here is the key\"; null means \"known, but the key is\n * gone\" (a tombstone — the envelope passes stage 2 and dies at stage 3\n * as decryption-failed, indistinguishable from any other undecryptable\n * envelope); undefined means \"unknown rkid\" and fails stage 2.\n */\nexport async function receive (\n env: unknown,\n keyForRkid: (rkid: string) => CryptoKey | null | undefined,\n completedEffects?: Set<string>,\n): Promise<Received> {\n const stages: ReceiveStage[] = []\n const step = (stage: ReceiveStage['stage'], label: string, ok: boolean): boolean => { stages.push({ stage, label, ok }); return ok }\n const e = env as Partial<Envelope> | null | undefined\n\n // 1 — the size bound holds BEFORE any decoding or decryption work:\n // estimated from the string alone, so an oversize envelope costs O(1)\n const ctEst = typeof e?.ciphertext === 'string' ? Math.floor(e.ciphertext.length * 3 / 4) : 0\n if (!step(1, `size bound: ciphertext − tag ≤ 65536 B (~${Math.max(0, ctEst - 16)} B)`, ctEst - 16 <= 65536)) return { stages, disposition: 'failed(oversize)' }\n\n // 2 — envelope form: the CLOSED shape — exactly the four fields, each\n // canonical; the rkid a decodable multikey the resolver knows\n const isObj = e !== null && typeof e === 'object' && !Array.isArray(e)\n const ctBytes = isObj ? canonicalB64u((e as any).ciphertext) : null\n const closedForm = isObj && Object.keys(e).length === 4\n && canonicalB64u(e.epk)?.length === 32 && canonicalB64u(e.nonce)?.length === 12\n && ctBytes !== null && ctBytes.length >= 17 // tag + at least one byte (schema lower bound)\n && typeof e.rkid === 'string' && xRawOfMk(e.rkid) !== null\n const key = closedForm ? keyForRkid((e as Envelope).rkid) : undefined\n if (!step(2, 'envelope: closed form · base64url canonical · epk 32 B · nonce 12 B · rkid known', closedForm && key !== undefined)) return { stages, disposition: 'failed(malformed)' }\n\n // 3 — decryption: X25519 + HKDF(rltp/v1/seal) + the AES-256-GCM tag.\n // A tombstoned rkid (key === null) dies HERE, not at stage 2.\n const opened = key === null ? { error: 'decryption-failed' as const } : await unseal(e as Envelope, key as CryptoKey)\n // only CRYPTO failures belong to stage 3; an authenticated plaintext\n // that defeats UTF-8 or JSON is a stage-4 malformed (review 3, M-2)\n if (!step(3, 'decryption: X25519 + HKDF(rltp/v1/seal) + AES-256-GCM tag', opened.error !== 'decryption-failed' && opened.error !== 'oversize')) return { stages, disposition: `failed(${opened.error!})` as Disposition }\n if (opened.error === 'malformed') { step(4, 'parse — invalid UTF-8 or not JSON', false); return { stages, disposition: 'failed(malformed)' } }\n\n // 4 — parse: a JSON object; digest over its CANONICAL form; cache\n // check. TOTAL: a document that parses but defeats the canonical\n // form (JSON.parse turns 1e400 into Infinity) is malformed here,\n // never an exception (review 2, B-2).\n const doc = (opened as { document?: Json }).document\n if (doc === null || doc === undefined || typeof doc !== 'object' || Array.isArray(doc)) { step(4, 'parse — not a JSON object', false); return { stages, disposition: 'failed(malformed)' } }\n let digest: string\n try { digest = await digestDoc(doc) } catch { step(4, 'parse — no canonical form (non-finite number)', false); return { stages, disposition: 'failed(malformed)' } }\n step(4, `parse + digest ${digest.slice(0, 14)}… · completed-effect cache`, true)\n if (completedEffects?.has(digest)) return { stages, disposition: 'duplicate-known', document: doc, digest }\n return { stages, disposition: 'unique', document: doc, digest }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"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","sourcesContent":["// delivery — the Delivery Contract: how documents travel, and what a\n// receiver must check before anything takes effect.\n//\n// The sealed envelope (X25519 ephemeral -> HKDF -> AES-256-GCM) and the\n// generic receive chain in its declared ORDER: the size bound holds\n// BEFORE decryption, the envelope form before that, and the digest is\n// taken over the canonical form of the PARSED document — never over the\n// raw bytes. Each stage names the disposition it produces, so a\n// rejection can always say where it happened.\n//\n// What this module deliberately does NOT carry: the type-specific stages\n// (proofs, bindings, effects) — those belong to the artifact's layer —\n// and the completed-effect CACHE itself. The cache contract is the\n// caller's to keep: only a COMPLETED effect's digest goes in (a\n// rejection is not an effect and stays repeatable); a cached digest\n// answers 'duplicate-known' forever after, and a second delivery never\n// produces a second effect. receive() honors such a cache when given one.\n//\n// Two ways to name the receiver's key: receive() takes a resolver to the\n// private CryptoKey (an identity Context's); receiveByAgreement()\n// takes an asynchronous key agreement that answers with the shared secret\n// or why not (the holder's KeyProvider, which never hands out a key).\n// Both run the same stages. Every function here takes an optional\n// SubtleCrypto; without one it uses the platform's at call time.\nimport { jcs, b64uOf, fromB64u } from './core.js'\nimport type { Json } from './core.js'\nimport { hkdf, xFromSeed, xRawOfMk, ecdh, digestDoc, rand } from './crypto.js'\nimport { platformSubtle } from './crypto.js'\n\nconst te = new TextEncoder()\n\n// canonical base64url or nothing — a second spelling of the same bytes\n// is a different string, and dedup digests are computed over strings\nconst canonicalB64u = (s: unknown): Uint8Array | null => {\n if (typeof s !== 'string') return null\n let b: Uint8Array\n try { b = fromB64u(s) } catch { return null }\n return b64uOf(b) === s ? b : null\n}\n\n// ── sealed envelope (Delivery §5) ───────────────────────────────────────\n// X25519 ephemeral → HKDF('rltp/v1/seal') → AES-256-GCM (12-byte nonce,\n// 16-byte tag appended). Entropy is caller-suppliable for replay.\nconst aesKey = async (shared: Uint8Array, usage: 'encrypt' | 'decrypt', S: SubtleCrypto): Promise<CryptoKey> => {\n if (shared.every((b) => b === 0)) throw new Error('all-zero shared secret')\n return S.importKey('raw', await hkdf(shared, 'rltp/v1/seal', 32, S), { name: 'AES-GCM' }, false, [usage])\n}\n/** A sealed envelope as it travels: recipient key id, ephemeral public key, nonce, ciphertext. */\nexport interface Envelope { rkid: string, epk: string, nonce: string, ciphertext: string }\n/** Caller-supplied entropy — the invariant that makes every construction replayable. */\nexport interface SealEntropy { ephSeed?: Uint8Array, nonce?: Uint8Array }\n\nexport async function seal (\n document: Json, recipientKeyAgreement: string, { ephSeed, nonce }: SealEntropy = {}, subtle?: SubtleCrypto,\n): Promise<Envelope> {\n // a producer API never emits what the contract rejects (B-3): the only\n // envelope nonce is 96 bits, the only ephemeral seed 32 bytes\n if (ephSeed !== undefined && !(ephSeed instanceof Uint8Array && ephSeed.length === 32)) throw new Error('ephSeed must be exactly 32 bytes')\n if (nonce !== undefined && !(nonce instanceof Uint8Array && nonce.length === 12)) throw new Error('envelope nonce must be exactly 12 bytes (Delivery §5)')\n const S = subtle ?? platformSubtle()\n const eph = await xFromSeed(ephSeed ?? rand(32), S)\n const theirRaw = xRawOfMk(recipientKeyAgreement)\n if (!theirRaw) throw new Error('malformed recipient keyAgreement')\n const key = await aesKey(await ecdh(eph.priv, theirRaw, S), 'encrypt', S)\n const n = nonce ?? rand(12)\n const plaintext = te.encode(jcs(document))\n if (plaintext.length > 65536) throw new Error('oversize')\n const ct = new Uint8Array(await S.encrypt({ name: 'AES-GCM', iv: n }, key, plaintext))\n return { rkid: recipientKeyAgreement, epk: b64uOf(eph.pubRaw), nonce: b64uOf(n), ciphertext: b64uOf(ct) }\n}\n\n/** Opening an envelope never throws: every failure is a named reason. */\nexport type Unsealed = { document: Json, error?: undefined } | { document?: undefined, error: 'malformed' | 'oversize' | 'decryption-failed' }\n\n/** Decrypt and parse under an agreed shared secret; never throws. */\nasync function openShared (nonce: Uint8Array, raw: Uint8Array, shared: Uint8Array, S: SubtleCrypto): Promise<Unsealed> {\n let key\n try { key = await aesKey(shared, 'decrypt', S) } catch { return { error: 'decryption-failed' } }\n let bytes\n try { bytes = await S.decrypt({ name: 'AES-GCM', iv: nonce }, key, raw) } catch { return { error: 'decryption-failed' } }\n // from here the cryptography has SPOKEN — everything below is form:\n // authenticated invalid UTF-8 and unparseable JSON are 'malformed'\n // (stage 4 in the receive chain), never a crypto failure (review 3, M-2)\n let plaintext\n try { plaintext = new TextDecoder('utf-8', { fatal: true }).decode(bytes) } catch { return { error: 'malformed' } }\n try { return { document: JSON.parse(plaintext) } }\n catch { return { error: 'malformed' } }\n}\n\nexport async function unseal (env: Envelope, xPriv: CryptoKey, subtle?: SubtleCrypto): Promise<Unsealed> {\n // total over ARBITRARY input (B-4): a foreign envelope with invalid or\n // non-canonical base64url is 'malformed', never an exception\n const nonce = canonicalB64u(env?.nonce), epkRaw = canonicalB64u(env?.epk), raw = canonicalB64u(env?.ciphertext)\n if (!nonce || !epkRaw || !raw) return { error: 'malformed' }\n if (nonce.length !== 12 || epkRaw.length !== 32 || raw.length < 16) return { error: 'malformed' }\n if (raw.length - 16 > 65536) return { error: 'oversize' } // size bound BEFORE decryption\n const S = subtle ?? platformSubtle()\n let shared\n try { shared = await ecdh(xPriv, epkRaw, S) } catch { return { error: 'decryption-failed' } }\n return openShared(nonce, raw, shared, S)\n}\n\n// ── the generic receive chain (Delivery §4: stages 1–4) ─────────────────\nexport interface ReceiveStage { stage: 1 | 2 | 3 | 4, label: string, ok: boolean }\nexport type Disposition = 'unique' | 'duplicate-known' | 'failed(oversize)' | 'failed(malformed)' | 'failed(decryption-failed)'\nexport interface Received {\n stages: ReceiveStage[]\n disposition: Disposition\n /** present when the chain passed stage 4 (also on duplicate-known) */\n document?: Json\n digest?: string\n /** why the key failed: 'unknown' at stage 2 (an rkid never issued),\n * 'retired' at stage 3 (a tombstone). Local diagnosis only: the\n * disposition stays the one Delivery §6.2 names. */\n key?: 'unknown' | 'retired'\n}\n\n/**\n * What a receiver's key agreement answers for an envelope's rkid and\n * ephemeral key (Delivery §5, §6.2 stages 2–3): the raw X25519 shared\n * secret; `retired` for a tombstone (known, the key destroyed: the\n * envelope dies at stage 3); `unknown` for an rkid never issued (stage 2);\n * `invalid` for an ephemeral key that yields no usable secret (stage 3).\n */\nexport type KeyAnswer =\n | { status: 'available', shared: Uint8Array }\n | { status: 'retired' }\n | { status: 'unknown' }\n | { status: 'invalid' }\n\n/**\n * The generic stages every delivery passes before its layer sees it.\n * World-neutral: keys come from the caller's resolver, the\n * completed-effect cache is the caller's set of digests. This function\n * only READS the cache — the caller adds a digest after (and only\n * after) the type-specific effect completed.\n *\n * The resolver speaks three words (Delivery §4, stage 2/3): a CryptoKey\n * means \"known, here is the key\"; null means \"known, but the key is\n * gone\" (a tombstone — the envelope passes stage 2 and dies at stage 3\n * as decryption-failed, indistinguishable from any other undecryptable\n * envelope); undefined means \"unknown rkid\" and fails stage 2.\n */\nexport async function receive (\n env: unknown,\n keyForRkid: (rkid: string) => CryptoKey | null | undefined,\n completedEffects?: Set<string>,\n subtle?: SubtleCrypto,\n): Promise<Received> {\n const resolve = async (rkid: string, epk: Uint8Array): Promise<KeyAnswer> => {\n const key = keyForRkid(rkid)\n if (key === undefined) return { status: 'unknown' }\n if (key === null) return { status: 'retired' }\n try { return { status: 'available', shared: await ecdh(key, epk, subtle ?? platformSubtle()) } } catch { return { status: 'invalid' } }\n }\n return receiveByAgreement(env, resolve, completedEffects ? (d) => completedEffects.has(d) : undefined, subtle)\n}\n\n/**\n * The same stages over a key agreement: `agree(rkid, epk)` is asked once,\n * after the envelope's closed form passed, and its answer decides stage 2\n * (unknown) and feeds stage 3. `completed(digest)` is the completed-effect\n * cache, read only.\n */\nexport async function receiveByAgreement (\n env: unknown,\n agree: (rkid: string, epk: Uint8Array) => Promise<KeyAnswer>,\n completed?: (digest: string) => boolean,\n subtle?: SubtleCrypto,\n): Promise<Received> {\n const S = subtle ?? platformSubtle()\n const stages: ReceiveStage[] = []\n const step = (stage: ReceiveStage['stage'], label: string, ok: boolean): boolean => { stages.push({ stage, label, ok }); return ok }\n const e = env as Partial<Envelope> | null | undefined\n\n // 1 — the size bound holds BEFORE any decoding or decryption work:\n // estimated from the string alone, so an oversize envelope costs O(1)\n const ctEst = typeof e?.ciphertext === 'string' ? Math.floor(e.ciphertext.length * 3 / 4) : 0\n if (!step(1, `size bound: ciphertext − tag ≤ 65536 B (~${Math.max(0, ctEst - 16)} B)`, ctEst - 16 <= 65536)) return { stages, disposition: 'failed(oversize)' }\n\n // 2 — envelope form: the CLOSED shape — exactly the four fields, each\n // canonical; the rkid a decodable multikey the resolver knows\n const isObj = e !== null && typeof e === 'object' && !Array.isArray(e)\n const ctBytes = isObj ? canonicalB64u((e as any).ciphertext) : null\n const epkRaw = isObj ? canonicalB64u(e.epk) : null\n const nonce = isObj ? canonicalB64u(e.nonce) : null\n const closedForm = isObj && Object.keys(e).length === 4\n && epkRaw?.length === 32 && nonce?.length === 12\n && ctBytes !== null && ctBytes.length >= 17 // tag + at least one byte (schema lower bound)\n && typeof e.rkid === 'string' && xRawOfMk(e.rkid) !== null\n const answer: KeyAnswer = closedForm ? await agree((e as Envelope).rkid, new Uint8Array(epkRaw!)) : { status: 'unknown' }\n if (!step(2, 'envelope: closed form · base64url canonical · epk 32 B · nonce 12 B · rkid known', closedForm && answer.status !== 'unknown')) {\n return { stages, disposition: 'failed(malformed)', ...(closedForm ? { key: 'unknown' as const } : {}) }\n }\n\n // 3 — decryption: X25519 + HKDF(rltp/v1/seal) + the AES-256-GCM tag.\n // A tombstoned rkid dies HERE, not at stage 2.\n const opened: Unsealed = answer.status === 'available' ? await openShared(nonce!, ctBytes!, answer.shared, S) : { error: 'decryption-failed' }\n // only CRYPTO failures belong to stage 3; an authenticated plaintext\n // that defeats UTF-8 or JSON is a stage-4 malformed (review 3, M-2)\n if (!step(3, 'decryption: X25519 + HKDF(rltp/v1/seal) + AES-256-GCM tag', opened.error !== 'decryption-failed' && opened.error !== 'oversize')) {\n return { stages, disposition: `failed(${opened.error!})` as Disposition, ...(answer.status === 'retired' ? { key: 'retired' as const } : {}) }\n }\n if (opened.error === 'malformed') { step(4, 'parse — invalid UTF-8 or not JSON', false); return { stages, disposition: 'failed(malformed)' } }\n\n // 4 — parse: a JSON object; digest over its CANONICAL form; cache\n // check. TOTAL: a document that parses but defeats the canonical\n // form (JSON.parse turns 1e400 into Infinity) is malformed here,\n // never an exception (review 2, B-2).\n const doc = (opened as { document?: Json }).document\n if (doc === null || doc === undefined || typeof doc !== 'object' || Array.isArray(doc)) { step(4, 'parse — not a JSON object', false); return { stages, disposition: 'failed(malformed)' } }\n let digest: string\n try { digest = await digestDoc(doc, S) } catch { step(4, 'parse — no canonical form (non-finite number)', false); return { stages, disposition: 'failed(malformed)' } }\n step(4, `parse + digest ${digest.slice(0, 14)}… · completed-effect cache`, true)\n if (completed?.(digest)) return { stages, disposition: 'duplicate-known', document: doc, digest }\n return { stages, disposition: 'unique', document: doc, digest }\n}\n"]}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { Json } from '../core.js';
|
|
2
|
+
import { BUNDLE_TYPE, DELIVERY_TYPE } from '../encounter.js';
|
|
3
|
+
import type { HolderModule } from '../engine.js';
|
|
4
|
+
import type { HolderState, Millis } from '../state.js';
|
|
5
|
+
export { BUNDLE_TYPE, DELIVERY_TYPE };
|
|
6
|
+
/** The command names of the human acts. */
|
|
7
|
+
export declare const ENCOUNTER_COMMANDS: Readonly<{
|
|
8
|
+
show: "encounter.show";
|
|
9
|
+
scan: "encounter.scan";
|
|
10
|
+
capture: "encounter.capture";
|
|
11
|
+
counter: "encounter.counter";
|
|
12
|
+
}>;
|
|
13
|
+
export interface ShowInput {
|
|
14
|
+
name?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ScanInput {
|
|
17
|
+
card: Json;
|
|
18
|
+
name?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface CaptureInput {
|
|
21
|
+
card: Json;
|
|
22
|
+
}
|
|
23
|
+
export interface CounterInput {
|
|
24
|
+
contactId: string;
|
|
25
|
+
}
|
|
26
|
+
/** The contact and relationship ids of the tuple under an own pair label. */
|
|
27
|
+
export declare const idsOf: (label: string) => {
|
|
28
|
+
contactId: string;
|
|
29
|
+
relId: string;
|
|
30
|
+
};
|
|
31
|
+
/** The prompt that asks to confirm the enactment of record `own`. */
|
|
32
|
+
export declare const confirmPromptId: (own: string) => string;
|
|
33
|
+
/** The own-challenge resolution (5240): recorded, open, else unknown. */
|
|
34
|
+
export declare function resolve(state: Readonly<HolderState>, value: string, when: Millis): 'recorded' | 'open' | 'unknown';
|
|
35
|
+
/** The encounter module createHolder registers. */
|
|
36
|
+
export declare function encounterModule(): HolderModule;
|
|
37
|
+
//# sourceMappingURL=ceremony.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ceremony.d.ts","sourceRoot":"","sources":["../../src/encounter/ceremony.ts"],"names":[],"mappings":"AAoFA,OAAO,KAAK,EAAE,IAAI,EAAc,MAAM,YAAY,CAAA;AAGlD,OAAO,EACL,WAAW,EAA+C,aAAa,EAExE,MAAM,iBAAiB,CAAA;AAMxB,OAAO,KAAK,EAAgD,YAAY,EAAmD,MAAM,cAAc,CAAA;AAC/I,OAAO,KAAK,EAAmC,WAAW,EAAE,MAAM,EAAU,MAAM,aAAa,CAAA;AAI/F,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,CAAA;AAErC,2CAA2C;AAC3C,eAAO,MAAM,kBAAkB;;;;;EAK7B,CAAA;AAEF,MAAM,WAAW,SAAS;IAAG,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AAC5C,MAAM,WAAW,SAAS;IAAG,IAAI,EAAE,IAAI,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE;AACxD,MAAM,WAAW,YAAY;IAAG,IAAI,EAAE,IAAI,CAAA;CAAE;AAC5C,MAAM,WAAW,YAAY;IAAG,SAAS,EAAE,MAAM,CAAA;CAAE;AASnD,6EAA6E;AAC7E,eAAO,MAAM,KAAK,GAAI,OAAO,MAAM,KAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAGvE,CAAA;AAED,qEAAqE;AACrE,eAAO,MAAM,eAAe,GAAI,KAAK,MAAM,KAAG,MAA4B,CAAA;AAE1E,yEAAyE;AACzE,wBAAgB,OAAO,CAAE,KAAK,EAAE,QAAQ,CAAC,WAAW,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,SAAS,CAInH;AAohBD,mDAAmD;AACnD,wBAAgB,eAAe,IAAK,YAAY,CAc/C"}
|