p2party 0.14.2 → 0.14.7

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.
Files changed (126) hide show
  1. package/README.md +230 -30
  2. package/docs/getting-started.md +15 -0
  3. package/docs/protocol-v4-security.md +40 -0
  4. package/docs/references.md +28 -8
  5. package/docs/session-api.md +10 -2
  6. package/lib/api/signalingServerApi.d.ts +13 -2
  7. package/lib/api/webrtc/applyIceConfiguration.d.ts +9 -0
  8. package/lib/api/webrtc/dataChannelHandler.d.ts +10 -0
  9. package/lib/api/webrtc/deleteRoomData.d.ts +13 -0
  10. package/lib/api/webrtc/disconnectFromAllRoomsQuery.d.ts +2 -1
  11. package/lib/api/webrtc/disconnectFromRoomQuery.d.ts +2 -1
  12. package/lib/api/webrtc/disconnectQuery.d.ts +2 -1
  13. package/lib/api/webrtc/iceRepair.d.ts +3 -1
  14. package/lib/api/webrtc/index.d.ts +2 -1
  15. package/lib/api/webrtc/interfaces.d.ts +37 -0
  16. package/lib/api/webrtc/negotiationLock.d.ts +24 -0
  17. package/lib/api/webrtc/pendingOffer.d.ts +29 -0
  18. package/lib/api/webrtc/rebindDeadline.d.ts +61 -0
  19. package/lib/api/webrtc/remoteTransportChange.d.ts +142 -0
  20. package/lib/api/webrtc/retiredRemoteTransports.d.ts +70 -0
  21. package/lib/api/webrtc/roomEdgeBudget.d.ts +10 -0
  22. package/lib/api/webrtc/setDescriptionQuery.d.ts +8 -1
  23. package/lib/api/webrtc/settleOnClose.d.ts +36 -0
  24. package/lib/blindRendezvous/admissionInput.d.ts +11 -0
  25. package/lib/blindRendezvous/admissionPolicy.d.ts +217 -0
  26. package/lib/blindRendezvous/canonicalSchema.d.ts +139 -0
  27. package/lib/blindRendezvous/carrierEnvelope.d.ts +105 -0
  28. package/lib/blindRendezvous/coreReduce.d.ts +199 -0
  29. package/lib/blindRendezvous/derivations.d.ts +381 -0
  30. package/lib/blindRendezvous/identityHelloAdmission.d.ts +89 -0
  31. package/lib/blindRendezvous/identityHelloAdmissionPersistence.d.ts +133 -0
  32. package/lib/blindRendezvous/identityHelloHistoricalEvidence.d.ts +52 -0
  33. package/lib/blindRendezvous/identityHelloOpen.d.ts +167 -0
  34. package/lib/blindRendezvous/identityHelloTrial.d.ts +271 -0
  35. package/lib/blindRendezvous/localAdmissibleProject.d.ts +101 -0
  36. package/lib/blindRendezvous/localPresenceKeyBinding.d.ts +108 -0
  37. package/lib/blindRendezvous/localStableIdentityCustody.d.ts +46 -0
  38. package/lib/blindRendezvous/normativeKernel.d.ts +222 -0
  39. package/lib/blindRendezvous/operation.d.ts +137 -0
  40. package/lib/blindRendezvous/operationPayload.d.ts +134 -0
  41. package/lib/blindRendezvous/pairBootstrapSuite.d.ts +93 -0
  42. package/lib/blindRendezvous/pairCrypto.d.ts +122 -0
  43. package/lib/blindRendezvous/pairLedger.d.ts +154 -0
  44. package/lib/blindRendezvous/pairOpenBudget.d.ts +67 -0
  45. package/lib/blindRendezvous/pairOpenReservation.d.ts +157 -0
  46. package/lib/blindRendezvous/pairPlaintext.d.ts +240 -0
  47. package/lib/blindRendezvous/pairStepEnvelope.d.ts +60 -0
  48. package/lib/blindRendezvous/plannerState.d.ts +61 -0
  49. package/lib/blindRendezvous/projections.d.ts +71 -0
  50. package/lib/blindRendezvous/publicWindow.d.ts +330 -0
  51. package/lib/blindRendezvous/retainedOperationStore.d.ts +187 -0
  52. package/lib/blindRendezvous/roomInviteV2.d.ts +92 -0
  53. package/lib/blindRendezvous/roomPolicyV4.d.ts +90 -0
  54. package/lib/blindRendezvous/schemas.d.ts +221 -0
  55. package/lib/blindRendezvous/storeDescriptor.d.ts +160 -0
  56. package/lib/cryptography/aeadWasm.d.ts +18 -0
  57. package/lib/cryptography/byteInput.d.ts +12 -0
  58. package/lib/cryptography/carrierAead.d.ts +23 -0
  59. package/lib/cryptography/chacha20poly1305.d.ts +7 -0
  60. package/lib/cryptography/fips202.d.ts +10 -0
  61. package/lib/cryptography/hpke.d.ts +84 -0
  62. package/lib/cryptography/hpkeSuite.d.ts +39 -0
  63. package/lib/cryptography/hybridKem.d.ts +42 -0
  64. package/lib/cryptography/hybridKemSuite.d.ts +22 -0
  65. package/lib/cryptography/interfaces.d.ts +3 -0
  66. package/lib/cryptography/mlkem.d.ts +27 -1
  67. package/lib/cryptography/mnemonic.d.ts +65 -1
  68. package/lib/cryptography/ownedEd25519KeyMaterial.d.ts +27 -0
  69. package/lib/cryptography/webCryptoSha256.d.ts +20 -0
  70. package/lib/cryptography/x25519.d.ts +18 -0
  71. package/lib/cryptography/xchacha20poly1305.d.ts +7 -0
  72. package/lib/db/api.d.ts +6 -3
  73. package/lib/db/identityEd25519ClientBoundary.d.ts +13 -0
  74. package/lib/db/src/getDB.d.ts +2 -2
  75. package/lib/db/types.d.ts +52 -4
  76. package/lib/db.worker.js +1 -1
  77. package/lib/handlers/coverChannelRegistry.d.ts +22 -0
  78. package/lib/handlers/edgeTeardownFollowUp.d.ts +35 -0
  79. package/lib/handlers/handleChallenge.d.ts +2 -1
  80. package/lib/handlers/handleConnectToPeer.d.ts +1 -1
  81. package/lib/handlers/handleHandshake.d.ts +2 -6
  82. package/lib/handlers/handleSendMessage.d.ts +60 -7
  83. package/lib/handlers/handleWebSocketMessage.d.ts +1 -1
  84. package/lib/handlers/handshakeCore.d.ts +2 -7
  85. package/lib/handlers/handshakeFrame.d.ts +25 -0
  86. package/lib/handlers/ratchetGateWait.d.ts +13 -0
  87. package/lib/handlers/reconcile.d.ts +24 -0
  88. package/lib/handlers/requestRoom.d.ts +30 -0
  89. package/lib/handlers/roomResponse.d.ts +53 -0
  90. package/lib/index.d.ts +99 -12
  91. package/lib/index.js +1 -1
  92. package/lib/index.min.js +1 -1
  93. package/lib/index.mjs +1 -1
  94. package/lib/libcrypto.provenance.json +5 -5
  95. package/lib/libcrypto.wasm +0 -0
  96. package/lib/middleware/roomListenerMiddleware.d.ts +4 -1
  97. package/lib/reducers/commonSlice.d.ts +3 -2
  98. package/lib/reducers/keyPairSlice.d.ts +3 -6
  99. package/lib/reducers/roomSlice.d.ts +81 -5
  100. package/lib/reducers/signalingServerSlice.d.ts +3 -2
  101. package/lib/session.d.ts +6 -3
  102. package/lib/session.js +1 -1
  103. package/lib/session.mjs +1 -1
  104. package/lib/store.d.ts +4 -2
  105. package/lib/utils/constants.d.ts +12 -0
  106. package/lib/utils/correlationId.d.ts +4 -0
  107. package/lib/utils/identityRestore.d.ts +108 -0
  108. package/lib/utils/interfaces.d.ts +25 -6
  109. package/lib/utils/roomConnectAdmission.d.ts +15 -0
  110. package/lib/utils/roomLeaveCoordinator.d.ts +38 -0
  111. package/lib/utils/roomRequestCoordinator.d.ts +104 -0
  112. package/lib/utils/roomRosterReconciler.d.ts +83 -0
  113. package/lib/utils/sdpFingerprint.d.ts +6 -0
  114. package/lib/utils/signalingAttemptLifecycle.d.ts +33 -0
  115. package/lib/utils/signalingAuth.d.ts +21 -2
  116. package/lib/utils/signalingBounds.d.ts +6 -0
  117. package/lib/utils/signalingFrame.d.ts +21 -0
  118. package/lib/utils/signalingHeartbeatWatchdog.d.ts +45 -0
  119. package/lib/utils/signalingIngressQueue.d.ts +49 -0
  120. package/lib/utils/signalingPeerRequestDebouncer.d.ts +13 -0
  121. package/lib/utils/signalingRoomLifecycle.d.ts +7 -0
  122. package/lib/utils/signalingRoomOperationLifecycle.d.ts +14 -0
  123. package/lib/utils/signalingServerBoundary.d.ts +11 -0
  124. package/lib/utils/terminalSettlement.d.ts +53 -0
  125. package/lib/utils/transportIdentity.d.ts +5 -0
  126. package/package.json +1 -1
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Constants-only SSOT for the fixed pair-bootstrap HPKE suite.
3
+ *
4
+ * Keeping this separate from the executable HPKE adapter lets schemas and the
5
+ * blind-rendezvous suite registry consume the exact wire geometry without
6
+ * importing WASM-backed cryptographic code.
7
+ */
8
+ export declare const HPKE_MLKEM768_X25519_KEM_ID = 25722;
9
+ export declare const HPKE_HKDF_SHA256_KDF_ID = 1;
10
+ export declare const HPKE_CHACHA20POLY1305_AEAD_ID = 3;
11
+ export declare const HPKE_MODE_BASE = 0;
12
+ export declare const HPKE_MODE_PSK = 1;
13
+ export declare const HPKE_HASH_BYTES = 32;
14
+ export declare const HPKE_KEY_BYTES = 32;
15
+ export declare const HPKE_NONCE_BYTES = 12;
16
+ export declare const HPKE_TAG_BYTES = 16;
17
+ export declare const HPKE_PAIR_PSK_BYTES = 32;
18
+ export declare const HPKE_PAIR_PSK_ID_BYTES = 32;
19
+ export declare const HPKE_MAX_EXPORT_BYTES: number;
20
+ export declare const HPKE_MAX_APPLICATION_CONTEXT_BYTES = 65535;
21
+ export declare const HPKE_MLKEM768_X25519_SUITE: Readonly<{
22
+ readonly specification: Readonly<{
23
+ kem: "draft-ietf-hpke-pq-05";
24
+ kemKeyDerivation: "draft-ietf-hpke-hpke-03";
25
+ keySchedule: "RFC 9180";
26
+ }>;
27
+ readonly kemId: 25722;
28
+ readonly kdfId: 1;
29
+ readonly aeadId: 3;
30
+ readonly publicKeyBytes: 1216;
31
+ readonly secretKeyBytes: 32;
32
+ readonly encapsulatedKeyBytes: 1120;
33
+ readonly sharedSecretBytes: 32;
34
+ readonly keyBytes: 32;
35
+ readonly nonceBytes: 12;
36
+ readonly tagBytes: 16;
37
+ readonly pskBytes: 32;
38
+ readonly pskIdBytes: 32;
39
+ }>;
@@ -0,0 +1,42 @@
1
+ import { MLKEM768_X25519_SUITE } from "./hybridKemSuite";
2
+ import type { LibCrypto } from "./libcrypto";
3
+ import type { MlKemDecapsulation, MlKemEncapsulation, MlKemKeyPair } from "./mlkem";
4
+ export { MLKEM768_X25519_CIPHERTEXT_BYTES, MLKEM768_X25519_PUBLIC_KEY_BYTES, MLKEM768_X25519_RANDOM_BYTES, MLKEM768_X25519_SEED_BYTES, MLKEM768_X25519_SECRET_KEY_BYTES, MLKEM768_X25519_SHARED_SECRET_BYTES, MLKEM768_X25519_SUITE, } from "./hybridKemSuite";
5
+ export type MlKem768X25519KeyPair = MlKemKeyPair;
6
+ export type MlKem768X25519Encapsulation = MlKemEncapsulation;
7
+ export type MlKem768X25519Decapsulation = MlKemDecapsulation;
8
+ /**
9
+ * A correctly framed peer ciphertext is not a valid ciphertext for this
10
+ * hybrid KEM. Infrastructure and local-key failures use their original errors.
11
+ */
12
+ export declare class HybridKemInvalidCiphertextError extends Error {
13
+ readonly name = "HybridKemInvalidCiphertextError";
14
+ constructor();
15
+ }
16
+ /**
17
+ * A correctly framed hybrid encapsulation key failed FIPS 203's ML-KEM
18
+ * modulus check or X25519 low-order-point validation.
19
+ */
20
+ export declare class HybridKemInvalidPublicKeyError extends Error {
21
+ readonly name = "HybridKemInvalidPublicKeyError";
22
+ constructor();
23
+ }
24
+ /**
25
+ * Validate one suite-1 hybrid encapsulation key without performing a second
26
+ * ML-KEM encapsulation.
27
+ *
28
+ * FIPS 203 encodes two 12-bit ML-KEM coefficients in each three-byte group;
29
+ * every coefficient must be below q=3329. The final 32 ML-KEM bytes are rho
30
+ * and are unrestricted. X25519 validity is the library's ordinary
31
+ * all-zero-shared-secret rejection. Public inputs need no constant-time scan.
32
+ */
33
+ export declare const validateMlKem768X25519PublicKey: (publicKey: Uint8Array, module: LibCrypto) => void;
34
+ export interface MlKem768X25519Backend {
35
+ readonly suite: typeof MLKEM768_X25519_SUITE;
36
+ generateKeyPair(): Promise<MlKem768X25519KeyPair>;
37
+ deriveKeyPair(seed: Uint8Array): Promise<MlKem768X25519KeyPair>;
38
+ encapsulate(publicKey: Uint8Array): Promise<MlKem768X25519Encapsulation>;
39
+ encapsulateDeterministically(publicKey: Uint8Array, randomness: Uint8Array): Promise<MlKem768X25519Encapsulation>;
40
+ decapsulate(ciphertext: Uint8Array, secretKey: Uint8Array): Promise<MlKem768X25519Decapsulation>;
41
+ }
42
+ export declare const createMlKem768X25519Backend: (module: LibCrypto) => MlKem768X25519Backend;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Frozen wire geometry for the pair-bootstrap KEM.
3
+ *
4
+ * This constants-only module is the SSOT shared by the crypto implementation
5
+ * and blind-rendezvous schemas. Changing any value requires a new suite ID.
6
+ */
7
+ export declare const MLKEM768_X25519_SEED_BYTES = 32;
8
+ export declare const MLKEM768_X25519_PUBLIC_KEY_BYTES = 1216;
9
+ export declare const MLKEM768_X25519_SECRET_KEY_BYTES = 32;
10
+ export declare const MLKEM768_X25519_CIPHERTEXT_BYTES = 1120;
11
+ export declare const MLKEM768_X25519_SHARED_SECRET_BYTES = 32;
12
+ export declare const MLKEM768_X25519_RANDOM_BYTES = 64;
13
+ export declare const MLKEM768_X25519_SUITE: Readonly<{
14
+ readonly standardName: "MLKEM768-X25519";
15
+ readonly specification: "draft-irtf-cfrg-concrete-hybrid-kems-04";
16
+ readonly seedBytes: 32;
17
+ readonly publicKeyBytes: 1216;
18
+ readonly secretKeyBytes: 32;
19
+ readonly ciphertextBytes: 1120;
20
+ readonly sharedSecretBytes: 32;
21
+ readonly randomnessBytes: 64;
22
+ }>;
@@ -11,6 +11,9 @@ export declare const crypto_secretbox_NONCEBYTES: number;
11
11
  export declare const crypto_aead_chacha20poly1305_ietf_KEYBYTES: number;
