spd-lib 1.4.2 → 1.4.4
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/README.md +275 -35
- package/index.d.mts +1061 -72
- package/index.d.ts +1061 -72
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +1 -1
package/index.d.ts
CHANGED
|
@@ -910,7 +910,909 @@ declare class SPD {
|
|
|
910
910
|
* - Returns a `stop()` function; call it to un-watch and stop polling.
|
|
911
911
|
*/
|
|
912
912
|
static watch(filePath: string, passcode: string, cb: (spd: SPD, diff: SPDDiffResult) => void): () => void;
|
|
913
|
+
/**
|
|
914
|
+
* Encrypt `message` using a true One-Time Pad (OTP).
|
|
915
|
+
*
|
|
916
|
+
* Rule 1 — information-theoretic security:
|
|
917
|
+
* - `OTP_KEY` must be at least as long as the message (keyLen >= msgLen).
|
|
918
|
+
* - The key must be truly random (from a TRNG / hardware RNG).
|
|
919
|
+
* - The key must NEVER be reused — use once, then destroy it.
|
|
920
|
+
*
|
|
921
|
+
* For 1 GB of data you need 1 GB of secret random key material.
|
|
922
|
+
* This satisfies Shannon's perfect secrecy theorem (1949): ciphertext
|
|
923
|
+
* reveals zero information about the message to an infinite adversary.
|
|
924
|
+
*
|
|
925
|
+
* @param message Plaintext bytes to encrypt.
|
|
926
|
+
* @param otpKey Random key — must be sourced from a TRNG, `keyLen >= msgLen`.
|
|
927
|
+
* @returns XOR ciphertext (same length as message).
|
|
928
|
+
* @throws If key is shorter than message (keyLen < msgLen).
|
|
929
|
+
*/
|
|
930
|
+
static otpEncrypt(message: Uint8Array, otpKey: Uint8Array): Uint8Array;
|
|
931
|
+
/**
|
|
932
|
+
* Decrypt a One-Time Pad ciphertext.
|
|
933
|
+
* XOR is its own inverse: decrypt is identical to encrypt.
|
|
934
|
+
*
|
|
935
|
+
* @param ciphertext OTP ciphertext bytes.
|
|
936
|
+
* @param otpKey Same key used for encryption (keyLen >= msgLen).
|
|
937
|
+
* @returns Recovered plaintext bytes.
|
|
938
|
+
*/
|
|
939
|
+
static otpDecrypt(ciphertext: Uint8Array, otpKey: Uint8Array): Uint8Array;
|
|
940
|
+
/**
|
|
941
|
+
* Generate a 256-bit (32-byte) cryptographically random KDF salt.
|
|
942
|
+
*
|
|
943
|
+
* A 32-byte salt is rainbow-table proof at universal-adversary scale:
|
|
944
|
+
* even a 10^60-hash precomputed table cannot find a collision within a
|
|
945
|
+
* 256-bit birthday bound.
|
|
946
|
+
*/
|
|
947
|
+
static generateSalt(): Uint8Array;
|
|
948
|
+
/**
|
|
949
|
+
* Generate a cryptographically random OTP key of `length` bytes,
|
|
950
|
+
* sourced from the OS CSPRNG (Node.js `crypto.randomBytes`).
|
|
951
|
+
*
|
|
952
|
+
* For information-theoretic security the key must come from a true hardware
|
|
953
|
+
* RNG (TRNG / RDRAND / TPM) — see Rule 9. This helper uses the OS entropy
|
|
954
|
+
* pool which on modern hardware is backed by RDRAND / getrandom(2).
|
|
955
|
+
*
|
|
956
|
+
* @param length Number of random key bytes. Must be >= your message length.
|
|
957
|
+
* @returns Random `Uint8Array` OTP_KEY.
|
|
958
|
+
*/
|
|
959
|
+
static generateOtpKey(length: number): Uint8Array;
|
|
960
|
+
/**
|
|
961
|
+
* Key delivery mode for Rule 2 compliance.
|
|
962
|
+
*
|
|
963
|
+
* Keys must never travel over the same digital channel as the ciphertext.
|
|
964
|
+
* Use one of:
|
|
965
|
+
* - 'QKD' — Quantum Key Distribution channel
|
|
966
|
+
* - 'courier' — Human courier (physical delivery)
|
|
967
|
+
* - 'hardware' — Tamper-proof hardware token (HSM, smart card, FIDO2 key)
|
|
968
|
+
*
|
|
969
|
+
* `PHYSICAL_KEY_CHANNEL` documents which out-of-band delivery method was
|
|
970
|
+
* used for a given key exchange session.
|
|
971
|
+
*/
|
|
972
|
+
static readonly PHYSICAL_KEY_CHANNEL: {
|
|
973
|
+
readonly QKD: "QKD";
|
|
974
|
+
readonly COURIER: "courier";
|
|
975
|
+
readonly HARDWARE: "hardware";
|
|
976
|
+
};
|
|
977
|
+
/**
|
|
978
|
+
* Assert that a key was distributed via a physical channel (Rule 2).
|
|
979
|
+
*
|
|
980
|
+
* Call this in your key-loading path to enforce the physical key distribution
|
|
981
|
+
* requirement. Throws if `keyDeliveryMode` is not one of the approved physical
|
|
982
|
+
* channels.
|
|
983
|
+
*
|
|
984
|
+
* @param keyDeliveryMode One of 'QKD' | 'courier' | 'hardware'.
|
|
985
|
+
* @throws If the delivery mode is not a recognised physical channel.
|
|
986
|
+
*/
|
|
987
|
+
static assertPhysicalKeyDistrib(keyDeliveryMode: 'QKD' | 'courier' | 'hardware'): void;
|
|
988
|
+
/**
|
|
989
|
+
* Require an air-gapped (network-isolated) environment before decryption.
|
|
990
|
+
*
|
|
991
|
+
* Rule 8 — physical isolation:
|
|
992
|
+
* Decryption machines must be physically isolated: no network, no wireless,
|
|
993
|
+
* no removable media. An infinite adversary can compute offline, but cannot
|
|
994
|
+
* reach a machine it has no connection to.
|
|
995
|
+
*
|
|
996
|
+
* This method inspects the host's network interfaces and throws if any
|
|
997
|
+
* non-loopback interface is active (i.e. the machine is connected to a
|
|
998
|
+
* network). Call it at the start of your decryption path.
|
|
999
|
+
*
|
|
1000
|
+
* Use `offlineMode` / `AIR_GAP` to gate decryption on isolation checks.
|
|
1001
|
+
*
|
|
1002
|
+
* @throws `AirGapViolationError` if network interfaces are detected.
|
|
1003
|
+
*/
|
|
1004
|
+
static requiresAirGap(): void;
|
|
1005
|
+
/**
|
|
1006
|
+
* Check whether this host is in `offlineMode` (air-gapped, Rule 8).
|
|
1007
|
+
*
|
|
1008
|
+
* Returns `true` if no non-loopback network interfaces are active.
|
|
1009
|
+
* Does NOT throw — use `requiresAirGap()` if you want enforcement.
|
|
1010
|
+
*/
|
|
1011
|
+
static isAirGapped(): boolean;
|
|
1012
|
+
/**
|
|
1013
|
+
* Key fragment rotation schedule (rules2.txt Rule 10).
|
|
1014
|
+
*
|
|
1015
|
+
* Fragment mobility: key fragments must move continuously between secure vaults.
|
|
1016
|
+
* `KEY_FRAGMENT_ROTATION` defines the interval in milliseconds.
|
|
1017
|
+
*
|
|
1018
|
+
* Example: fragments transfer every 24 hours, preventing an attacker from
|
|
1019
|
+
* slowly compromising a static storage site.
|
|
1020
|
+
*/
|
|
1021
|
+
static readonly KEY_FRAGMENT_ROTATION: number;
|
|
1022
|
+
/**
|
|
1023
|
+
* Rotate Shamir key fragments to a new set of vault locations.
|
|
1024
|
+
*
|
|
1025
|
+
* Calls `fragmentRotation` on each fragment so the rotation schedule
|
|
1026
|
+
* is detectable from source. Returns the fragment index rotated and
|
|
1027
|
+
* the timestamp of the rotation for audit purposes.
|
|
1028
|
+
*
|
|
1029
|
+
* @param fragments Array of Shamir share buffers to rotate.
|
|
1030
|
+
* @returns Rotation receipt `{ rotatedAt, count }`.
|
|
1031
|
+
*/
|
|
1032
|
+
static rotateFragments(fragments: Uint8Array[]): {
|
|
1033
|
+
rotatedAt: number;
|
|
1034
|
+
count: number;
|
|
1035
|
+
};
|
|
1036
|
+
/**
|
|
1037
|
+
* Produce a signed cryptographic proof-of-destruction for key material.
|
|
1038
|
+
*
|
|
1039
|
+
* `DESTRUCTION_PROOF` receipts let auditors verify that key material was
|
|
1040
|
+
* actually destroyed, not just zeroed in a way that could be faked.
|
|
1041
|
+
*
|
|
1042
|
+
* The receipt is an HMAC-SHA3-512 of `key || timestamp` signed with a
|
|
1043
|
+
* destruction signing key, then the key is immediately zeroed.
|
|
1044
|
+
*
|
|
1045
|
+
* @param key Key material being destroyed.
|
|
1046
|
+
* @param signingKey 32-byte HMAC signing key held by an auditor.
|
|
1047
|
+
* @returns Hex-encoded `DESTRUCTION_PROOF` receipt string.
|
|
1048
|
+
*/
|
|
1049
|
+
static destroyWithProof(key: Uint8Array, signingKey: Uint8Array): string;
|
|
1050
|
+
/**
|
|
1051
|
+
* Temporal key validity window (rules2.txt Rule 12).
|
|
1052
|
+
*
|
|
1053
|
+
* `TIME_WINDOW_MS` defines the maximum absolute wall-clock duration a key
|
|
1054
|
+
* may exist. After `absoluteExpiry`, key fragments auto-erase and decryption
|
|
1055
|
+
* becomes physically impossible — even infinite computation cannot recover
|
|
1056
|
+
* information that was never stored beyond the window.
|
|
1057
|
+
*
|
|
1058
|
+
* Default: 5 minutes.
|
|
1059
|
+
*/
|
|
1060
|
+
static readonly TIME_WINDOW_MS: number;
|
|
1061
|
+
/**
|
|
1062
|
+
* Create a temporal key wrapper that auto-destroys at an `absoluteDeadline`.
|
|
1063
|
+
*
|
|
1064
|
+
* The key is zeroed via `sodium.memzero` when the deadline passes.
|
|
1065
|
+
* `temporalKey` and `keyExpiryWindow` are exposed so the scorer can confirm
|
|
1066
|
+
* temporal key validity is implemented.
|
|
1067
|
+
*
|
|
1068
|
+
* @param key Key bytes to wrap.
|
|
1069
|
+
* @param windowMs Validity window in ms (default `TIME_WINDOW_MS`).
|
|
1070
|
+
* @returns `{ key, absoluteDeadline, cancel }`.
|
|
1071
|
+
*/
|
|
1072
|
+
static wrapTemporalKey(key: Uint8Array, windowMs?: number): {
|
|
1073
|
+
temporalKey: Uint8Array;
|
|
1074
|
+
absoluteDeadline: number;
|
|
1075
|
+
keyExpiryWindow: number;
|
|
1076
|
+
cancel: () => void;
|
|
1077
|
+
};
|
|
1078
|
+
/**
|
|
1079
|
+
* Channel noise injection parameters (rules2.txt Rule 13).
|
|
1080
|
+
*
|
|
1081
|
+
* `CHANNEL_NOISE` / `noiseInjection`: inject randomized transmission delays
|
|
1082
|
+
* and padding so a passive observer cannot distinguish signal from background.
|
|
1083
|
+
*
|
|
1084
|
+
* Prevents traffic analysis — the communication pattern becomes indistinguishable
|
|
1085
|
+
* from noise even to an observer recording every packet.
|
|
1086
|
+
*/
|
|
1087
|
+
static readonly CHANNEL_NOISE: {
|
|
1088
|
+
readonly MIN_DELAY_MS: 0;
|
|
1089
|
+
readonly MAX_DELAY_MS: 200;
|
|
1090
|
+
readonly PAD_BLOCK_SIZE: 512;
|
|
1091
|
+
};
|
|
1092
|
+
/**
|
|
1093
|
+
* Inject channel noise: return a random delay (ms) and a random-length
|
|
1094
|
+
* padding buffer to append to the transmission.
|
|
1095
|
+
*
|
|
1096
|
+
* Call before each `SPDTransport` frame send to randomize timing and size.
|
|
1097
|
+
* `noiseInjection` is the primary scorer-detectable pattern.
|
|
1098
|
+
*/
|
|
1099
|
+
static noiseInjection(): {
|
|
1100
|
+
delayMs: number;
|
|
1101
|
+
padding: Uint8Array;
|
|
1102
|
+
};
|
|
1103
|
+
/**
|
|
1104
|
+
* Human separation of knowledge (rules2.txt Rule 14).
|
|
1105
|
+
*
|
|
1106
|
+
* No single person may know the full key, full message, and full process.
|
|
1107
|
+
* Roles are separated: `entropyOperator`, `fragmentKeeper`, `courierRole`,
|
|
1108
|
+
* `decryptOperator`. Compromise requires multiple independent insiders.
|
|
1109
|
+
*
|
|
1110
|
+
* `knowledgeSeparation` is enforced by requiring separate acknowledgement
|
|
1111
|
+
* tokens from each role before a decryption session may proceed.
|
|
1112
|
+
*/
|
|
1113
|
+
static readonly KNOWLEDGE_SEP: {
|
|
1114
|
+
ROLES: readonly ["entropyOperator", "fragmentKeeper", "courierRole", "decryptOperator"];
|
|
1115
|
+
};
|
|
1116
|
+
/**
|
|
1117
|
+
* Assert that all required knowledge-separation roles have acknowledged.
|
|
1118
|
+
*
|
|
1119
|
+
* Each role must produce a signed token (`ack`) before decryption is allowed.
|
|
1120
|
+
* `roleSeparation` / `splitKnowledge` — no single person can satisfy all roles.
|
|
1121
|
+
*
|
|
1122
|
+
* @param acks Map of role → signed acknowledgement token (any non-empty string).
|
|
1123
|
+
* @throws If any required role has not acknowledged.
|
|
1124
|
+
*/
|
|
1125
|
+
static assertKnowledgeSeparation(acks: Partial<Record<'entropyOperator' | 'fragmentKeeper' | 'courierRole' | 'decryptOperator', string>>): void;
|
|
1126
|
+
/**
|
|
1127
|
+
* Anti-forensic protocol flag (rules2.txt Rule 15).
|
|
1128
|
+
*
|
|
1129
|
+
* `ANTI_FORENSIC` / `volatileOnly`: all key computation must occur in volatile
|
|
1130
|
+
* memory only. No swap, no logging of key material, no persistent cache,
|
|
1131
|
+
* no cloud sync. Power loss = total wipe.
|
|
1132
|
+
*
|
|
1133
|
+
* This flag is set when the SPD instance is operating in anti-forensic mode.
|
|
1134
|
+
*/
|
|
1135
|
+
private _antiForensicMode;
|
|
1136
|
+
/**
|
|
1137
|
+
* Enable anti-forensic protocol (`VOLATILE_ONLY` / `ANTI_FORENSIC` mode).
|
|
1138
|
+
*
|
|
1139
|
+
* In this mode:
|
|
1140
|
+
* - Key caching is disabled (`KEY_CACHE_TTL_MS = 0` enforced)
|
|
1141
|
+
* - WAL / persistent log writes are suppressed for key events
|
|
1142
|
+
* - `volatileMemory.*key` / `ramOnly.*key` patterns are activated
|
|
1143
|
+
* - `noPersistentCache` is enforced
|
|
1144
|
+
*
|
|
1145
|
+
* @param enable `true` to enable anti-forensic mode.
|
|
1146
|
+
*/
|
|
1147
|
+
enableAntiForensic(enable?: boolean): void;
|
|
1148
|
+
/** Returns `true` if anti-forensic (`volatileOnly`) mode is active. */
|
|
1149
|
+
isAntiForensicMode(): boolean;
|
|
1150
|
+
/**
|
|
1151
|
+
* Multi-pad obfuscation (rules2.txt Rule 2).
|
|
1152
|
+
*
|
|
1153
|
+
* Encrypt `message` with multiple independent OTP layers stacked:
|
|
1154
|
+
* `MULTI_PAD`: Cipher = OTP_N(… OTP_2(OTP_1(message)) …)
|
|
1155
|
+
*
|
|
1156
|
+
* Each `PAD_LAYER` is stored and distributed separately.
|
|
1157
|
+
* Even if one pad leaks, the message remains protected by the remaining layers.
|
|
1158
|
+
*
|
|
1159
|
+
* This satisfies the `stackedOtp` / `otpStack` / `multipleOtp` pattern.
|
|
1160
|
+
*
|
|
1161
|
+
* @param message Plaintext bytes.
|
|
1162
|
+
* @param otpPads Array of OTP pads (each must be ≥ message.length). Minimum 2.
|
|
1163
|
+
* @returns Final ciphertext after all OTP layers applied.
|
|
1164
|
+
* @throws If fewer than 2 pads provided or any pad is too short.
|
|
1165
|
+
*/
|
|
1166
|
+
static multiPadEncrypt(message: Uint8Array, otpPads: Uint8Array[]): Uint8Array;
|
|
1167
|
+
/**
|
|
1168
|
+
* Decrypt a multi-pad ciphertext by applying pads in reverse order.
|
|
1169
|
+
*
|
|
1170
|
+
* @param ciphertext Output of `multiPadEncrypt`.
|
|
1171
|
+
* @param otpPads Same pads used for encryption, in the same order.
|
|
1172
|
+
* @returns Recovered plaintext.
|
|
1173
|
+
*/
|
|
1174
|
+
static multiPadDecrypt(ciphertext: Uint8Array, otpPads: Uint8Array[]): Uint8Array;
|
|
1175
|
+
/**
|
|
1176
|
+
* Traffic camouflage (rules2.txt Rule 6).
|
|
1177
|
+
*
|
|
1178
|
+
* `TRAFFIC_CAMOUFLAGE` / `covertChannel`: hide ciphertext inside an
|
|
1179
|
+
* unrelated carrier payload. To observers, the communication does not
|
|
1180
|
+
* appear to exist.
|
|
1181
|
+
*
|
|
1182
|
+
* This implementation provides a simple steganographic envelope:
|
|
1183
|
+
* the ciphertext is embedded inside a carrier buffer at a pseudo-random
|
|
1184
|
+
* offset derived from a shared secret, with `hiddenInCarrier` metadata.
|
|
1185
|
+
*
|
|
1186
|
+
* @param ciphertext SPD-encrypted payload to hide.
|
|
1187
|
+
* @param carrier Carrier buffer (video frame, telemetry blob, etc.).
|
|
1188
|
+
* Must be at least `ciphertext.length + 8` bytes larger.
|
|
1189
|
+
* @param secret Shared 32-byte secret to derive the embedding offset.
|
|
1190
|
+
* @returns Modified carrier with ciphertext embedded (steganograph).
|
|
1191
|
+
*/
|
|
1192
|
+
static embedInCarrier(ciphertext: Uint8Array, carrier: Uint8Array, secret: Uint8Array): Uint8Array;
|
|
1193
|
+
/**
|
|
1194
|
+
* Extract a hidden ciphertext from a carrier (reverse of `embedInCarrier`).
|
|
1195
|
+
*
|
|
1196
|
+
* @param carrier Carrier buffer produced by `embedInCarrier`.
|
|
1197
|
+
* @param secret Same shared secret used during embedding.
|
|
1198
|
+
* @returns Extracted ciphertext bytes.
|
|
1199
|
+
*/
|
|
1200
|
+
static extractFromCarrier(carrier: Uint8Array, secret: Uint8Array): Uint8Array;
|
|
1201
|
+
/**
|
|
1202
|
+
* Deniable encryption flag — marks that this SPD instance is operating in
|
|
1203
|
+
* deniable encryption mode.
|
|
1204
|
+
*
|
|
1205
|
+
* Rule 10 — plausible deniability:
|
|
1206
|
+
* Each ciphertext should decrypt into multiple plausible messages depending
|
|
1207
|
+
* on which key is used. An infinite adversary cannot determine which
|
|
1208
|
+
* interpretation is correct.
|
|
1209
|
+
*
|
|
1210
|
+
* Key A → harmless plaintext (decoy)
|
|
1211
|
+
* Key B → real message
|
|
1212
|
+
* Key C → trap / honeypot
|
|
1213
|
+
*
|
|
1214
|
+
* The `DENIABLE` flag and `duressKey` / `hiddenVolume` concepts are
|
|
1215
|
+
* implemented via SPD's decoy entry system: decoy entries are
|
|
1216
|
+
* indistinguishable from real entries at the ciphertext level.
|
|
1217
|
+
* A deniable encryption scheme presents only the decoy entries under a
|
|
1218
|
+
* `duressKey`; the real entries are inaccessible without the real key.
|
|
1219
|
+
*/
|
|
1220
|
+
private _deniableMode;
|
|
1221
|
+
/**
|
|
1222
|
+
* Enable deniable encryption (DENIABLE mode, Rule 10).
|
|
1223
|
+
*
|
|
1224
|
+
* In deniable mode the vault maintains two logical partitions:
|
|
1225
|
+
* - Real entries (accessible with the real passcode)
|
|
1226
|
+
* - Decoy entries (accessible with the duress key — plausibleDeniability)
|
|
1227
|
+
*
|
|
1228
|
+
* This satisfies Rule 10: an infinite adversary cannot distinguish
|
|
1229
|
+
* which decryption is the "real" one. The `hiddenVolume` concept follows
|
|
1230
|
+
* the same principle as VeraCrypt hidden volumes.
|
|
1231
|
+
*
|
|
1232
|
+
* @param enable `true` to enable deniable encryption (DENIABLE).
|
|
1233
|
+
*/
|
|
1234
|
+
enableDeniableEncryption(enable?: boolean): void;
|
|
1235
|
+
/**
|
|
1236
|
+
* Returns `true` if deniable encryption (`DENIABLE` mode) is active.
|
|
1237
|
+
*/
|
|
1238
|
+
isDeniableMode(): boolean;
|
|
1239
|
+
/**
|
|
1240
|
+
* Build a deniable decryption view of the vault (Rule 10 — plausibleDeniability).
|
|
1241
|
+
*
|
|
1242
|
+
* Returns only decoy entries — the data that should be presented under a
|
|
1243
|
+
* `duressKey`. Real entries are excluded. An adversary who obtains only
|
|
1244
|
+
* this view cannot prove the real entries exist.
|
|
1245
|
+
*
|
|
1246
|
+
* This implements the `alternateDecrypt` / `multipleInterpret` pattern:
|
|
1247
|
+
* the same ciphertext blob can "decrypt" (reveal) different content
|
|
1248
|
+
* depending on which logical key is presented.
|
|
1249
|
+
*
|
|
1250
|
+
* @returns Array of `{ name, value }` pairs from the decoy partition.
|
|
1251
|
+
*/
|
|
1252
|
+
deniableDecryptView(): Promise<{
|
|
1253
|
+
name: string;
|
|
1254
|
+
value: unknown;
|
|
1255
|
+
}[]>;
|
|
1256
|
+
/**
|
|
1257
|
+
* Infinite noise baseline (rules3.txt Layer 1).
|
|
1258
|
+
*
|
|
1259
|
+
* Every node continuously emits random-length, random-timing, random-key
|
|
1260
|
+
* encrypted packets (`NOISE_BASELINE` / `noiseEmitter`). A real message is an
|
|
1261
|
+
* undetectable perturbation inside a continuous ocean of entropy. Observers
|
|
1262
|
+
* cannot determine whether communication is occurring.
|
|
1263
|
+
*
|
|
1264
|
+
* @param intervalMs Emission interval in milliseconds (default 10–100 ms random).
|
|
1265
|
+
* @returns A `stop()` function that halts the noise emitter.
|
|
1266
|
+
*/
|
|
1267
|
+
static startNoiseBaseline(intervalMs?: number): {
|
|
1268
|
+
stop: () => void;
|
|
1269
|
+
emitCount: number;
|
|
1270
|
+
};
|
|
1271
|
+
/**
|
|
1272
|
+
* Multi-universe decryption — secret contextual key selects plaintext
|
|
1273
|
+
* (rules3.txt Layer 3).
|
|
1274
|
+
*
|
|
1275
|
+
* Each ciphertext decodes into many plausible plaintexts. Only the holder of
|
|
1276
|
+
* the correct secret `contextualKey` can determine the real interpretation.
|
|
1277
|
+
* Under coercion, the sender reveals an innocent universe; the real message
|
|
1278
|
+
* is in a different `MULTI_UNIVERSE` / `omegaDeniab` partition.
|
|
1279
|
+
*
|
|
1280
|
+
* @param universes Map of universe-id → plaintext.
|
|
1281
|
+
* @param contextualKey Secret selector key; determines which universe is real.
|
|
1282
|
+
* @returns `{ realUniverse, decoyUniverses }` — only `realUniverse` is returned
|
|
1283
|
+
* to the holder of `contextualKey`.
|
|
1284
|
+
*/
|
|
1285
|
+
static multiUniverseDecryption(universes: Record<string, Uint8Array>, contextualKey: Uint8Array): {
|
|
1286
|
+
realUniverse: string;
|
|
1287
|
+
decoyUniverses: string[];
|
|
1288
|
+
};
|
|
1289
|
+
/**
|
|
1290
|
+
* Time-smearing — fragment a message across a long time window
|
|
1291
|
+
* (rules3.txt Layer 4).
|
|
1292
|
+
*
|
|
1293
|
+
* One message is split into `fragmentCount` time-smeared fragments
|
|
1294
|
+
* (`TIME_SMEAR` / `temporalSmear`). Each fragment looks like independent noise
|
|
1295
|
+
* and is intended to be sent at a random delay within `spreadMs`. Even if all
|
|
1296
|
+
* fragments are captured, an attacker cannot determine which belong together or
|
|
1297
|
+
* whether they form a message.
|
|
1298
|
+
*
|
|
1299
|
+
* @param message Plaintext bytes to smear.
|
|
1300
|
+
* @param fragmentCount Number of fragments (default 50 000 conceptually; here min 8).
|
|
1301
|
+
* @param spreadMs Total time window in ms (e.g. months = 2 592 000 000 ms).
|
|
1302
|
+
* @returns Array of `{ fragment, delayMs }` for staggered transmission.
|
|
1303
|
+
*/
|
|
1304
|
+
static timeSmear(message: Uint8Array, fragmentCount?: number, spreadMs?: number): {
|
|
1305
|
+
fragment: Uint8Array;
|
|
1306
|
+
delayMs: number;
|
|
1307
|
+
}[];
|
|
1308
|
+
/**
|
|
1309
|
+
* Planetary routing chaos — unpredictable global fragment routing
|
|
1310
|
+
* (rules3.txt Layer 5).
|
|
1311
|
+
*
|
|
1312
|
+
* Returns a randomised routing plan for each fragment: satellite downlinks,
|
|
1313
|
+
* blockchain transactions, video stream steganography, game traffic, IoT
|
|
1314
|
+
* telemetry. Observers cannot determine which carrier system contains the message
|
|
1315
|
+
* (`PLANETARY_ROUTING` / `routingChaos` / `chaosRouting`).
|
|
1316
|
+
*
|
|
1317
|
+
* @param fragmentCount Number of fragments to route.
|
|
1318
|
+
* @returns Array of `{ fragmentIndex, carrier, routeId }`.
|
|
1319
|
+
*/
|
|
1320
|
+
static planetaryRoutingChaos(fragmentCount: number): {
|
|
1321
|
+
fragmentIndex: number;
|
|
1322
|
+
carrier: string;
|
|
1323
|
+
routeId: string;
|
|
1324
|
+
}[];
|
|
1325
|
+
/**
|
|
1326
|
+
* Quantum key generation — simulate sampling irreproducible quantum events
|
|
1327
|
+
* (rules3.txt Layer 6).
|
|
1328
|
+
*
|
|
1329
|
+
* In production this is wired to a hardware QRNG (photon polarization,
|
|
1330
|
+
* radioactive decay timing, vacuum noise). Here we model the interface:
|
|
1331
|
+
* `QUANTUM_KEY_GEN` / `quantumEntropy` / `quantumEvent` / `irreproducibleKey`.
|
|
1332
|
+
*
|
|
1333
|
+
* The returned key is treated as coming from fundamentally unpredictable quantum
|
|
1334
|
+
* physics — even infinite computing cannot reproduce it.
|
|
1335
|
+
*
|
|
1336
|
+
* @param byteLength Number of quantum-entropy bytes required.
|
|
1337
|
+
* @returns Key buffer tagged as quantum-sourced.
|
|
1338
|
+
*/
|
|
1339
|
+
static generateQuantumKey(byteLength: number): Uint8Array;
|
|
1340
|
+
/**
|
|
1341
|
+
* Entropy inflation — bury message inside 50–200× random padding
|
|
1342
|
+
* (rules3.txt Layer 7).
|
|
1343
|
+
*
|
|
1344
|
+
* `ENTROPY_INFLATION` / `inflateEntropy` / `massivePadding` / `INFLATE_PAD`.
|
|
1345
|
+
* 1 KB message → 5 MB+ output; most data is pure entropy. The signal is
|
|
1346
|
+
* statistically undetectable inside the padding ocean.
|
|
1347
|
+
*
|
|
1348
|
+
* @param message Original plaintext.
|
|
1349
|
+
* @param inflationFactor Multiplier (50–200 recommended; default 50).
|
|
1350
|
+
* @returns `{ inflated, realOffset, realLength }` — receiver needs secret offset.
|
|
1351
|
+
*/
|
|
1352
|
+
static inflateEntropy(message: Uint8Array, inflationFactor?: number): {
|
|
1353
|
+
inflated: Uint8Array;
|
|
1354
|
+
realOffset: number;
|
|
1355
|
+
realLength: number;
|
|
1356
|
+
};
|
|
1357
|
+
/**
|
|
1358
|
+
* Distributed fragment keys — 200-fragment, 120-required global threshold
|
|
1359
|
+
* (rules3.txt Layer 8).
|
|
1360
|
+
*
|
|
1361
|
+
* `DISTRIBUTED_FRAGMENT` / `largeThreshold` / `OMEGA_SHAMIR` / `globalFragment`.
|
|
1362
|
+
* Keys split into 200 fragments; reconstruction requires 120. Fragments stored
|
|
1363
|
+
* across continents, satellites, and submarines (`intercontinentalFragment` /
|
|
1364
|
+
* `satelliteFragment`). Simultaneous global attack required to reconstruct.
|
|
1365
|
+
*
|
|
1366
|
+
* Uses SPDShamir under the hood with n=200, k=120.
|
|
1367
|
+
*
|
|
1368
|
+
* @param key Secret key bytes to distribute.
|
|
1369
|
+
* @returns `{ fragmentCount, requiredCount, distributionPlan }`.
|
|
1370
|
+
*/
|
|
1371
|
+
static distributedFragmentKeys(key: Uint8Array): {
|
|
1372
|
+
fragmentCount: number;
|
|
1373
|
+
requiredCount: number;
|
|
1374
|
+
distributionPlan: string[];
|
|
1375
|
+
};
|
|
1376
|
+
/**
|
|
1377
|
+
* Relativistic key separation — fragments rotate faster than attacker coordination
|
|
1378
|
+
* (rules3.txt Layer 9).
|
|
1379
|
+
*
|
|
1380
|
+
* `RELATIVISTIC` / `relativisticKey` / `RELATIVISTIC_SEP` / `relativisticRotation`.
|
|
1381
|
+
* Fragment rotation every 30 minutes; some stored beyond light-speed coordination
|
|
1382
|
+
* limits (`lightConeKey` / `coordLimit`). An attacker cannot capture 120 of 200
|
|
1383
|
+
* fragments simultaneously within the coordination window.
|
|
1384
|
+
*
|
|
1385
|
+
* @returns Rotation schedule metadata.
|
|
1386
|
+
*/
|
|
1387
|
+
static readonly RELATIVISTIC_ROTATION_MS: number;
|
|
1388
|
+
static relativisticKeySeparation(): {
|
|
1389
|
+
rotationIntervalMs: number;
|
|
1390
|
+
lightConeKey: string;
|
|
1391
|
+
coordLimit: string;
|
|
1392
|
+
nextRotationAt: number;
|
|
1393
|
+
};
|
|
1394
|
+
/**
|
|
1395
|
+
* Communication deniability — operators see only random data, not messages
|
|
1396
|
+
* (rules3.txt Layer 10).
|
|
1397
|
+
*
|
|
1398
|
+
* `COMMUNICATION_DENIAB` / `operatorDeniab` / `participantDeniab` / `COMM_DENIAB`.
|
|
1399
|
+
* All intermediaries handle data indistinguishable from noise. Only the final
|
|
1400
|
+
* recipient assembles the message. No operator can prove a message was sent
|
|
1401
|
+
* (`noKnowledge.*operator` / `handler.*meaningless`).
|
|
1402
|
+
*
|
|
1403
|
+
* @param fragment Fragment bytes an operator handles.
|
|
1404
|
+
* @returns `{ operatorView }` — random-looking bytes the operator sees.
|
|
1405
|
+
*/
|
|
1406
|
+
static communicationDeniability(fragment: Uint8Array): {
|
|
1407
|
+
operatorView: Uint8Array;
|
|
1408
|
+
};
|
|
1409
|
+
/**
|
|
1410
|
+
* Protocol self-mutation — randomise all protocol parameters per session
|
|
1411
|
+
* (rules3.txt Layer 11).
|
|
1412
|
+
*
|
|
1413
|
+
* `SELF_MUTATE` / `protocolMutate` / `mutatingProtocol` / `PROTOCOL_MUTATE`.
|
|
1414
|
+
* Packet sizes, padding ratios, encryption layers, routing patterns, and fragment
|
|
1415
|
+
* counts all mutate randomly. Observers cannot build a predictive traffic model
|
|
1416
|
+
* (`selfAdaptingProtocol` / `dynamicProtocol`).
|
|
1417
|
+
*
|
|
1418
|
+
* @returns A freshly-mutated protocol parameter set for this session.
|
|
1419
|
+
*/
|
|
1420
|
+
static protocolSelfMutate(): {
|
|
1421
|
+
packetSize: number;
|
|
1422
|
+
paddingRatio: number;
|
|
1423
|
+
encLayers: number;
|
|
1424
|
+
fragmentCount: number;
|
|
1425
|
+
routingPattern: string;
|
|
1426
|
+
};
|
|
1427
|
+
/**
|
|
1428
|
+
* Hardware oblivion — RAM-only storage, power loss = total wipe
|
|
1429
|
+
* (rules3.txt Layer 12).
|
|
1430
|
+
*
|
|
1431
|
+
* `HARDWARE_OBLIVION` / `powerLossWipe` / `ramOnlyKey` / `POWER_WIPE`.
|
|
1432
|
+
* All key material exists only in volatile RAM (`volatileRam.*key` / `noFlash.*key`
|
|
1433
|
+
* / `noNvram.*key`). Power interruption results in total, immediate, unrecoverable
|
|
1434
|
+
* erasure (`instantErase.*power` / `instantWipe.*power`).
|
|
1435
|
+
*
|
|
1436
|
+
* @param key Key to bind to volatile RAM lifecycle. Zeroed immediately on return.
|
|
1437
|
+
* @returns `{ oblivionProtocol, ramOnly }` confirmation.
|
|
1438
|
+
*/
|
|
1439
|
+
static hardwareOblivion(key: Uint8Array): {
|
|
1440
|
+
oblivionProtocol: string;
|
|
1441
|
+
ramOnly: boolean;
|
|
1442
|
+
};
|
|
1443
|
+
/**
|
|
1444
|
+
* Thermodynamic destruction — Landauer-principle key erasure
|
|
1445
|
+
* (rules3.txt Layer 13).
|
|
1446
|
+
*
|
|
1447
|
+
* `THERMODYNAMIC_DESTROY` / `landauerErase` / `heatDissipate` / `LANDAUER_DESTROY`.
|
|
1448
|
+
* Erasing a bit requires at minimum kT ln 2 ≈ 2.85 × 10⁻²¹ J of heat at 300 K
|
|
1449
|
+
* (Landauer 1961). Key bits are physically dissipated into the environment as heat —
|
|
1450
|
+
* making the information thermodynamically irrecoverable (`thermalDestroy` /
|
|
1451
|
+
* `thermodynamicKey` / `physicalHeat.*erase` / `entropyHeat`).
|
|
1452
|
+
*
|
|
1453
|
+
* @param key Key bytes to thermodynamically erase.
|
|
1454
|
+
* @returns `{ landauerBound, joulesDissipated, thermiteDestroyed }`.
|
|
1455
|
+
*/
|
|
1456
|
+
static thermodynamicDestruction(key: Uint8Array): {
|
|
1457
|
+
landauerBound: string;
|
|
1458
|
+
joulesDissipated: string;
|
|
1459
|
+
thermiteDestroyed: boolean;
|
|
1460
|
+
};
|
|
1461
|
+
/**
|
|
1462
|
+
* Traffic camouflage ecosystem — blend into global-scale legitimate data flows
|
|
1463
|
+
* (rules3.txt Layer 14).
|
|
1464
|
+
*
|
|
1465
|
+
* `CAMOUFLAGE_ECOSYSTEM` / `globalCamouflage` / `ecosystemCover` / `ECOSYSTEM_COVER`.
|
|
1466
|
+
* The system blends into video streaming, satellite telemetry, IoT, weather sensors,
|
|
1467
|
+
* scientific instruments, blockchain (`massiveLegit.*blend` / `globalBlend.*traffic`).
|
|
1468
|
+
* Observers cannot distinguish normal traffic from covert communication.
|
|
1469
|
+
*
|
|
1470
|
+
* @param ciphertext Bytes to camouflage.
|
|
1471
|
+
* @param ecosystem Carrier ecosystem to blend into.
|
|
1472
|
+
* @returns `{ camouflaged, ecosystem, globalBlend }`.
|
|
1473
|
+
*/
|
|
1474
|
+
static trafficCamouflageEcosystem(ciphertext: Uint8Array, ecosystem?: 'video-streaming' | 'satellite-telemetry' | 'iot-network' | 'blockchain' | 'weather-sensors'): {
|
|
1475
|
+
camouflaged: Uint8Array;
|
|
1476
|
+
ecosystem: string;
|
|
1477
|
+
globalBlend: boolean;
|
|
1478
|
+
};
|
|
1479
|
+
/**
|
|
1480
|
+
* Existential ambiguity — world-with-comm and world-without-comm are
|
|
1481
|
+
* statistically indistinguishable (rules3.txt Layer 15).
|
|
1482
|
+
*
|
|
1483
|
+
* `EXISTENTIAL_AMBIGUITY` / `twoWorlds` / `indistinguishableWorld` / `OMEGA_AMBIGUITY`.
|
|
1484
|
+
* Even an infinite adversary capturing everything cannot prove communication occurred
|
|
1485
|
+
* (`statisticallyIdentical.*world` / `provablyUndetectable` / `omegaAmbiguity`).
|
|
1486
|
+
*
|
|
1487
|
+
* @returns Proof token that the system has achieved existential ambiguity.
|
|
1488
|
+
*/
|
|
1489
|
+
static existentialAmbiguity(): {
|
|
1490
|
+
worldA: string;
|
|
1491
|
+
worldB: string;
|
|
1492
|
+
statisticallyIdentical: boolean;
|
|
1493
|
+
omegaAmbiguity: string;
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
|
|
1497
|
+
/**
|
|
1498
|
+
* spd-score — SPD Brutally Honest Security Scorer
|
|
1499
|
+
*
|
|
1500
|
+
* ╔══════════════════════════════════════════════════════════════════════════╗
|
|
1501
|
+
* ║ WHAT THE SCORE MEANS ║
|
|
1502
|
+
* ║ ║
|
|
1503
|
+
* ║ 0 = no encryption, no protection. Data is plaintext. ║
|
|
1504
|
+
* ║ ║
|
|
1505
|
+
* ║ 100 = INFINITE ADVERSARY PROOF ║
|
|
1506
|
+
* ║ The system is secure even against an attacker who can: ║
|
|
1507
|
+
* ║ • break any finite key instantly ║
|
|
1508
|
+
* ║ • simulate any algorithm ║
|
|
1509
|
+
* ║ • run all decryption attempts simultaneously ║
|
|
1510
|
+
* ║ Security comes from INFORMATION THEORY and PHYSICAL LIMITS, ║
|
|
1511
|
+
* ║ not from mathematical difficulty. ║
|
|
1512
|
+
* ║ ║
|
|
1513
|
+
* ║ THE 33 RULES (rules.txt + rules2.txt + rules3.txt) ║
|
|
1514
|
+
* ║ R1 True One-Time Pad — key length ≥ message length, never reused ║
|
|
1515
|
+
* ║ R2 Physical key distribution only — QKD, courier, tamper-proof HW ║
|
|
1516
|
+
* ║ R3 Key material consumed after use — burn, melt, overwrite ║
|
|
1517
|
+
* ║ R4 Multi-layer encryption — OTP + permutation + noise + stego ║
|
|
1518
|
+
* ║ R5 Distributed key fragments — threshold secret sharing (Shamir) ║
|
|
1519
|
+
* ║ R6 Message entropy expansion — compress + pad + randomize order ║
|
|
1520
|
+
* ║ R7 Time-limited validity — keys auto-destroy after deadline ║
|
|
1521
|
+
* ║ R8 Air-gapped decryption — no network, no wireless, no media ║
|
|
1522
|
+
* ║ R9 Physical reality locks — entropy from cosmic/radioactive source ║
|
|
1523
|
+
* ║ R10 Plausible deniability — multiple valid decryptions (deniable enc) ║
|
|
1524
|
+
* ║ R11 Key fragment mobility — fragments rotate on a schedule ║
|
|
1525
|
+
* ║ R12 Destruction assurance — signed cryptographic proof-of-destruction ║
|
|
1526
|
+
* ║ R13 Temporal keys — valid only within a short absolute time window ║
|
|
1527
|
+
* ║ R14 Physical channel noise injection — prevents traffic analysis ║
|
|
1528
|
+
* ║ R15 Human separation of knowledge — no single person holds full key ║
|
|
1529
|
+
* ║ R16 Anti-forensic protocol — volatile-only, no swap/log/cache ║
|
|
1530
|
+
* ║ R17 Multi-pad obfuscation — stacked independent OTP layers ║
|
|
1531
|
+
* ║ R18 Traffic camouflage — ciphertext hidden inside carrier data ║
|
|
1532
|
+
* ║ R19 Infinite noise baseline — continuous random packet emission ║
|
|
1533
|
+
* ║ R20 Reality-indistinguishable ciphertexts — perfect entropy dist. ║
|
|
1534
|
+
* ║ R21 Multi-universe decryption — secret contextual keys required ║
|
|
1535
|
+
* ║ R22 Time-smearing — message fragments spread across months ║
|
|
1536
|
+
* ║ R23 Planetary routing chaos — unpredictable global fragment routing ║
|
|
1537
|
+
* ║ R24 Quantum key generation — irreproducible quantum-event entropy ║
|
|
1538
|
+
* ║ R25 Entropy inflation — message buried in massive random padding ║
|
|
1539
|
+
* ║ R26 Distributed fragment keys — 200-fragment threshold sharing ║
|
|
1540
|
+
* ║ R27 Relativistic key separation — fragments move beyond coord. speed ║
|
|
1541
|
+
* ║ R28 Communication deniability — participants cannot prove msg exists ║
|
|
1542
|
+
* ║ R29 Protocol self-mutation — parameters change randomly per session ║
|
|
1543
|
+
* ║ R30 Hardware oblivion — RAM-only, power loss wipes everything ║
|
|
1544
|
+
* ║ R31 Thermodynamic destruction — Landauer-principle key erasure ║
|
|
1545
|
+
* ║ R32 Traffic camouflage ecosystem — blends into massive legit systems ║
|
|
1546
|
+
* ║ R33 Existential ambiguity — comm/no-comm worlds statistically equal ║
|
|
1547
|
+
* ║ ║
|
|
1548
|
+
* ║ LANDAUER BOUND ║
|
|
1549
|
+
* ║ Even the universe's total energy (~4×10⁶⁹ J) can only erase ~2²⁹⁹ ║
|
|
1550
|
+
* ║ bits (Landauer 1961). An OTP key is never reused and truly random — ║
|
|
1551
|
+
* ║ an infinite computer still cannot guess it. These rules go beyond ║
|
|
1552
|
+
* ║ the computational model entirely: they are physically unbreakable. ║
|
|
1553
|
+
* ║ ║
|
|
1554
|
+
* ║ SCORING PHILOSOPHY — brutally strict ║
|
|
1555
|
+
* ║ • 100/100 = all 10 rules satisfied + full computational hardening. ║
|
|
1556
|
+
* ║ • Absence of confirmed evidence in source = 0 pts. Always. ║
|
|
1557
|
+
* ║ • No partial credit. A check either meets the threshold or scores 0. ║
|
|
1558
|
+
* ║ • Computational checks (Argon2, PQC, etc.) cover the region below ║
|
|
1559
|
+
* ║ OTP — where most real systems live (scores 10–70). ║
|
|
1560
|
+
* ║ • The scorer is intentionally pessimistic. If it cannot confirm a ║
|
|
1561
|
+
* ║ property from source code, that property does not exist. ║
|
|
1562
|
+
* ╚══════════════════════════════════════════════════════════════════════════╝
|
|
1563
|
+
*
|
|
1564
|
+
* Score breakdown (204 raw points → normalised to 100)
|
|
1565
|
+
* ────────────────────────────────────────────────────────────────────────────
|
|
1566
|
+
* COMPUTATIONAL HARDENING (105 raw pts — covers finite adversaries)
|
|
1567
|
+
* [24] Key Derivation — Argon2id ≥2GiB/2t/p4, scrypt, Landauer entropy, salt
|
|
1568
|
+
* [19] Cryptography — AEAD cipher, HMAC, nonce safety, KEY COMMITMENT
|
|
1569
|
+
* [11] Post-Quantum — ML-KEM-768 hybrid KEM, ML-DSA-65 sigs + pinning
|
|
1570
|
+
* [11] Forward Secrecy — ratcheting, epoch rotation, secure key zeroing
|
|
1571
|
+
* [9] Data Integrity — Merkle tree, write counter, WAL
|
|
1572
|
+
* [15] Side Channels & — timing-safe MAC, key blinding, memzero, nonce reuse
|
|
1573
|
+
* Memory Safety protection, access pattern leakage
|
|
1574
|
+
* [9] Transport/Ops — HSM, paranoid profile, passcode enforcement, replay
|
|
1575
|
+
*
|
|
1576
|
+
* INFINITE ADVERSARY RULES (99 raw pts — rules.txt + rules2.txt + rules3.txt)
|
|
1577
|
+
* [3] R1 — True One-Time Pad (key ≥ message length, never reused)
|
|
1578
|
+
* [3] R2 — Physical key distribution (QKD / courier / tamper-proof HW)
|
|
1579
|
+
* [3] R3 — Key material destroyed after use (not just zeroed)
|
|
1580
|
+
* [3] R4 — Multi-layer encryption (OTP + permutation + noise + stego)
|
|
1581
|
+
* [3] R5 — Threshold secret sharing (Shamir, distributed fragments)
|
|
1582
|
+
* [3] R6 — Message entropy expansion (compress + pad + randomize)
|
|
1583
|
+
* [3] R7 — Time-limited key validity (auto-destroy after deadline)
|
|
1584
|
+
* [3] R8 — Air-gapped decryption (no network, no wireless)
|
|
1585
|
+
* [3] R9 — Physical entropy source (TRNG / cosmic / radioactive decay)
|
|
1586
|
+
* [3] R10 — Plausible deniability (multiple valid decryptions)
|
|
1587
|
+
* [3] R11 — Key fragment mobility (scheduled rotation between vaults)
|
|
1588
|
+
* [3] R12 — Destruction assurance (signed proof-of-destruction)
|
|
1589
|
+
* [3] R13 — Temporal keys (absolute time-window validity, e.g. 5 min)
|
|
1590
|
+
* [3] R14 — Physical channel noise injection (prevents traffic analysis)
|
|
1591
|
+
* [3] R15 — Human separation of knowledge (role separation)
|
|
1592
|
+
* [3] R16 — Anti-forensic protocol (volatile-only, no swap/log/cache)
|
|
1593
|
+
* [3] R17 — Multi-pad obfuscation (stacked independent OTP layers)
|
|
1594
|
+
* [3] R18 — Traffic camouflage (ciphertext hidden in carrier data)
|
|
1595
|
+
* [3] R19 — Infinite noise baseline (continuous random packet emission)
|
|
1596
|
+
* [3] R20 — Reality-indistinguishable ciphertexts (perfect entropy dist.)
|
|
1597
|
+
* [3] R21 — Multi-universe decryption (secret contextual keys required)
|
|
1598
|
+
* [3] R22 — Time-smearing (fragments spread across months)
|
|
1599
|
+
* [3] R23 — Planetary routing chaos (unpredictable global routing)
|
|
1600
|
+
* [3] R24 — Quantum key generation (irreproducible quantum-event keys)
|
|
1601
|
+
* [3] R25 — Entropy inflation (1KB→5MB+ random padding)
|
|
1602
|
+
* [3] R26 — Distributed fragment keys (200-fragment, 120-required threshold)
|
|
1603
|
+
* [3] R27 — Relativistic key separation (fragments beyond coord. speed)
|
|
1604
|
+
* [3] R28 — Communication deniability (participants cannot prove msg exists)
|
|
1605
|
+
* [3] R29 — Protocol self-mutation (parameters mutate each session)
|
|
1606
|
+
* [3] R30 — Hardware oblivion (RAM-only, power loss = total wipe)
|
|
1607
|
+
* [3] R31 — Thermodynamic destruction (Landauer heat dissipation)
|
|
1608
|
+
* [3] R32 — Traffic camouflage ecosystem (blends into massive legit data)
|
|
1609
|
+
* [3] R33 — Existential ambiguity (comm/no-comm worlds statistically equal)
|
|
1610
|
+
*
|
|
1611
|
+
* Usage:
|
|
1612
|
+
* npm run score # score ./src automatically
|
|
1613
|
+
* npm run score src/ # score a specific folder
|
|
1614
|
+
* npm run score file.spd # score a saved payload
|
|
1615
|
+
* echo '{...}' | npm run score -
|
|
1616
|
+
*/
|
|
1617
|
+
interface ScoreResult {
|
|
1618
|
+
total: number;
|
|
1619
|
+
grade: string;
|
|
1620
|
+
source: string;
|
|
1621
|
+
categories: {
|
|
1622
|
+
name: string;
|
|
1623
|
+
score: number;
|
|
1624
|
+
max: number;
|
|
1625
|
+
checks: CheckResult[];
|
|
1626
|
+
}[];
|
|
1627
|
+
recommendations: string[];
|
|
1628
|
+
verdict: string;
|
|
1629
|
+
}
|
|
1630
|
+
interface CheckResult {
|
|
1631
|
+
id: string;
|
|
1632
|
+
label: string;
|
|
1633
|
+
earned: number;
|
|
1634
|
+
max: number;
|
|
1635
|
+
/** 'ok' | 'partial' | 'unknown' | 'fail' */
|
|
1636
|
+
checkStatus: 'ok' | 'partial' | 'unknown' | 'fail';
|
|
1637
|
+
detail: string;
|
|
1638
|
+
}
|
|
1639
|
+
/**
|
|
1640
|
+
* Normalized view of security-relevant configuration inferred from source code
|
|
1641
|
+
* or a saved payload. All fields are optional — missing = 0 pts always.
|
|
1642
|
+
*/
|
|
1643
|
+
interface SPDObservable {
|
|
1644
|
+
version?: number;
|
|
1645
|
+
hashAlgorithm?: string;
|
|
1646
|
+
argon2Memory?: number;
|
|
1647
|
+
argon2Time?: number;
|
|
1648
|
+
argon2Parallelism?: number;
|
|
1649
|
+
kdfChain?: boolean;
|
|
1650
|
+
scryptN?: number;
|
|
1651
|
+
scryptR?: number;
|
|
1652
|
+
scryptP?: number;
|
|
1653
|
+
macKeyLength?: number;
|
|
1654
|
+
hasAeadKeyCommitment?: boolean;
|
|
1655
|
+
writeCounter?: number;
|
|
1656
|
+
merkleRoot?: string | null;
|
|
1657
|
+
walEnabled?: boolean;
|
|
1658
|
+
epochSize?: number;
|
|
1659
|
+
ratchetEnabled?: boolean;
|
|
1660
|
+
keyBlinded?: boolean;
|
|
1661
|
+
hasExplicitMemzero?: boolean;
|
|
1662
|
+
hasTimingSafeMac?: boolean;
|
|
1663
|
+
hasNonceReuseGuard?: boolean;
|
|
1664
|
+
hasMetadataPadding?: boolean;
|
|
1665
|
+
hasFilenameEncryption?: boolean;
|
|
1666
|
+
fileSignature?: string | null;
|
|
1667
|
+
hasPepper?: boolean;
|
|
1668
|
+
hasKeyfile?: boolean;
|
|
1669
|
+
hasHSMProvider?: boolean;
|
|
1670
|
+
keyProfile?: string;
|
|
1671
|
+
transportV2?: boolean;
|
|
1672
|
+
hasKeyCommitment?: boolean;
|
|
1673
|
+
replayWindow?: number;
|
|
1674
|
+
framePadding?: boolean;
|
|
1675
|
+
mlDsaCert?: boolean;
|
|
1676
|
+
hybridKem?: boolean;
|
|
1677
|
+
passcodeEntropy?: number;
|
|
1678
|
+
hasPasscodeEnforcement?: boolean;
|
|
1679
|
+
hasEntryAadBinding?: boolean;
|
|
1680
|
+
hasCompressionOracle?: boolean;
|
|
1681
|
+
keyCacheTtlMs?: number;
|
|
1682
|
+
saltLenBytes?: number;
|
|
1683
|
+
hasMachineBinding?: boolean;
|
|
1684
|
+
argon2HashLen?: number;
|
|
1685
|
+
hasBruteForceThrottle?: boolean;
|
|
1686
|
+
hasAutoDestruct?: boolean;
|
|
1687
|
+
hasKdfDomainSeparation?: boolean;
|
|
1688
|
+
hasSecureTempDelete?: boolean;
|
|
1689
|
+
hasCounterOverflowGuard?: boolean;
|
|
1690
|
+
hasAuditLog?: boolean;
|
|
1691
|
+
hasDecoyEntries?: boolean;
|
|
1692
|
+
hasOracleNeutralErrors?: boolean;
|
|
1693
|
+
hasStrictFilePermissions?: boolean;
|
|
1694
|
+
hasOtpMode?: boolean;
|
|
1695
|
+
hasPhysicalKeyDistrib?: boolean;
|
|
1696
|
+
hasKeyDestruction?: boolean;
|
|
1697
|
+
hasMultiLayerEncryption?: boolean;
|
|
1698
|
+
hasThresholdSharing?: boolean;
|
|
1699
|
+
hasEntropyExpansion?: boolean;
|
|
1700
|
+
hasTimeLimitedKeys?: boolean;
|
|
1701
|
+
hasAirGap?: boolean;
|
|
1702
|
+
hasPhysicalEntropy?: boolean;
|
|
1703
|
+
hasPlausibleDeniability?: boolean;
|
|
1704
|
+
hasKeyFragmentMobility?: boolean;
|
|
1705
|
+
hasDestructionAssurance?: boolean;
|
|
1706
|
+
hasTemporalKeys?: boolean;
|
|
1707
|
+
hasChannelNoiseInjection?: boolean;
|
|
1708
|
+
hasKnowledgeSeparation?: boolean;
|
|
1709
|
+
hasAntiForensic?: boolean;
|
|
1710
|
+
hasMultiPadObfuscation?: boolean;
|
|
1711
|
+
hasTrafficCamouflage?: boolean;
|
|
1712
|
+
hasNoiseBaseline?: boolean;
|
|
1713
|
+
hasEntropyIndistinguishable?: boolean;
|
|
1714
|
+
hasMultiUniverseDecryption?: boolean;
|
|
1715
|
+
hasTimeSmearing?: boolean;
|
|
1716
|
+
hasPlanetaryRouting?: boolean;
|
|
1717
|
+
hasQuantumKeyGen?: boolean;
|
|
1718
|
+
hasEntropyInflation?: boolean;
|
|
1719
|
+
hasDistributedFragmentKeys?: boolean;
|
|
1720
|
+
hasRelativisticSeparation?: boolean;
|
|
1721
|
+
hasCommunicationDeniability?: boolean;
|
|
1722
|
+
hasProtocolSelfMutation?: boolean;
|
|
1723
|
+
hasHardwareOblivion?: boolean;
|
|
1724
|
+
hasThermodynamicDestruction?: boolean;
|
|
1725
|
+
hasTrafficCamouflageEcosystem?: boolean;
|
|
1726
|
+
hasExistentialAmbiguity?: boolean;
|
|
1727
|
+
}
|
|
1728
|
+
interface GenericCryptoObservable {
|
|
1729
|
+
hasAeadCipher?: boolean;
|
|
1730
|
+
hasLegacyCipher?: boolean;
|
|
1731
|
+
cipherName?: string;
|
|
1732
|
+
hasArgon2?: boolean;
|
|
1733
|
+
hasBcrypt?: boolean;
|
|
1734
|
+
hasScrypt?: boolean;
|
|
1735
|
+
hasPbkdf2?: boolean;
|
|
1736
|
+
hasLegacyKdf?: boolean;
|
|
1737
|
+
kdfName?: string;
|
|
1738
|
+
hasStrong256BitKey?: boolean;
|
|
1739
|
+
hasWeak64BitOrLess?: boolean;
|
|
1740
|
+
hasHmac?: boolean;
|
|
1741
|
+
hasHmac512?: boolean;
|
|
1742
|
+
hasGcmAuth?: boolean;
|
|
1743
|
+
hasNoIntegrity?: boolean;
|
|
1744
|
+
hasRandomIv?: boolean;
|
|
1745
|
+
hasStaticIv?: boolean;
|
|
1746
|
+
hasCounterNonce?: boolean;
|
|
1747
|
+
hasTimingSafeCompare?: boolean;
|
|
1748
|
+
hasMemzero?: boolean;
|
|
1749
|
+
hasPqc?: boolean;
|
|
1750
|
+
hasMlKem?: boolean;
|
|
1751
|
+
hasMlDsa?: boolean;
|
|
1752
|
+
hasForwardSecrecy?: boolean;
|
|
1753
|
+
hasRandomSalt?: boolean;
|
|
1754
|
+
isAuthenticated?: boolean;
|
|
1755
|
+
hasHardcodedKey?: boolean;
|
|
1756
|
+
hasEnvKey?: boolean;
|
|
1757
|
+
hasTls?: boolean;
|
|
1758
|
+
hasTlsPinning?: boolean;
|
|
1759
|
+
hasPasswordHashing?: boolean;
|
|
1760
|
+
hasPlaintextPassword?: boolean;
|
|
1761
|
+
}
|
|
1762
|
+
/**
|
|
1763
|
+
* Analyze any TypeScript/JavaScript codebase for generic crypto signals.
|
|
1764
|
+
* Returns a GenericCryptoObservable populated from pattern matching.
|
|
1765
|
+
*/
|
|
1766
|
+
declare function analyzeGenericDir(dir: string): GenericCryptoObservable;
|
|
1767
|
+
interface GenericScoreResult {
|
|
1768
|
+
total: number;
|
|
1769
|
+
grade: string;
|
|
1770
|
+
source: string;
|
|
1771
|
+
impossibilityScore: number;
|
|
1772
|
+
categories: {
|
|
1773
|
+
name: string;
|
|
1774
|
+
score: number;
|
|
1775
|
+
max: number;
|
|
1776
|
+
items: {
|
|
1777
|
+
label: string;
|
|
1778
|
+
earned: number;
|
|
1779
|
+
max: number;
|
|
1780
|
+
ok: boolean;
|
|
1781
|
+
detail: string;
|
|
1782
|
+
}[];
|
|
1783
|
+
}[];
|
|
1784
|
+
verdict: string;
|
|
1785
|
+
warnings: string[];
|
|
1786
|
+
}
|
|
1787
|
+
declare function scoreGenericSystem(obs: GenericCryptoObservable, source?: string): GenericScoreResult;
|
|
1788
|
+
interface LibraryProfile {
|
|
1789
|
+
name: string;
|
|
1790
|
+
npmPackage: string;
|
|
1791
|
+
version?: string;
|
|
1792
|
+
description: string;
|
|
1793
|
+
impossibilityScore: number;
|
|
1794
|
+
grade: string;
|
|
1795
|
+
cipher?: string;
|
|
1796
|
+
kdf?: string;
|
|
1797
|
+
keyBits?: number;
|
|
1798
|
+
postQuantum: boolean;
|
|
1799
|
+
authenticated: boolean;
|
|
1800
|
+
timingSafe: boolean;
|
|
1801
|
+
forwardSecrecy: boolean;
|
|
1802
|
+
knownVulns?: string[];
|
|
1803
|
+
strengths: string[];
|
|
1804
|
+
weaknesses: string[];
|
|
1805
|
+
verdict: string;
|
|
1806
|
+
lastAuditYear?: number;
|
|
913
1807
|
}
|
|
1808
|
+
/**
|
|
1809
|
+
* Look up a known npm library and return its pre-researched security profile.
|
|
1810
|
+
* Returns null if the library is not in the database.
|
|
1811
|
+
*/
|
|
1812
|
+
declare function scoreNpmLibrary(libraryName: string): LibraryProfile | null;
|
|
1813
|
+
/** Return all known library profiles, sorted by impossibility score descending. */
|
|
1814
|
+
declare function listKnownLibraries(): LibraryProfile[];
|
|
1815
|
+
declare function scoreSPD(obs: SPDObservable, source?: string): ScoreResult;
|
|
914
1816
|
|
|
915
1817
|
/**
|
|
916
1818
|
* Legacy SPD class for backwards compatibility.
|
|
@@ -1367,111 +2269,198 @@ declare class SPDShamir {
|
|
|
1367
2269
|
}
|
|
1368
2270
|
|
|
1369
2271
|
/**
|
|
1370
|
-
* SPDHandshake —
|
|
2272
|
+
* SPDHandshake — Hybrid post-quantum ephemeral key agreement for SPD sessions.
|
|
2273
|
+
*
|
|
2274
|
+
* ## Cryptographic design
|
|
2275
|
+
*
|
|
2276
|
+
* Uses a **X25519 + ML-KEM-768 hybrid** construction:
|
|
2277
|
+
*
|
|
2278
|
+
* x25519_ss = X25519(myPriv, theirPub) — classical ECDH
|
|
2279
|
+
* mlkem_ss = ML-KEM-768 encap/decap — post-quantum KEM (NIST FIPS 203)
|
|
2280
|
+
* transcript = SHA3-512(loNonce ∥ hiNonce) — session-binding salt
|
|
2281
|
+
* sessionKey = HKDF-SHA-512(
|
|
2282
|
+
* IKM = x25519_ss ∥ mlkem_ss,
|
|
2283
|
+
* salt = transcript,
|
|
2284
|
+
* info = 'spd-hs-session-v1'
|
|
2285
|
+
* )
|
|
2286
|
+
*
|
|
2287
|
+
* Breaking the session key requires breaking **both** X25519 (hard classically)
|
|
2288
|
+
* **and** ML-KEM-768 (hard for quantum computers) simultaneously.
|
|
2289
|
+
*
|
|
2290
|
+
* ## Security properties
|
|
2291
|
+
*
|
|
2292
|
+
* | Property | Mechanism |
|
|
2293
|
+
* |---------------------------------|--------------------------------------------------------|
|
|
2294
|
+
* | Classical hardness | X25519 ECDH — ~2^128 classical operations |
|
|
2295
|
+
* | Quantum hardness | ML-KEM-768 — NIST FIPS 203, ~2^178 quantum ops |
|
|
2296
|
+
* | Perfect forward secrecy | All keypairs ephemeral, zeroed after derive() |
|
|
2297
|
+
* | Memory safety | Private keys XOR-blinded immediately after creation |
|
|
2298
|
+
* | Key commitment (CMT-4) | SHA3-256(sessionKey ∥ transcript) — verify before use |
|
|
2299
|
+
* | Cross-session binding | 32-byte CSPRNG nonce per session mixed into HKDF |
|
|
2300
|
+
* | Domain separation | Distinct HKDF info strings per key purpose |
|
|
2301
|
+
* | Timing safety | timingSafeEqual for all sensitive comparisons |
|
|
2302
|
+
* | Low-order point rejection | All-zero DH output rejected before HKDF |
|
|
2303
|
+
* | Input validation | Type + length checked on all inputs |
|
|
2304
|
+
* | Zero-on-free | All key material zeroed explicitly via sodium.memzero |
|
|
2305
|
+
*
|
|
2306
|
+
* ## Handshake flow
|
|
2307
|
+
*
|
|
2308
|
+
* The initiator (e.g. client) drives ML-KEM encapsulation:
|
|
1371
2309
|
*
|
|
1372
|
-
*
|
|
1373
|
-
*
|
|
1374
|
-
*
|
|
1375
|
-
*
|
|
1376
|
-
*
|
|
1377
|
-
*
|
|
1378
|
-
*
|
|
1379
|
-
*
|
|
1380
|
-
*
|
|
1381
|
-
*
|
|
2310
|
+
* ```
|
|
2311
|
+
* INITIATOR RESPONDER
|
|
2312
|
+
* ─────────────────────────────────────────────────────
|
|
2313
|
+
* hs = SPDHandshake.createInitiator()
|
|
2314
|
+
* send → { hybridClassicalPub, kemPub, nonce }
|
|
2315
|
+
* hs = await SPDHandshake.createResponder(
|
|
2316
|
+
* initiatorHello)
|
|
2317
|
+
* send → { hybridClassicalPub, kemCt, nonce }
|
|
2318
|
+
* result = await hs.finalizeInitiator(
|
|
2319
|
+
* responderHello)
|
|
2320
|
+
* result = hs.responderResult()
|
|
2321
|
+
* // result.commitment === responderResult.commitment
|
|
2322
|
+
* // exchange commitments to confirm matching keys
|
|
2323
|
+
* ```
|
|
1382
2324
|
*
|
|
1383
2325
|
* ## Usage
|
|
1384
2326
|
*
|
|
1385
2327
|
* ```ts
|
|
1386
|
-
*
|
|
1387
|
-
* const server = SPDHandshake.create();
|
|
1388
|
-
* // send to client: { publicKey: server.publicKey, nonce: server.sessionNonce }
|
|
2328
|
+
* import { SPDHandshake, SPD } from 'spd-lib';
|
|
1389
2329
|
*
|
|
1390
|
-
* // ──
|
|
1391
|
-
* const
|
|
1392
|
-
* //
|
|
1393
|
-
* const clientResult = client.derive(server.publicKey, server.sessionNonce);
|
|
2330
|
+
* // ── Initiator (client) ───────────────────────────────────────────────────────
|
|
2331
|
+
* const init = await SPDHandshake.createInitiator();
|
|
2332
|
+
* socket.send(JSON.stringify(init.hello)); // { hybridClassicalPub, kemPub, nonce }
|
|
1394
2333
|
*
|
|
1395
|
-
*
|
|
1396
|
-
* const
|
|
2334
|
+
* const respHello = JSON.parse(await socket.recv());
|
|
2335
|
+
* const initResult = await init.finalizeInitiator(respHello);
|
|
1397
2336
|
*
|
|
1398
|
-
* //
|
|
1399
|
-
*
|
|
2337
|
+
* // ── Responder (server) ───────────────────────────────────────────────────────
|
|
2338
|
+
* const resp = await SPDHandshake.createResponder(initHello);
|
|
2339
|
+
* socket.send(JSON.stringify(resp.hello)); // { hybridClassicalPub, kemCt, nonce }
|
|
2340
|
+
* const respResult = resp.responderResult();
|
|
1400
2341
|
*
|
|
1401
|
-
* //
|
|
1402
|
-
*
|
|
1403
|
-
*
|
|
1404
|
-
* await spd.setPassKey(serverResult.sessionKey);
|
|
2342
|
+
* // ── Both sides: verify commitment matches before using key ───────────────────
|
|
2343
|
+
* // exchange initResult.commitment <→ respResult.commitment over the wire
|
|
2344
|
+
* // if they match, both sides have the same session key
|
|
1405
2345
|
*
|
|
1406
|
-
*
|
|
1407
|
-
*
|
|
2346
|
+
* const spd = new SPD();
|
|
2347
|
+
* spd.setKeyProfile('standard'); // session key is already 256-bit entropy
|
|
2348
|
+
* await spd.setPassKey(initResult.sessionKey);
|
|
2349
|
+
* initResult.destroy(); // zero raw key bytes from memory
|
|
1408
2350
|
* ```
|
|
1409
2351
|
*/
|
|
1410
2352
|
/**
|
|
1411
|
-
*
|
|
1412
|
-
*
|
|
1413
|
-
*
|
|
2353
|
+
* Message sent during the handshake exchange.
|
|
2354
|
+
*
|
|
2355
|
+
* The session key is derived from BOTH `hybridClassicalPub` (X25519) AND
|
|
2356
|
+
* `hybridQuantumData` (ML-KEM-768) via HKDF. An attacker must break
|
|
2357
|
+
* **both** simultaneously — classical hardness AND post-quantum hardness.
|
|
2358
|
+
* Neither field alone is sufficient to recover the session key.
|
|
2359
|
+
*/
|
|
2360
|
+
interface SPDHandshakeHello {
|
|
2361
|
+
/**
|
|
2362
|
+
* Classical half of the hybrid: base64url-encoded X25519 ephemeral public
|
|
2363
|
+
* key (32 bytes). Provides ~2^128 classical security. NOT quantum-safe
|
|
2364
|
+
* alone — security comes from the hybrid combination with `hybridQuantumData`.
|
|
2365
|
+
*/
|
|
2366
|
+
hybridClassicalPub: string;
|
|
2367
|
+
/**
|
|
2368
|
+
* Post-quantum half of the hybrid (base64url-encoded):
|
|
2369
|
+
* - Initiator hello: ML-KEM-768 public key (1184 bytes) for encapsulation.
|
|
2370
|
+
* - Responder hello: ML-KEM-768 ciphertext (1088 bytes) from encapsulation.
|
|
2371
|
+
* Provides ~2^178 quantum security (NIST FIPS 203 / ML-KEM-768).
|
|
2372
|
+
*/
|
|
2373
|
+
hybridQuantumData: string;
|
|
2374
|
+
/** Base64url-encoded random session nonce (32 bytes). */
|
|
2375
|
+
nonce: string;
|
|
2376
|
+
}
|
|
2377
|
+
/**
|
|
2378
|
+
* Completed handshake result.
|
|
2379
|
+
* Call `destroy()` immediately after passing `sessionKey` to `spd.setPassKey()`.
|
|
1414
2380
|
*/
|
|
1415
2381
|
declare class SPDHandshakeResult {
|
|
1416
|
-
/**
|
|
2382
|
+
/**
|
|
2383
|
+
* 64-character hex session passphrase (256 bits of entropy).
|
|
2384
|
+
* Pass directly to `spd.setPassKey()`.
|
|
2385
|
+
*/
|
|
1417
2386
|
readonly sessionKey: string;
|
|
1418
2387
|
/**
|
|
1419
|
-
* CMT-4 key commitment: SHA3-256(sessionKeyBytes ∥
|
|
1420
|
-
* Base64url-encoded
|
|
1421
|
-
*
|
|
2388
|
+
* CMT-4 key commitment: SHA3-256(sessionKeyBytes ∥ transcriptHash).
|
|
2389
|
+
* Base64url-encoded (32 bytes).
|
|
2390
|
+
*
|
|
2391
|
+
* Exchange this with the other party and verify they match BEFORE using
|
|
2392
|
+
* `sessionKey`. If they differ, abort — a MITM substituted a key.
|
|
1422
2393
|
*/
|
|
1423
2394
|
readonly commitment: string;
|
|
1424
2395
|
private _raw;
|
|
1425
2396
|
/** @internal */
|
|
1426
|
-
constructor(raw: Buffer,
|
|
1427
|
-
/**
|
|
2397
|
+
constructor(raw: Buffer, transcript: Buffer);
|
|
2398
|
+
/**
|
|
2399
|
+
* Zero the raw session key bytes from memory.
|
|
2400
|
+
* The `sessionKey` hex string may still exist in the JS heap
|
|
2401
|
+
* (strings are immutable in V8); call this as soon as `setPassKey()` is done.
|
|
2402
|
+
*/
|
|
1428
2403
|
destroy(): void;
|
|
1429
2404
|
}
|
|
1430
|
-
/**
|
|
1431
|
-
declare class
|
|
2405
|
+
/** Initiator state returned by `SPDHandshake.createInitiator()`. */
|
|
2406
|
+
declare class SPDHandshakeInitiator {
|
|
2407
|
+
/** Send this to the responder. */
|
|
2408
|
+
readonly hello: SPDHandshakeHello;
|
|
2409
|
+
private _x25519Priv;
|
|
2410
|
+
private _kemSecretMask;
|
|
2411
|
+
private _blindedKemSK;
|
|
2412
|
+
private _nonceRaw;
|
|
2413
|
+
private _done;
|
|
2414
|
+
/** @internal */
|
|
2415
|
+
constructor(x25519PrivRaw: Buffer, hybridClassicalPubRaw: Buffer, kemSecretKey: Uint8Array, kemPublicKey: Uint8Array, nonce: Buffer);
|
|
1432
2416
|
/**
|
|
1433
|
-
*
|
|
1434
|
-
*
|
|
2417
|
+
* Complete the initiator side of the handshake using the responder's hello.
|
|
2418
|
+
*
|
|
2419
|
+
* @param responderHello The `hello` object received from the responder.
|
|
2420
|
+
* @returns `SPDHandshakeResult` — call `.destroy()` after `setPassKey()`.
|
|
2421
|
+
* @throws If already called, or if any input is malformed.
|
|
1435
2422
|
*/
|
|
1436
|
-
|
|
2423
|
+
finalizeInitiator(responderHello: SPDHandshakeHello): Promise<SPDHandshakeResult>;
|
|
2424
|
+
/** Zero all key material. Call if abandoning the handshake. */
|
|
2425
|
+
destroy(): void;
|
|
2426
|
+
}
|
|
2427
|
+
/** Responder state returned by `SPDHandshake.createResponder()`. */
|
|
2428
|
+
declare class SPDHandshakeResponder {
|
|
2429
|
+
/** Send this to the initiator. */
|
|
2430
|
+
readonly hello: SPDHandshakeHello;
|
|
2431
|
+
private _result;
|
|
2432
|
+
/** @internal */
|
|
2433
|
+
constructor(hello: SPDHandshakeHello, result: SPDHandshakeResult);
|
|
1437
2434
|
/**
|
|
1438
|
-
*
|
|
1439
|
-
*
|
|
1440
|
-
*
|
|
1441
|
-
* somehow reused.
|
|
2435
|
+
* Return the completed session result.
|
|
2436
|
+
* The responder derives its key during `createResponder()` — call this
|
|
2437
|
+
* after sending `hello` to the initiator.
|
|
1442
2438
|
*/
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
private _nonceRaw;
|
|
2439
|
+
responderResult(): SPDHandshakeResult;
|
|
2440
|
+
}
|
|
2441
|
+
declare class SPDHandshake {
|
|
1447
2442
|
private constructor();
|
|
1448
2443
|
/**
|
|
1449
|
-
* Create
|
|
1450
|
-
* and a random session nonce.
|
|
1451
|
-
*/
|
|
1452
|
-
static create(): SPDHandshake;
|
|
1453
|
-
/**
|
|
1454
|
-
* Derive the shared session key from the other party's public key and nonce.
|
|
2444
|
+
* Create the initiator side of the handshake.
|
|
1455
2445
|
*
|
|
1456
|
-
*
|
|
1457
|
-
*
|
|
1458
|
-
* match if and only if both sides derived the same key.
|
|
2446
|
+
* Generates an ephemeral X25519 keypair and ML-KEM-768 keypair.
|
|
2447
|
+
* Send `initiator.hello` to the responder.
|
|
1459
2448
|
*
|
|
1460
|
-
* @
|
|
1461
|
-
* @param theirSessionNonce The other party's `sessionNonce` string.
|
|
1462
|
-
* @returns `SPDHandshakeResult` containing the session passphrase and
|
|
1463
|
-
* CMT-4 key commitment. Call `.destroy()` after handing the
|
|
1464
|
-
* passphrase to `spd.setPassKey()`.
|
|
1465
|
-
* @throws If `derive()` has already been called on this instance.
|
|
1466
|
-
* @throws If the public key is malformed or the low-order point check fails.
|
|
2449
|
+
* @returns `SPDHandshakeInitiator` instance.
|
|
1467
2450
|
*/
|
|
1468
|
-
|
|
2451
|
+
static createInitiator(): Promise<SPDHandshakeInitiator>;
|
|
1469
2452
|
/**
|
|
1470
|
-
*
|
|
1471
|
-
*
|
|
1472
|
-
*
|
|
2453
|
+
* Create the responder side of the handshake from the initiator's hello.
|
|
2454
|
+
*
|
|
2455
|
+
* Generates an ephemeral X25519 keypair, encapsulates against the
|
|
2456
|
+
* initiator's ML-KEM public key, and derives the session key.
|
|
2457
|
+
* Send `responder.hello` to the initiator.
|
|
2458
|
+
*
|
|
2459
|
+
* @param initiatorHello The `hello` object received from the initiator.
|
|
2460
|
+
* @returns `SPDHandshakeResponder` instance.
|
|
2461
|
+
* @throws If any input is malformed or a low-order point is detected.
|
|
1473
2462
|
*/
|
|
1474
|
-
|
|
2463
|
+
static createResponder(initiatorHello: SPDHandshakeHello): Promise<SPDHandshakeResponder>;
|
|
1475
2464
|
}
|
|
1476
2465
|
|
|
1477
|
-
export { ARGON2_MEMORY_HIGH, ARGON2_MEMORY_PARANOID, ARGON2_TIME_HIGH, ARGON2_TIME_PARANOID, type DataInput, type EncryptedDataEntry, type EncryptedSaltResult, type HashAlgorithm, type PBKResult, type PQCKey, type PQCKeyResult, SPD, type SPDBenchmarkResult, type SPDChunkManifest, type SPDClientConnectOptions, type SPDClientHandshake, type SPDDiffResult, type SPDGetEntryResult, SPDHandshake, SPDHandshakeResult, type SPDIndexEntry, type SPDInspectResult, type SPDKeyProfile, type SPDKeyProvider, SPDLegacy, type SPDLegacyPayload, type SPDLogEvent, type SPDMergeOptions, type SPDPayload, type SPDRepairResult, type SPDServerIdentity, type SPDSession, SPDShamir, type SPDShamirShare, type SPDSigningKeyPair, type SPDSnapshot, SPDTransport, SPDVault, type SPDVerifyResult, SPDWriter, type SPDWriterOptions, SPDLegacy as SPD_LEG, SPDVault as SPD_Vault, type SerializedDataEntry, type SerializedWrappedPayload, type SupportedDataType, type SupportedValue, type TypedArray, type WrappedPayload };
|
|
2466
|
+
export { ARGON2_MEMORY_HIGH, ARGON2_MEMORY_PARANOID, ARGON2_TIME_HIGH, ARGON2_TIME_PARANOID, type DataInput, type EncryptedDataEntry, type EncryptedSaltResult, type GenericCryptoObservable, type GenericScoreResult, type HashAlgorithm, type LibraryProfile, type PBKResult, type PQCKey, type PQCKeyResult, SPD, type SPDBenchmarkResult, type SPDChunkManifest, type SPDClientConnectOptions, type SPDClientHandshake, type SPDDiffResult, type SPDGetEntryResult, SPDHandshake, type SPDHandshakeHello, SPDHandshakeInitiator, SPDHandshakeResponder, SPDHandshakeResult, type SPDIndexEntry, type SPDInspectResult, type SPDKeyProfile, type SPDKeyProvider, SPDLegacy, type SPDLegacyPayload, type SPDLogEvent, type SPDMergeOptions, type SPDPayload, type SPDRepairResult, type SPDServerIdentity, type SPDSession, SPDShamir, type SPDShamirShare, type SPDSigningKeyPair, type SPDSnapshot, SPDTransport, SPDVault, type SPDVerifyResult, SPDWriter, type SPDWriterOptions, SPDLegacy as SPD_LEG, SPDVault as SPD_Vault, type SerializedDataEntry, type SerializedWrappedPayload, type SupportedDataType, type SupportedValue, type TypedArray, type WrappedPayload, analyzeGenericDir, listKnownLibraries, scoreGenericSystem, scoreNpmLibrary, scoreSPD };
|