12
12
  export declare const crypto_aead_chacha20poly1305_ietf_NPUBBYTES: number;
13
13
  export declare const crypto_aead_chacha20poly1305_ietf_ABYTES: number;
14
+ export declare const crypto_aead_xchacha20poly1305_ietf_KEYBYTES: number;
15
+ export declare const crypto_aead_xchacha20poly1305_ietf_NPUBBYTES: number;
16
+ export declare const crypto_aead_xchacha20poly1305_ietf_ABYTES: number;
14
17
  export declare const crypto_pwhash_argon2id_SALTBYTES: number;
15
18
  export declare const crypto_core_ristretto255_BYTES: number;
16
19
  export declare const crypto_core_ristretto255_HASHBYTES: number;
@@ -45,6 +45,15 @@ export declare const ML_KEM_SUITES: Readonly<{
45
45
  1024: Readonly<MlKemSuiteDescriptor<1024>>;
46
46
  }>;
47
47
  export declare const getMlKemSuite: <P extends MlKemParameterSet>(parameterSet: P) => Readonly<MlKemSuiteDescriptor<P>>;
48
+ /**
49
+ * FIPS 203 Section 7.2 modulus check for one encoded encapsulation key.
50
+ *
51
+ * Each three-byte group in the encoded polynomial vector contains two
52
+ * little-endian 12-bit coefficients, both of which must be below q=3329.
53
+ * The final 32-byte public seed is unrestricted. This pure check is shared by
54
+ * every composed KEM so canonical ML-KEM public-key encoding has one SSOT.
55
+ */
56
+ export declare const mlKemPublicKeyHasCanonicalEncoding: (publicKey: unknown, parameterSet: MlKemParameterSet) => boolean;
48
57
  type MlKemKeyPairFunction = (publicKey: number, secretKey: number, coins64: number) => number;
49
58
  type MlKemEncapsFunction = (ciphertext: number, sharedSecret: number, publicKey: number, coins32: number) => number;
50
59
  type MlKemDecapsFunction = (sharedSecret: number, ciphertext: number, secretKey: number) => number;
@@ -104,12 +113,29 @@ export interface MlKemBackend<P extends MlKemParameterSet = MlKemParameterSet> {
104
113
  encapsulate(publicKey: Uint8Array): Promise<MlKemEncapsulation>;
105
114
  decapsulate(ciphertext: Uint8Array, secretKey: Uint8Array): Promise<MlKemDecapsulation>;
106
115
  }
116
+ /**
117
+ * Real-WASM ML-KEM backend with the explicit deterministic inputs required by
118
+ * composed, version-pinned KEMs. The ordinary backend remains the narrower
119
+ * seam used by protocol state machines and test doubles.
120
+ */
121
+ export interface DeterministicMlKemBackend<P extends MlKemParameterSet = MlKemParameterSet> extends MlKemBackend<P> {
122
+ /**
123
+ * FIPS 203 KeyGen_internal with the caller-supplied 64-byte d || z seed.
124
+ * The seed is borrowed; this method snapshots but never wipes caller bytes.
125
+ */
126
+ deriveKeyPair(seed: Uint8Array): Promise<MlKemKeyPair>;
127
+ /**
128
+ * FIPS 203 Encaps_internal with caller-supplied 32-byte randomness.
129
+ * Inputs are borrowed; this method snapshots but never wipes caller bytes.
130
+ */
131
+ encapsulateDeterministically(publicKey: Uint8Array, randomness: Uint8Array): Promise<MlKemEncapsulation>;
132
+ }
107
133
  /** Compatibility aliases for the currently shipped ML-KEM-768 handshake. */
108
134
  export type MlKem768KeyPair = MlKemKeyPair;
109
135
  export type MlKem768Encapsulation = MlKemEncapsulation;
110
136
  export type MlKem768Decapsulation = MlKemDecapsulation;
111
137
  export type MlKem768Backend = MlKemBackend<768>;
112
- export declare const createMlKemBackend: <P extends MlKemParameterSet>(module: LibCrypto, suite: Readonly<MlKemSuiteDescriptor<P>>) => MlKemBackend<P>;
138
+ export declare const createMlKemBackend: <P extends MlKemParameterSet>(module: LibCrypto, suite: Readonly<MlKemSuiteDescriptor<P>>) => DeterministicMlKemBackend<P>;
113
139
  /**
114
140
  * Temporary compatibility factory for the protocol-v3 ML-KEM-768 wire suite.
115
141
  */
@@ -1,4 +1,41 @@
1
1
  import type { LibCrypto } from "./libcrypto";
2
+ /**
3
+ * The result of a mnemonic check, shaped for a form field: `reason` is a
4
+ * displayable sentence naming the first problem found, and is absent when the
5
+ * phrase is usable.
6
+ */
7
+ export interface MnemonicValidation {
8
+ ok: boolean;
9
+ reason?: string;
10
+ }
11
+ /**
12
+ * The canonical form of a recovery phrase, and part of the derivation
13
+ * contract: NFKD, then any run of whitespace collapsed to a single space,
14
+ * trimmed, lowercased.
15
+ *
16
+ * A phrase is transcribed by a human from paper, a password manager or a
17
+ * screenshot, so it arrives with a trailing newline, a double space, a soft
18
+ * wrap, or a capital first letter from a keyboard's autocapitalisation. All of
19
+ * those used to be rejected outright by the wordlist lookup. Normalising them
20
+ * away here means `" Adapt patrol "` and `"adapt patrol"` are the same
21
+ * phrase everywhere: for validation, and for the argon2id input that produces
22
+ * the seed. Every phrase that derived a key before this normalisation existed
23
+ * was already in canonical form, so no backup changes what it restores.
24
+ */
25
+ export declare const normalizeMnemonic: (mnemonic: string) => string;
26
+ /**
27
+ * Derive an argon2id seed from a passphrase.
28
+ *
29
+ * This is the low-level KDF: it applies NFKD only, because an arbitrary
30
+ * passphrase is not a mnemonic and must not be lowercased. Callers that hash a
31
+ * recovery phrase pass it through `normalizeMnemonic` first, as
32
+ * `keyPairFromMnemonic` does.
33
+ *
34
+ * @param mnemonic - Passphrase to stretch
35
+ * @param salt - Optional salt; a random one is generated when omitted
36
+ * @param module - Optional preloaded WASM module, otherwise one is loaded
37
+ * @returns The argon2id seed. The caller owns it and should wipe it.
38
+ */
2
39
  export declare const argon2: (mnemonic: string, salt?: Uint8Array, module?: LibCrypto) => Promise<Uint8Array>;
3
40
  /**
4
41
  * Generates a sequence of words chosen from a prespecified wordlist
@@ -15,6 +52,27 @@ export declare const argon2: (mnemonic: string, salt?: Uint8Array, module?: LibC
15
52
  export declare const generateMnemonic: (strength?: 128 | 160 | 192 | 224 | 256 | 288 | 320 | 352 | 384 | 416 | 448 | 480 | 512) => Promise<string>;
16
53
  export declare const mnemonicToEntropy: (mnemonic: string) => Promise<boolean>;
17
54
  export declare const validateMnemonic: (mnemonic: string) => Promise<boolean>;
55
+ /**
56
+ * Everything about a recovery phrase that can be checked without hashing:
57
+ * word count and membership of the wordlist. Synchronous, so a form can call
58
+ * it on every keystroke and tell the user which word they mistyped.
59
+ *
60
+ * The checksum is deliberately not checked here — SHA-512 is only available
61
+ * asynchronously through Web Crypto. Use `validateMnemonicPhrase` (or
62
+ * `validateMnemonic`) once the phrase is structurally complete.
63
+ *
64
+ * @param words - The phrase as typed; normalisation is applied for you
65
+ * @returns `{ ok }`, plus a displayable `reason` for the first problem found
66
+ */
67
+ export declare const validateMnemonicWords: (words: string) => MnemonicValidation;
68
+ /**
69
+ * The full check: `validateMnemonicWords` plus the checksum, reported in the
70
+ * same shape so a form can show one message wherever the phrase went wrong.
71
+ *
72
+ * @param words - The phrase as typed; normalisation is applied for you
73
+ * @returns `{ ok }`, plus a displayable `reason` when the phrase is unusable
74
+ */
75
+ export declare const validateMnemonicPhrase: (words: string) => Promise<MnemonicValidation>;
18
76
  /**
19
77
  * Generates an Ed25519 key pair from the provided mnemonic.
20
78
  * Optionally, you can strenthen the generation with a password.
@@ -22,8 +80,14 @@ export declare const validateMnemonic: (mnemonic: string) => Promise<boolean>;
22
80
  * The password is used as a salt for argon2id.
23
81
  * From the generated seed we extract the key pair.
24
82
  *
83
+ * The phrase is normalised first (see `normalizeMnemonic`), so how it was
84
+ * typed does not change the identity it restores. Nothing here is persisted:
85
+ * the seed, the salt and the encoded password are wiped before returning, and
86
+ * the phrase itself stays the caller's to forget.
87
+ *
25
88
  * @param mnemonic - Sequence of words from the predefined wordlist
26
89
  * @param password - Optional salt for the seed derivation
90
+ * @param module - Optional preloaded WASM module, otherwise one is loaded
27
91
  * @returns An Ed25519 key pair
28
92
  */
29
- export declare const keyPairFromMnemonic: (mnemonic: string, password?: string) => Promise<import("./interfaces").SignKeyPair>;
93
+ export declare const keyPairFromMnemonic: (mnemonic: string, password?: string, module?: LibCrypto) => Promise<import("./interfaces").SignKeyPair>;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Internal, owned Ed25519 secret-key capture shared by trusted local
3
+ * persistence and custody boundaries.
4
+ *
5
+ * This module deliberately exposes no process-local capability and no signing
6
+ * operation. Callers must keep the returned material behind their own trusted
7
+ * boundary and wipe it when that ownership ends.
8
+ */
9
+ import type { LibCrypto } from "./libcrypto";
10
+ export interface OwnedEd25519KeyMaterial {
11
+ readonly secretKey: Uint8Array;
12
+ readonly publicKey: Uint8Array;
13
+ }
14
+ export interface CaptureConsistentEd25519KeyMaterialOptions {
15
+ readonly module?: LibCrypto;
16
+ readonly secretKey: Uint8Array;
17
+ readonly inputLabel: string;
18
+ /** Optional synchronous validation after secret capture and before await. */
19
+ readonly validateBeforeDerivation?: () => void;
20
+ readonly rejectInconsistentSecretKey: () => never;
21
+ }
22
+ /**
23
+ * Own a 64-byte Ed25519 secret before the first await and verify its public
24
+ * suffix by deriving the key pair from its seed.
25
+ */
26
+ export declare const captureConsistentEd25519KeyMaterial: (options: CaptureConsistentEd25519KeyMaterialOptions) => Promise<OwnedEd25519KeyMaterial>;
27
+ export declare const wipeOwnedEd25519KeyMaterial: (material: OwnedEd25519KeyMaterial) => void;
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Shared WebCrypto SHA-256, HMAC-SHA-256, and RFC 5869 HKDF-SHA-256.
3
+ *
4
+ * Every public function snapshots caller-owned bytes synchronously. Callers may
5
+ * therefore mutate or transfer their buffers as soon as the function returns
6
+ * its promise without changing the in-flight operation.
7
+ */
8
+ /** SHA-256 over a synchronous snapshot of `input`. */
9
+ export declare const sha256: (input: Uint8Array) => Promise<Uint8Array>;
10
+ /** HMAC-SHA-256 over synchronous snapshots of `key` and `message`. */
11
+ export declare const hmacSha256: (key: Uint8Array, message: Uint8Array) => Promise<Uint8Array>;
12
+ /** RFC 5869 HKDF-Extract with SHA-256. */
13
+ export declare const hkdfSha256Extract: (salt: Uint8Array, ikm: Uint8Array) => Promise<Uint8Array>;
14
+ /**
15
+ * RFC 5869 HKDF-Expand with SHA-256.
16
+ *
17
+ * This API requires a standards-conforming PRK of at least 32 bytes and a
18
+ * nonempty output no longer than RFC 5869's 255-block upper bound.
19
+ */
20
+ export declare const hkdfSha256Expand: (prk: Uint8Array, info: Uint8Array, length: number) => Promise<Uint8Array>;
@@ -3,6 +3,18 @@ export interface X25519KeyPair {
3
3
  publicKey: Uint8Array;
4
4
  secretKey: Uint8Array;
5
5
  }
6
+ /**
7
+ * The peer-supplied u-coordinate produced the prohibited all-zero X25519
8
+ * shared secret (for example, a low-order point).
9
+ *
10
+ * This is distinct from allocation/module failures so protocol receivers can
11
+ * classify attacker-controlled invalid KEM input as a closed no-match without
12
+ * hiding cryptographic infrastructure faults.
13
+ */
14
+ export declare class X25519RejectedPublicPointError extends Error {
15
+ readonly name = "X25519RejectedPublicPointError";
16
+ constructor();
17
+ }
6
18
  export declare const x25519Keypair: (module: LibCrypto) => X25519KeyPair;
7
19
  /**
8
20
  * Async, optional-module wrapper over `x25519Keypair`, mirroring `ed25519.newKeyPair`:
@@ -13,3 +25,9 @@ export declare const x25519Keypair: (module: LibCrypto) => X25519KeyPair;
13
25
  */
14
26
  export declare const newX25519KeyPair: (module?: LibCrypto) => Promise<X25519KeyPair>;
15
27
  export declare const x25519Dh: (secretKey: Uint8Array, publicKey: Uint8Array, module: LibCrypto) => Uint8Array;
28
+ /**
29
+ * Derive an X25519 public key by scalar-multiplying the RFC 7748 u=9 base
30
+ * point. The canonical base point stays module-owned so callers cannot mutate
31
+ * protocol input shared by later derivations.
32
+ */
33
+ export declare const x25519PublicFromSecret: (secretKey: Uint8Array, module: LibCrypto) => Uint8Array;
@@ -0,0 +1,7 @@
1
+ import type { LibCrypto } from "./libcrypto";
2
+ export declare const XCHACHA20POLY1305_MAX_WASM_BYTES = 2147483647;
3
+ export declare const XCHACHA20POLY1305_MAX_PLAINTEXT_BYTES: number;
4
+ /** Seal to XChaCha20-Poly1305 `ciphertext || 16-byte tag`. */
5
+ export declare const xchacha20Poly1305Seal: (module: LibCrypto, key: Uint8Array, nonce: Uint8Array, plaintext: Uint8Array, associatedData: Uint8Array) => Uint8Array;
6
+ /** Open `ciphertext || tag`, returning null on authentication failure. */
7
+ export declare const xchacha20Poly1305Open: (module: LibCrypto, key: Uint8Array, nonce: Uint8Array, ciphertextAndTag: Uint8Array, associatedData: Uint8Array) => Uint8Array | null;
package/lib/db/api.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Chunk, ReceiveChunk, NewChunk, NewChunkSelector, SendQueue, RatchetSession, IdentityEd25519, IdentityX25519 } from "./types";
1
+ import type { Chunk, ReceiveChunk, NewChunk, NewChunkSelector, SendQueue, RatchetSession, IdentityDerivation, IdentityEd25519KeyMaterial, IdentityX25519 } from "./types";
2
2
  export declare const getDBAddressBookEntry: (peerId?: string, peerPublicKey?: string) => Promise<import("./types").UsernamedPeer | undefined>;
3
3
  export declare const getAllDBAddressBookEntries: () => Promise<import("./types").UsernamedPeer[]>;
4
4
  export declare const setDBAddressBookEntry: (username: string, peerId: string, peerPublicKey: string) => Promise<undefined>;
@@ -62,6 +62,9 @@ export declare const deletePinAttemptState: (roomId: string, peerIdentityEd25519
62
62
  export declare const getIdentityX25519: () => Promise<IdentityX25519 | undefined>;
63
63
  export declare const setIdentityX25519: (identity: IdentityX25519) => Promise<undefined>;
64
64
  export declare const deleteIdentityX25519: () => Promise<undefined>;
65
- export declare const getIdentityEd25519: () => Promise<IdentityEd25519 | undefined>;
66
- export declare const setIdentityEd25519: (identity: IdentityEd25519) => Promise<undefined>;
65
+ export declare const getIdentityEd25519: () => Promise<import("./types").IdentityEd25519 | undefined>;
66
+ export declare const setIdentityEd25519: (identity: IdentityEd25519KeyMaterial) => Promise<bigint>;
67
67
  export declare const deleteIdentityEd25519: () => Promise<undefined>;
68
+ export declare const getIdentityDerivation: () => Promise<IdentityDerivation | null>;
69
+ export declare const setIdentityDerivation: (derivation: IdentityDerivation) => Promise<undefined>;
70
+ export declare const deleteIdentityDerivation: () => Promise<undefined>;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Main-realm ownership boundary for the persisted Ed25519 identity.
3
+ *
4
+ * The database worker only wraps bytes and allocates revisions. Seed
5
+ * derivation stays here so it uses the application's one configured
6
+ * cryptography/WASM source.
7
+ */
8
+ import type { IdentityEd25519, IdentityEd25519KeyMaterial } from "./types";
9
+ type IdentityWriter = (identity: IdentityEd25519KeyMaterial, transfer: Transferable[]) => Promise<unknown> | unknown;
10
+ export declare const wipeUnclaimedWorkerSecret: (value: unknown) => void;
11
+ export declare const readIdentityEd25519AtClientBoundary: (read: () => Promise<unknown>) => Promise<IdentityEd25519 | undefined>;
12
+ export declare const writeIdentityEd25519AtClientBoundary: (identity: IdentityEd25519KeyMaterial, write: IdentityWriter) => Promise<bigint>;
13
+ export {};
@@ -1,5 +1,5 @@
1
1
  import type { DBSchema, IDBPDatabase } from "idb";
2
- import type { MessageData, Chunk, SendQueue, AddressBook, BlacklistedPeer, UniqueRoom, NewChunk, RatchetSession, StoredIdentityX25519, StoredIdentityEd25519, PinAttemptState } from "../types";
2
+ import type { MessageData, Chunk, SendQueue, AddressBook, BlacklistedPeer, UniqueRoom, NewChunk, RatchetSession, StoredIdentityX25519, StoredIdentityEd25519, StoredIdentityEd25519Revision, StoredIdentityDerivation, PinAttemptState } from "../types";
3
3
  export declare const dbName = "p2party";
4
4
  export declare const dbVersion = 19;
5
5
  export interface RepoSchema extends DBSchema {
@@ -74,7 +74,7 @@ export interface RepoSchema extends DBSchema {
74
74
  };
75
75
  };
76
76
  meta: {
77
- value: CryptoKey | StoredIdentityX25519 | StoredIdentityEd25519 | PinAttemptState;
77
+ value: CryptoKey | StoredIdentityX25519 | StoredIdentityEd25519 | StoredIdentityEd25519Revision | StoredIdentityDerivation | PinAttemptState;
78
78
  key: string;
79
79
  };
80
80
  }
package/lib/db/types.d.ts CHANGED
@@ -167,15 +167,48 @@ export interface StoredIdentityX25519 {
167
167
  wrappedSecret: ArrayBuffer;
168
168
  crossSig: ArrayBuffer;
169
169
  }
170
- /** Ed25519 account identity at the worker API boundary. */
171
- export interface IdentityEd25519 {
170
+ /** Ed25519 account key material accepted by the worker write boundary. */
171
+ export interface IdentityEd25519KeyMaterial {
172
172
  pub: ArrayBuffer;
173
173
  secret: ArrayBuffer;
174
174
  }
175
+ /** Ed25519 account identity returned by the worker read boundary. */
176
+ export interface IdentityEd25519 extends IdentityEd25519KeyMaterial {
177
+ /** Persistent, non-reused uint64 revision allocated by IndexedDB. */
178
+ recordRevision: bigint;
179
+ }
175
180
  /** At-rest Ed25519 record (meta key "identityEd25519"). */
176
181
  export interface StoredIdentityEd25519 {
182
+ version: 1;
177
183
  pub: ArrayBuffer;
178
184
  wrappedSecret: ArrayBuffer;
185
+ recordRevision: bigint;
186
+ }
187
+ /** Persistent Ed25519 revision high-water/tombstone record in the meta store. */
188
+ export interface StoredIdentityEd25519Revision {
189
+ version: 1;
190
+ lastRevision: bigint;
191
+ }
192
+ /**
193
+ * How the current Ed25519 account identity came into being. "mnemonic" means it
194
+ * was derived from a recovery phrase and can therefore be reproduced from one;
195
+ * "random" means it was generated from a random seed and is unrecoverable.
196
+ * Non-secret: it says nothing about the phrase or the key, only about whether a
197
+ * backup is possible at all.
198
+ */
199
+ export type IdentityDerivation = "random" | "mnemonic";
200
+ /** At-rest derivation record (meta key "identityDerivation"). */
201
+ export interface StoredIdentityDerivation {
202
+ version: 1;
203
+ derivation: IdentityDerivation;
204
+ /**
205
+ * The Ed25519 public key this claim describes, when one was stored at the
206
+ * time it was recorded. A flag whose binding no longer matches the stored
207
+ * account key is reported as unknown rather than carried over: claiming
208
+ * recoverability for a key that was never derived from a phrase would hand
209
+ * the user a backup that restores someone else's identity.
210
+ */
211
+ boundPub: ArrayBuffer | null;
179
212
  }
180
213
  /** Non-secret online PIN-guess throttle state for one room/peer-identity edge. */
181
214
  export interface PinAttemptState {
@@ -410,11 +443,23 @@ export type WorkerMessages = {
410
443
  } | {
411
444
  id: number;
412
445
  method: "setIdentityEd25519";
413
- args: [identity: IdentityEd25519];
446
+ args: [identity: IdentityEd25519KeyMaterial];
414
447
  } | {
415
448
  id: number;
416
449
  method: "deleteIdentityEd25519";
417
450
  args: [];
451
+ } | {
452
+ id: number;
453
+ method: "getIdentityDerivation";
454
+ args: [];
455
+ } | {
456
+ id: number;
457
+ method: "setIdentityDerivation";
458
+ args: [derivation: IdentityDerivation];
459
+ } | {
460
+ id: number;
461
+ method: "deleteIdentityDerivation";
462
+ args: [];
418
463
  } | {
419
464
  id: number;
420
465
  method: "deleteDB";
@@ -470,7 +515,10 @@ export interface WorkerMethodReturnTypes {
470
515
  setIdentityX25519: undefined;
471
516
  deleteIdentityX25519: undefined;
472
517
  getIdentityEd25519: IdentityEd25519 | undefined;
473
- setIdentityEd25519: undefined;
518
+ setIdentityEd25519: bigint;
474
519
  deleteIdentityEd25519: undefined;
520
+ getIdentityDerivation: IdentityDerivation | null;
521
+ setIdentityDerivation: undefined;
522
+ deleteIdentityDerivation: undefined;
475
523
  deleteDB: undefined;
476
524
  }