canary-kit 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CANARY.md +1065 -0
- package/INTEGRATION.md +351 -0
- package/LICENSE +21 -0
- package/NIP-CANARY.md +624 -0
- package/README.md +187 -0
- package/SECURITY.md +92 -0
- package/dist/beacon.d.ts +104 -0
- package/dist/beacon.d.ts.map +1 -0
- package/dist/beacon.js +197 -0
- package/dist/beacon.js.map +1 -0
- package/dist/counter.d.ts +37 -0
- package/dist/counter.d.ts.map +1 -0
- package/dist/counter.js +62 -0
- package/dist/counter.js.map +1 -0
- package/dist/crypto.d.ts +111 -0
- package/dist/crypto.d.ts.map +1 -0
- package/dist/crypto.js +309 -0
- package/dist/crypto.js.map +1 -0
- package/dist/derive.d.ts +68 -0
- package/dist/derive.d.ts.map +1 -0
- package/dist/derive.js +85 -0
- package/dist/derive.js.map +1 -0
- package/dist/encoding.d.ts +56 -0
- package/dist/encoding.d.ts.map +1 -0
- package/dist/encoding.js +98 -0
- package/dist/encoding.js.map +1 -0
- package/dist/group.d.ts +185 -0
- package/dist/group.d.ts.map +1 -0
- package/dist/group.js +263 -0
- package/dist/group.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/nostr.d.ts +134 -0
- package/dist/nostr.d.ts.map +1 -0
- package/dist/nostr.js +175 -0
- package/dist/nostr.js.map +1 -0
- package/dist/presets.d.ts +26 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +39 -0
- package/dist/presets.js.map +1 -0
- package/dist/session.d.ts +114 -0
- package/dist/session.d.ts.map +1 -0
- package/dist/session.js +173 -0
- package/dist/session.js.map +1 -0
- package/dist/sync-crypto.d.ts +66 -0
- package/dist/sync-crypto.d.ts.map +1 -0
- package/dist/sync-crypto.js +125 -0
- package/dist/sync-crypto.js.map +1 -0
- package/dist/sync.d.ts +191 -0
- package/dist/sync.d.ts.map +1 -0
- package/dist/sync.js +568 -0
- package/dist/sync.js.map +1 -0
- package/dist/token.d.ts +186 -0
- package/dist/token.d.ts.map +1 -0
- package/dist/token.js +344 -0
- package/dist/token.js.map +1 -0
- package/dist/verify.d.ts +45 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +59 -0
- package/dist/verify.js.map +1 -0
- package/dist/wordlist.d.ts +28 -0
- package/dist/wordlist.d.ts.map +1 -0
- package/dist/wordlist.js +297 -0
- package/dist/wordlist.js.map +1 -0
- package/llms-full.txt +1461 -0
- package/llms.txt +180 -0
- package/package.json +144 -0
package/dist/counter.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { sha256 } from './crypto.js';
|
|
2
|
+
/** Default rotation interval: 7 days in seconds. */
|
|
3
|
+
export const DEFAULT_ROTATION_INTERVAL = 604_800;
|
|
4
|
+
/**
|
|
5
|
+
* Maximum allowed usage offset above the current time-based counter.
|
|
6
|
+
* Implementations MUST reject counter updates where effective counter > time-based counter + MAX_COUNTER_OFFSET.
|
|
7
|
+
* See CANARY spec §Counter Acceptance.
|
|
8
|
+
*/
|
|
9
|
+
export const MAX_COUNTER_OFFSET = 100;
|
|
10
|
+
/**
|
|
11
|
+
* Derive the current counter from a unix timestamp and rotation interval.
|
|
12
|
+
* Counter = floor(timestamp / interval).
|
|
13
|
+
*
|
|
14
|
+
* @param timestampSec - Unix timestamp in seconds (non-negative finite number).
|
|
15
|
+
* @param rotationIntervalSec - Rotation interval in seconds (positive finite number, default: 604800 = 7 days).
|
|
16
|
+
* @returns Integer counter value within uint32 range.
|
|
17
|
+
* @throws {RangeError} If timestampSec is negative/non-finite, rotationIntervalSec is non-positive/non-finite, or counter exceeds uint32.
|
|
18
|
+
*/
|
|
19
|
+
export function getCounter(timestampSec, rotationIntervalSec = DEFAULT_ROTATION_INTERVAL) {
|
|
20
|
+
if (!Number.isFinite(timestampSec) || timestampSec < 0) {
|
|
21
|
+
throw new RangeError(`timestampSec must be a non-negative finite number, got ${timestampSec}`);
|
|
22
|
+
}
|
|
23
|
+
if (!Number.isFinite(rotationIntervalSec) || rotationIntervalSec <= 0) {
|
|
24
|
+
throw new RangeError(`rotationIntervalSec must be a positive finite number, got ${rotationIntervalSec}`);
|
|
25
|
+
}
|
|
26
|
+
const result = Math.floor(timestampSec / rotationIntervalSec);
|
|
27
|
+
if (result > 0xFFFFFFFF) {
|
|
28
|
+
throw new RangeError(`Counter exceeds uint32 range (${result}). Use a larger rotation interval.`);
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Derive a counter from an event identifier (e.g. a task ID or Nostr event ID).
|
|
34
|
+
* Uses SHA-256 truncated to 32 bits for a deterministic, uniformly distributed counter.
|
|
35
|
+
* Per CANARY spec §Counter Schemes: event-based counters are deterministic from event ID.
|
|
36
|
+
*
|
|
37
|
+
* @param eventId - String identifier to derive the counter from (e.g. a Nostr event ID).
|
|
38
|
+
* @returns Unsigned 32-bit integer derived from SHA-256 of the event ID.
|
|
39
|
+
*/
|
|
40
|
+
export function counterFromEventId(eventId) {
|
|
41
|
+
const hash = sha256(new TextEncoder().encode(eventId));
|
|
42
|
+
// Read first 4 bytes as unsigned 32-bit big-endian integer
|
|
43
|
+
return (hash[0] << 24 | hash[1] << 16 | hash[2] << 8 | hash[3]) >>> 0;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Serialise a counter to an 8-byte big-endian Uint8Array.
|
|
47
|
+
* Same encoding as TOTP (RFC 6238).
|
|
48
|
+
*
|
|
49
|
+
* @param counter - Non-negative safe integer to serialise.
|
|
50
|
+
* @returns 8-byte big-endian Uint8Array representation of the counter.
|
|
51
|
+
* @throws {RangeError} If counter is negative, not an integer, or exceeds Number.MAX_SAFE_INTEGER.
|
|
52
|
+
*/
|
|
53
|
+
export function counterToBytes(counter) {
|
|
54
|
+
if (!Number.isInteger(counter) || counter < 0 || counter > Number.MAX_SAFE_INTEGER) {
|
|
55
|
+
throw new RangeError(`Counter must be a non-negative safe integer, got ${counter}`);
|
|
56
|
+
}
|
|
57
|
+
const buf = new Uint8Array(8);
|
|
58
|
+
const view = new DataView(buf.buffer);
|
|
59
|
+
view.setBigUint64(0, BigInt(counter), false); // false = big-endian
|
|
60
|
+
return buf;
|
|
61
|
+
}
|
|
62
|
+
//# sourceMappingURL=counter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counter.js","sourceRoot":"","sources":["../src/counter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAEpC,oDAAoD;AACpD,MAAM,CAAC,MAAM,yBAAyB,GAAG,OAAO,CAAA;AAEhD;;;;GAIG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,GAAG,CAAA;AAErC;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU,CACxB,YAAoB,EACpB,sBAA8B,yBAAyB;IAEvD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,YAAY,CAAC,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,UAAU,CAAC,0DAA0D,YAAY,EAAE,CAAC,CAAA;IAChG,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,mBAAmB,CAAC,IAAI,mBAAmB,IAAI,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,UAAU,CAAC,6DAA6D,mBAAmB,EAAE,CAAC,CAAA;IAC1G,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,GAAG,mBAAmB,CAAC,CAAA;IAC7D,IAAI,MAAM,GAAG,UAAU,EAAE,CAAC;QACxB,MAAM,IAAI,UAAU,CAAC,iCAAiC,MAAM,oCAAoC,CAAC,CAAA;IACnG,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe;IAChD,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;IACtD,2DAA2D;IAC3D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;AACvE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,OAAe;IAC5C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,IAAI,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACnF,MAAM,IAAI,UAAU,CAAC,oDAAoD,OAAO,EAAE,CAAC,CAAA;IACrF,CAAC;IACD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAA;IAC7B,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAA;IACrC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAA,CAAC,qBAAqB;IAClE,OAAO,GAAG,CAAA;AACZ,CAAC"}
|
package/dist/crypto.d.ts
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal synchronous crypto primitives — Node.js and browser compatible.
|
|
3
|
+
*
|
|
4
|
+
* SHA-256: FIPS 180-4
|
|
5
|
+
* HMAC: RFC 2104
|
|
6
|
+
*
|
|
7
|
+
* Uses only Uint8Array and the global `crypto` object (Web Crypto API).
|
|
8
|
+
* No async, no Web Crypto subtle API, no Buffer.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Compute SHA-256 of `data`.
|
|
12
|
+
* Implements FIPS 180-4 sections 5 (padding), 6.2 (hash computation).
|
|
13
|
+
*
|
|
14
|
+
* @param data - Input bytes to hash.
|
|
15
|
+
* @returns 32-byte SHA-256 digest.
|
|
16
|
+
*/
|
|
17
|
+
export declare function sha256(data: Uint8Array): Uint8Array;
|
|
18
|
+
/**
|
|
19
|
+
* Compute HMAC-SHA256(key, data) and return the raw 32-byte digest.
|
|
20
|
+
*
|
|
21
|
+
* RFC 2104:
|
|
22
|
+
* H(K XOR opad, H(K XOR ipad, data))
|
|
23
|
+
* ipad = 0x36 repeated, opad = 0x5c repeated.
|
|
24
|
+
* Keys longer than the block size are hashed first.
|
|
25
|
+
* Keys shorter than the block size are zero-padded on the right.
|
|
26
|
+
*
|
|
27
|
+
* @param key - HMAC key bytes (hashed if longer than 64 bytes, zero-padded if shorter).
|
|
28
|
+
* @param data - Input data bytes.
|
|
29
|
+
* @returns 32-byte HMAC-SHA256 digest.
|
|
30
|
+
*/
|
|
31
|
+
export declare function hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;
|
|
32
|
+
/**
|
|
33
|
+
* Generate a cryptographically secure 32-byte seed as a 64-character hex string.
|
|
34
|
+
* Uses the global `crypto.getRandomValues` (Web Crypto API).
|
|
35
|
+
*
|
|
36
|
+
* @returns 64-character lowercase hex string (32 random bytes).
|
|
37
|
+
*/
|
|
38
|
+
export declare function randomSeed(): string;
|
|
39
|
+
/**
|
|
40
|
+
* Convert a hex string to a Uint8Array. Replaces `Buffer.from(hex, 'hex')`.
|
|
41
|
+
*
|
|
42
|
+
* @param hex - Even-length hex string (case-insensitive).
|
|
43
|
+
* @returns Decoded byte array.
|
|
44
|
+
* @throws {Error} If hex has odd length.
|
|
45
|
+
* @throws {TypeError} If hex contains invalid characters.
|
|
46
|
+
*/
|
|
47
|
+
export declare function hexToBytes(hex: string): Uint8Array;
|
|
48
|
+
/**
|
|
49
|
+
* Convert a Uint8Array to a lowercase hex string. Replaces `buffer.toString('hex')`.
|
|
50
|
+
*
|
|
51
|
+
* @param bytes - Input byte array.
|
|
52
|
+
* @returns Lowercase hex string (2 characters per byte).
|
|
53
|
+
*/
|
|
54
|
+
export declare function bytesToHex(bytes: Uint8Array): string;
|
|
55
|
+
/**
|
|
56
|
+
* Read an unsigned 16-bit big-endian integer from `bytes` at `offset`.
|
|
57
|
+
* Replaces `buffer.readUInt16BE(offset)`.
|
|
58
|
+
*
|
|
59
|
+
* @param bytes - Source byte array.
|
|
60
|
+
* @param offset - Byte offset to read from.
|
|
61
|
+
* @returns Unsigned 16-bit integer value.
|
|
62
|
+
* @throws {RangeError} If offset is out of bounds.
|
|
63
|
+
*/
|
|
64
|
+
export declare function readUint16BE(bytes: Uint8Array, offset: number): number;
|
|
65
|
+
/**
|
|
66
|
+
* Concatenate multiple Uint8Arrays into one.
|
|
67
|
+
* Replaces `Buffer.concat([...])`.
|
|
68
|
+
*
|
|
69
|
+
* @param arrays - One or more Uint8Arrays to concatenate.
|
|
70
|
+
* @returns A single Uint8Array containing all input bytes in order.
|
|
71
|
+
*/
|
|
72
|
+
export declare function concatBytes(...arrays: Uint8Array[]): Uint8Array;
|
|
73
|
+
/**
|
|
74
|
+
* Encode a Uint8Array as a base64 string. Available in Node 16+ and all browsers.
|
|
75
|
+
*
|
|
76
|
+
* @param bytes - Input byte array.
|
|
77
|
+
* @returns Base64-encoded string.
|
|
78
|
+
*/
|
|
79
|
+
export declare function bytesToBase64(bytes: Uint8Array): string;
|
|
80
|
+
/**
|
|
81
|
+
* Decode a base64 string to a Uint8Array.
|
|
82
|
+
*
|
|
83
|
+
* @param base64 - Base64-encoded string.
|
|
84
|
+
* @returns Decoded byte array.
|
|
85
|
+
*/
|
|
86
|
+
export declare function base64ToBytes(base64: string): Uint8Array;
|
|
87
|
+
/**
|
|
88
|
+
* Best-effort constant-time comparison of two byte arrays.
|
|
89
|
+
* Pads both arrays to equal length to avoid leaking length via timing.
|
|
90
|
+
*
|
|
91
|
+
* **Caveat:** JavaScript runtimes do not guarantee constant-time execution —
|
|
92
|
+
* JIT compilation and speculative execution may introduce timing variation.
|
|
93
|
+
* This is a defence-in-depth measure, not a cryptographic guarantee. For
|
|
94
|
+
* high-assurance environments, pair with rate limiting and consider
|
|
95
|
+
* platform-native constant-time primitives.
|
|
96
|
+
*
|
|
97
|
+
* @param a - First byte array.
|
|
98
|
+
* @param b - Second byte array.
|
|
99
|
+
* @returns `true` if arrays are equal in length and content, `false` otherwise.
|
|
100
|
+
*/
|
|
101
|
+
export declare function timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Best-effort constant-time comparison of two strings (UTF-8 encoded, then byte-compared).
|
|
104
|
+
* See {@link timingSafeEqual} caveats.
|
|
105
|
+
*
|
|
106
|
+
* @param a - First string.
|
|
107
|
+
* @param b - Second string.
|
|
108
|
+
* @returns `true` if strings are equal, `false` otherwise.
|
|
109
|
+
*/
|
|
110
|
+
export declare function timingSafeStringEqual(a: string, b: string): boolean;
|
|
111
|
+
//# sourceMappingURL=crypto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.d.ts","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAqCH;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,UAAU,CAiFnD;AAQD;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,IAAI,EAAE,UAAU,GAAG,UAAU,CA6BxE;AAMD;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAInC;AAMD;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CAWlD;AAED;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAMpD;AAED;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGtE;AAED;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,GAAG,MAAM,EAAE,UAAU,EAAE,GAAG,UAAU,CAS/D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAIvD;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAKxD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,UAAU,GAAG,OAAO,CAYrE;AAID;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEnE"}
|
package/dist/crypto.js
ADDED
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Universal synchronous crypto primitives — Node.js and browser compatible.
|
|
3
|
+
*
|
|
4
|
+
* SHA-256: FIPS 180-4
|
|
5
|
+
* HMAC: RFC 2104
|
|
6
|
+
*
|
|
7
|
+
* Uses only Uint8Array and the global `crypto` object (Web Crypto API).
|
|
8
|
+
* No async, no Web Crypto subtle API, no Buffer.
|
|
9
|
+
*/
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// SHA-256 — FIPS 180-4
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/** Initial hash values H0–H7 (first 32 bits of fractional parts of sqrt of first 8 primes). */
|
|
14
|
+
const H0 = [
|
|
15
|
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
|
16
|
+
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19,
|
|
17
|
+
];
|
|
18
|
+
/** Round constants K[0..63] (first 32 bits of fractional parts of cbrt of first 64 primes). */
|
|
19
|
+
const K = new Uint32Array([
|
|
20
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
|
21
|
+
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
22
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
|
23
|
+
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
24
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
|
25
|
+
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
26
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
|
27
|
+
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
28
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
|
29
|
+
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
30
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
|
31
|
+
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
32
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
|
33
|
+
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
34
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
|
35
|
+
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2,
|
|
36
|
+
]);
|
|
37
|
+
/** Rotate-right a 32-bit integer by n bits. */
|
|
38
|
+
function rotr32(x, n) {
|
|
39
|
+
return ((x >>> n) | (x << (32 - n))) >>> 0;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Compute SHA-256 of `data`.
|
|
43
|
+
* Implements FIPS 180-4 sections 5 (padding), 6.2 (hash computation).
|
|
44
|
+
*
|
|
45
|
+
* @param data - Input bytes to hash.
|
|
46
|
+
* @returns 32-byte SHA-256 digest.
|
|
47
|
+
*/
|
|
48
|
+
export function sha256(data) {
|
|
49
|
+
// --- Pre-processing: padding (FIPS 180-4 §5.1.1) ---
|
|
50
|
+
const bitLen = data.length * 8;
|
|
51
|
+
// Append 0x80, then zero bytes, then 8-byte big-endian bit-length.
|
|
52
|
+
// Total padded length must be a multiple of 64 bytes (512 bits).
|
|
53
|
+
// After the message and 0x80 byte we need at least 8 bytes for the length,
|
|
54
|
+
// so we pad to the next multiple of 64 that satisfies this.
|
|
55
|
+
const padded = new Uint8Array(Math.ceil((data.length + 9) / 64) * 64);
|
|
56
|
+
padded.set(data);
|
|
57
|
+
padded[data.length] = 0x80;
|
|
58
|
+
// Write 64-bit big-endian bit length at the end.
|
|
59
|
+
// bitLen fits in a 53-bit JS number so we can split safely.
|
|
60
|
+
const view = new DataView(padded.buffer);
|
|
61
|
+
view.setUint32(padded.length - 8, Math.floor(bitLen / 0x100000000), false);
|
|
62
|
+
view.setUint32(padded.length - 4, bitLen >>> 0, false);
|
|
63
|
+
// --- Processing blocks (FIPS 180-4 §6.2.2) ---
|
|
64
|
+
// Working variables
|
|
65
|
+
let [h0, h1, h2, h3, h4, h5, h6, h7] = H0;
|
|
66
|
+
const W = new Uint32Array(64);
|
|
67
|
+
for (let offset = 0; offset < padded.length; offset += 64) {
|
|
68
|
+
// Prepare message schedule W[0..63]
|
|
69
|
+
for (let t = 0; t < 16; t++) {
|
|
70
|
+
W[t] = view.getUint32(offset + t * 4, false);
|
|
71
|
+
}
|
|
72
|
+
for (let t = 16; t < 64; t++) {
|
|
73
|
+
const w15 = W[t - 15];
|
|
74
|
+
const w2 = W[t - 2];
|
|
75
|
+
const s0 = rotr32(w15, 7) ^ rotr32(w15, 18) ^ (w15 >>> 3);
|
|
76
|
+
const s1 = rotr32(w2, 17) ^ rotr32(w2, 19) ^ (w2 >>> 10);
|
|
77
|
+
W[t] = (W[t - 16] + s0 + W[t - 7] + s1) >>> 0;
|
|
78
|
+
}
|
|
79
|
+
// Initialise working variables
|
|
80
|
+
let a = h0, b = h1, c = h2, d = h3;
|
|
81
|
+
let e = h4, f = h5, g = h6, hh = h7;
|
|
82
|
+
// 64 rounds
|
|
83
|
+
for (let t = 0; t < 64; t++) {
|
|
84
|
+
const S1 = rotr32(e, 6) ^ rotr32(e, 11) ^ rotr32(e, 25);
|
|
85
|
+
const ch = (e & f) ^ (~e & g);
|
|
86
|
+
const tmp1 = (hh + S1 + ch + K[t] + W[t]) >>> 0;
|
|
87
|
+
const S0 = rotr32(a, 2) ^ rotr32(a, 13) ^ rotr32(a, 22);
|
|
88
|
+
const maj = (a & b) ^ (a & c) ^ (b & c);
|
|
89
|
+
const tmp2 = (S0 + maj) >>> 0;
|
|
90
|
+
hh = g;
|
|
91
|
+
g = f;
|
|
92
|
+
f = e;
|
|
93
|
+
e = (d + tmp1) >>> 0;
|
|
94
|
+
d = c;
|
|
95
|
+
c = b;
|
|
96
|
+
b = a;
|
|
97
|
+
a = (tmp1 + tmp2) >>> 0;
|
|
98
|
+
}
|
|
99
|
+
// Add the compressed chunk to the current hash value
|
|
100
|
+
h0 = (h0 + a) >>> 0;
|
|
101
|
+
h1 = (h1 + b) >>> 0;
|
|
102
|
+
h2 = (h2 + c) >>> 0;
|
|
103
|
+
h3 = (h3 + d) >>> 0;
|
|
104
|
+
h4 = (h4 + e) >>> 0;
|
|
105
|
+
h5 = (h5 + f) >>> 0;
|
|
106
|
+
h6 = (h6 + g) >>> 0;
|
|
107
|
+
h7 = (h7 + hh) >>> 0;
|
|
108
|
+
}
|
|
109
|
+
// Produce the final hash value (big-endian)
|
|
110
|
+
const digest = new Uint8Array(32);
|
|
111
|
+
const dv = new DataView(digest.buffer);
|
|
112
|
+
dv.setUint32(0, h0, false);
|
|
113
|
+
dv.setUint32(4, h1, false);
|
|
114
|
+
dv.setUint32(8, h2, false);
|
|
115
|
+
dv.setUint32(12, h3, false);
|
|
116
|
+
dv.setUint32(16, h4, false);
|
|
117
|
+
dv.setUint32(20, h5, false);
|
|
118
|
+
dv.setUint32(24, h6, false);
|
|
119
|
+
dv.setUint32(28, h7, false);
|
|
120
|
+
return digest;
|
|
121
|
+
}
|
|
122
|
+
// ---------------------------------------------------------------------------
|
|
123
|
+
// HMAC-SHA256 — RFC 2104
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
const BLOCK_SIZE = 64; // SHA-256 block size in bytes
|
|
126
|
+
/**
|
|
127
|
+
* Compute HMAC-SHA256(key, data) and return the raw 32-byte digest.
|
|
128
|
+
*
|
|
129
|
+
* RFC 2104:
|
|
130
|
+
* H(K XOR opad, H(K XOR ipad, data))
|
|
131
|
+
* ipad = 0x36 repeated, opad = 0x5c repeated.
|
|
132
|
+
* Keys longer than the block size are hashed first.
|
|
133
|
+
* Keys shorter than the block size are zero-padded on the right.
|
|
134
|
+
*
|
|
135
|
+
* @param key - HMAC key bytes (hashed if longer than 64 bytes, zero-padded if shorter).
|
|
136
|
+
* @param data - Input data bytes.
|
|
137
|
+
* @returns 32-byte HMAC-SHA256 digest.
|
|
138
|
+
*/
|
|
139
|
+
export function hmacSha256(key, data) {
|
|
140
|
+
// If the key is longer than the block size, hash it first.
|
|
141
|
+
const normalised = key.length > BLOCK_SIZE ? sha256(key) : key;
|
|
142
|
+
// Pad/extend to block size.
|
|
143
|
+
const k = new Uint8Array(BLOCK_SIZE);
|
|
144
|
+
k.set(normalised);
|
|
145
|
+
// Build inner and outer padded keys.
|
|
146
|
+
const ipad = new Uint8Array(BLOCK_SIZE);
|
|
147
|
+
const opad = new Uint8Array(BLOCK_SIZE);
|
|
148
|
+
for (let i = 0; i < BLOCK_SIZE; i++) {
|
|
149
|
+
ipad[i] = k[i] ^ 0x36;
|
|
150
|
+
opad[i] = k[i] ^ 0x5c;
|
|
151
|
+
}
|
|
152
|
+
// inner = sha256(ipad || data)
|
|
153
|
+
const inner = sha256(concatBytes(ipad, data));
|
|
154
|
+
// outer = sha256(opad || inner)
|
|
155
|
+
const result = sha256(concatBytes(opad, inner));
|
|
156
|
+
// Best-effort zeroing of key material and intermediate state
|
|
157
|
+
k.fill(0);
|
|
158
|
+
ipad.fill(0);
|
|
159
|
+
opad.fill(0);
|
|
160
|
+
inner.fill(0);
|
|
161
|
+
return result;
|
|
162
|
+
}
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Random seed
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
/**
|
|
167
|
+
* Generate a cryptographically secure 32-byte seed as a 64-character hex string.
|
|
168
|
+
* Uses the global `crypto.getRandomValues` (Web Crypto API).
|
|
169
|
+
*
|
|
170
|
+
* @returns 64-character lowercase hex string (32 random bytes).
|
|
171
|
+
*/
|
|
172
|
+
export function randomSeed() {
|
|
173
|
+
const bytes = new Uint8Array(32);
|
|
174
|
+
crypto.getRandomValues(bytes);
|
|
175
|
+
return bytesToHex(bytes);
|
|
176
|
+
}
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// Byte / hex utilities
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
/**
|
|
181
|
+
* Convert a hex string to a Uint8Array. Replaces `Buffer.from(hex, 'hex')`.
|
|
182
|
+
*
|
|
183
|
+
* @param hex - Even-length hex string (case-insensitive).
|
|
184
|
+
* @returns Decoded byte array.
|
|
185
|
+
* @throws {Error} If hex has odd length.
|
|
186
|
+
* @throws {TypeError} If hex contains invalid characters.
|
|
187
|
+
*/
|
|
188
|
+
export function hexToBytes(hex) {
|
|
189
|
+
if (hex.length % 2 !== 0) {
|
|
190
|
+
throw new Error(`hexToBytes: odd-length hex string (${hex.length} chars)`);
|
|
191
|
+
}
|
|
192
|
+
const bytes = new Uint8Array(hex.length / 2);
|
|
193
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
194
|
+
const pair = hex.slice(i * 2, i * 2 + 2);
|
|
195
|
+
if (!/^[0-9a-fA-F]{2}$/.test(pair))
|
|
196
|
+
throw new TypeError(`Invalid hex character at position ${i * 2}`);
|
|
197
|
+
bytes[i] = parseInt(pair, 16);
|
|
198
|
+
}
|
|
199
|
+
return bytes;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Convert a Uint8Array to a lowercase hex string. Replaces `buffer.toString('hex')`.
|
|
203
|
+
*
|
|
204
|
+
* @param bytes - Input byte array.
|
|
205
|
+
* @returns Lowercase hex string (2 characters per byte).
|
|
206
|
+
*/
|
|
207
|
+
export function bytesToHex(bytes) {
|
|
208
|
+
let hex = '';
|
|
209
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
210
|
+
hex += bytes[i].toString(16).padStart(2, '0');
|
|
211
|
+
}
|
|
212
|
+
return hex;
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Read an unsigned 16-bit big-endian integer from `bytes` at `offset`.
|
|
216
|
+
* Replaces `buffer.readUInt16BE(offset)`.
|
|
217
|
+
*
|
|
218
|
+
* @param bytes - Source byte array.
|
|
219
|
+
* @param offset - Byte offset to read from.
|
|
220
|
+
* @returns Unsigned 16-bit integer value.
|
|
221
|
+
* @throws {RangeError} If offset is out of bounds.
|
|
222
|
+
*/
|
|
223
|
+
export function readUint16BE(bytes, offset) {
|
|
224
|
+
if (offset < 0 || offset + 1 >= bytes.length)
|
|
225
|
+
throw new RangeError(`readUint16BE: offset ${offset} out of bounds for length ${bytes.length}`);
|
|
226
|
+
return ((bytes[offset] << 8) | bytes[offset + 1]) >>> 0;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Concatenate multiple Uint8Arrays into one.
|
|
230
|
+
* Replaces `Buffer.concat([...])`.
|
|
231
|
+
*
|
|
232
|
+
* @param arrays - One or more Uint8Arrays to concatenate.
|
|
233
|
+
* @returns A single Uint8Array containing all input bytes in order.
|
|
234
|
+
*/
|
|
235
|
+
export function concatBytes(...arrays) {
|
|
236
|
+
const total = arrays.reduce((n, a) => n + a.length, 0);
|
|
237
|
+
const out = new Uint8Array(total);
|
|
238
|
+
let offset = 0;
|
|
239
|
+
for (const arr of arrays) {
|
|
240
|
+
out.set(arr, offset);
|
|
241
|
+
offset += arr.length;
|
|
242
|
+
}
|
|
243
|
+
return out;
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Encode a Uint8Array as a base64 string. Available in Node 16+ and all browsers.
|
|
247
|
+
*
|
|
248
|
+
* @param bytes - Input byte array.
|
|
249
|
+
* @returns Base64-encoded string.
|
|
250
|
+
*/
|
|
251
|
+
export function bytesToBase64(bytes) {
|
|
252
|
+
let binary = '';
|
|
253
|
+
for (let i = 0; i < bytes.length; i++)
|
|
254
|
+
binary += String.fromCharCode(bytes[i]);
|
|
255
|
+
return btoa(binary);
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Decode a base64 string to a Uint8Array.
|
|
259
|
+
*
|
|
260
|
+
* @param base64 - Base64-encoded string.
|
|
261
|
+
* @returns Decoded byte array.
|
|
262
|
+
*/
|
|
263
|
+
export function base64ToBytes(base64) {
|
|
264
|
+
const binary = atob(base64);
|
|
265
|
+
const bytes = new Uint8Array(binary.length);
|
|
266
|
+
for (let i = 0; i < binary.length; i++)
|
|
267
|
+
bytes[i] = binary.charCodeAt(i);
|
|
268
|
+
return bytes;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Best-effort constant-time comparison of two byte arrays.
|
|
272
|
+
* Pads both arrays to equal length to avoid leaking length via timing.
|
|
273
|
+
*
|
|
274
|
+
* **Caveat:** JavaScript runtimes do not guarantee constant-time execution —
|
|
275
|
+
* JIT compilation and speculative execution may introduce timing variation.
|
|
276
|
+
* This is a defence-in-depth measure, not a cryptographic guarantee. For
|
|
277
|
+
* high-assurance environments, pair with rate limiting and consider
|
|
278
|
+
* platform-native constant-time primitives.
|
|
279
|
+
*
|
|
280
|
+
* @param a - First byte array.
|
|
281
|
+
* @param b - Second byte array.
|
|
282
|
+
* @returns `true` if arrays are equal in length and content, `false` otherwise.
|
|
283
|
+
*/
|
|
284
|
+
export function timingSafeEqual(a, b) {
|
|
285
|
+
const len = Math.max(a.length, b.length);
|
|
286
|
+
// Pre-allocate zero-padded copies to eliminate branch in the comparison loop
|
|
287
|
+
const paddedA = new Uint8Array(len);
|
|
288
|
+
const paddedB = new Uint8Array(len);
|
|
289
|
+
paddedA.set(a);
|
|
290
|
+
paddedB.set(b);
|
|
291
|
+
let diff = a.length ^ b.length; // non-zero if lengths differ
|
|
292
|
+
for (let i = 0; i < len; i++) {
|
|
293
|
+
diff |= paddedA[i] ^ paddedB[i];
|
|
294
|
+
}
|
|
295
|
+
return diff === 0;
|
|
296
|
+
}
|
|
297
|
+
const stringEncoder = new TextEncoder();
|
|
298
|
+
/**
|
|
299
|
+
* Best-effort constant-time comparison of two strings (UTF-8 encoded, then byte-compared).
|
|
300
|
+
* See {@link timingSafeEqual} caveats.
|
|
301
|
+
*
|
|
302
|
+
* @param a - First string.
|
|
303
|
+
* @param b - Second string.
|
|
304
|
+
* @returns `true` if strings are equal, `false` otherwise.
|
|
305
|
+
*/
|
|
306
|
+
export function timingSafeStringEqual(a, b) {
|
|
307
|
+
return timingSafeEqual(stringEncoder.encode(a), stringEncoder.encode(b));
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=crypto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crypto.js","sourceRoot":"","sources":["../src/crypto.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E,+FAA+F;AAC/F,MAAM,EAAE,GAAsB;IAC5B,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/C,CAAA;AAED,+FAA+F;AAC/F,MAAM,CAAC,GAAG,IAAI,WAAW,CAAC;IACxB,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;IAC9C,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU;CAC/C,CAAC,CAAA;AAEF,+CAA+C;AAC/C,SAAS,MAAM,CAAC,CAAS,EAAE,CAAS;IAClC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;AAC5C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,IAAgB;IACrC,sDAAsD;IACtD,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,CAAA;IAC9B,mEAAmE;IACnE,iEAAiE;IACjE,2EAA2E;IAC3E,4DAA4D;IAC5D,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAA;IACrE,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChB,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAA;IAC1B,iDAAiD;IACjD,4DAA4D;IAC5D,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACxC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,WAAW,CAAC,EAAE,KAAK,CAAC,CAAA;IAC1E,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,KAAK,CAAC,EAAE,KAAK,CAAC,CAAA;IAEtD,gDAAgD;IAChD,oBAAoB;IACpB,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,GAAG,EAAE,CAAA;IAEzC,MAAM,CAAC,GAAG,IAAI,WAAW,CAAC,EAAE,CAAC,CAAA;IAE7B,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,EAAE,EAAE,CAAC;QAC1D,oCAAoC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAA;QAC9C,CAAC;QACD,KAAK,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAA;YACrB,MAAM,EAAE,GAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YACpB,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,CAAA;YACzD,MAAM,EAAE,GAAG,MAAM,CAAC,EAAE,EAAG,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,EAAG,EAAE,CAAC,GAAG,CAAC,EAAE,KAAM,EAAE,CAAC,CAAA;YAC3D,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;QAC/C,CAAC;QAED,+BAA+B;QAC/B,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,CAAA;QAClC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,EAAE,CAAA;QAEnC,YAAY;QACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,EAAE,GAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;YACxD,MAAM,EAAE,GAAI,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YAC9B,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;YAC/C,MAAM,EAAE,GAAI,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;YACxD,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;YACvC,MAAM,IAAI,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,KAAK,CAAC,CAAA;YAE7B,EAAE,GAAG,CAAC,CAAA;YACN,CAAC,GAAI,CAAC,CAAA;YACN,CAAC,GAAI,CAAC,CAAA;YACN,CAAC,GAAI,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;YACrB,CAAC,GAAI,CAAC,CAAA;YACN,CAAC,GAAI,CAAC,CAAA;YACN,CAAC,GAAI,CAAC,CAAA;YACN,CAAC,GAAI,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAA;QAC1B,CAAC;QAED,qDAAqD;QACrD,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QACnB,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QACnB,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QACnB,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QACnB,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QACnB,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QACnB,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAA;QACnB,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,CAAC,CAAA;IACtB,CAAC;IAED,4CAA4C;IAC5C,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IACjC,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IACtC,EAAE,CAAC,SAAS,CAAC,CAAC,EAAG,EAAE,EAAE,KAAK,CAAC,CAAA;IAC3B,EAAE,CAAC,SAAS,CAAC,CAAC,EAAG,EAAE,EAAE,KAAK,CAAC,CAAA;IAC3B,EAAE,CAAC,SAAS,CAAC,CAAC,EAAG,EAAE,EAAE,KAAK,CAAC,CAAA;IAC3B,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAA;IAC3B,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAA;IAC3B,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAA;IAC3B,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAA;IAC3B,EAAE,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,CAAC,CAAA;IAC3B,OAAO,MAAM,CAAA;AACf,CAAC;AAED,8EAA8E;AAC9E,yBAAyB;AACzB,8EAA8E;AAE9E,MAAM,UAAU,GAAG,EAAE,CAAA,CAAC,8BAA8B;AAEpD;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,GAAe,EAAE,IAAgB;IAC1D,2DAA2D;IAC3D,MAAM,UAAU,GAAG,GAAG,CAAC,MAAM,GAAG,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAA;IAE9D,4BAA4B;IAC5B,MAAM,CAAC,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAA;IACpC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IAEjB,qCAAqC;IACrC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAA;IACvC,MAAM,IAAI,GAAG,IAAI,UAAU,CAAC,UAAU,CAAC,CAAA;IACvC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,UAAU,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;QACrB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAA;IACvB,CAAC;IAED,+BAA+B;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,CAAA;IAE7C,gCAAgC;IAChC,MAAM,MAAM,GAAG,MAAM,CAAC,WAAW,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAA;IAE/C,6DAA6D;IAC7D,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACT,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACZ,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACZ,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IAEb,OAAO,MAAM,CAAA;AACf,CAAC;AAED,8EAA8E;AAC9E,cAAc;AACd,8EAA8E;AAE9E;;;;;GAKG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAA;IAChC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAA;IAC7B,OAAO,UAAU,CAAC,KAAK,CAAC,CAAA;AAC1B,CAAC;AAED,8EAA8E;AAC9E,uBAAuB;AACvB,8EAA8E;AAE9E;;;;;;;GAOG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACpC,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,sCAAsC,GAAG,CAAC,MAAM,SAAS,CAAC,CAAA;IAC5E,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,CAAC,CAAA;IAC5C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;QACxC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,SAAS,CAAC,qCAAqC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;QACrG,KAAK,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC,CAAA;IAC/B,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAA;IAC/C,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,YAAY,CAAC,KAAiB,EAAE,MAAc;IAC5D,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM;QAAE,MAAM,IAAI,UAAU,CAAC,wBAAwB,MAAM,6BAA6B,KAAK,CAAC,MAAM,EAAE,CAAC,CAAA;IAC7I,OAAO,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;AACzD,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,GAAG,MAAoB;IACjD,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAA;IACtD,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,KAAK,CAAC,CAAA;IACjC,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QACpB,MAAM,IAAI,GAAG,CAAC,MAAM,CAAA;IACtB,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,KAAiB;IAC7C,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAA;IAC9E,OAAO,IAAI,CAAC,MAAM,CAAC,CAAA;AACrB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,MAAc;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAA;IAC3B,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAA;IAC3C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;IACvE,OAAO,KAAK,CAAA;AACd,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,eAAe,CAAC,CAAa,EAAE,CAAa;IAC1D,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAA;IACxC,6EAA6E;IAC7E,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAA;IACnC,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,GAAG,CAAC,CAAA;IACnC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACd,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA;IACd,IAAI,IAAI,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAA,CAAC,6BAA6B;IAC5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAA;IACjC,CAAC;IACD,OAAO,IAAI,KAAK,CAAC,CAAA;AACnB,CAAC;AAED,MAAM,aAAa,GAAG,IAAI,WAAW,EAAE,CAAA;AAEvC;;;;;;;GAOG;AACH,MAAM,UAAU,qBAAqB,CAAC,CAAS,EAAE,CAAS;IACxD,OAAO,eAAe,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAA;AAC1E,CAAC"}
|
package/dist/derive.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group-level word derivation — thin wrappers around the universal token API.
|
|
3
|
+
*
|
|
4
|
+
* All derivation uses token.ts (CANARY-DERIVE) with context 'canary:group'.
|
|
5
|
+
* This module provides convenience functions for group word/phrase operations.
|
|
6
|
+
*/
|
|
7
|
+
/** Context string used for group-level word derivation. */
|
|
8
|
+
export declare const GROUP_CONTEXT = "canary:group";
|
|
9
|
+
/**
|
|
10
|
+
* Derive the verification word for a given seed and counter.
|
|
11
|
+
* All group members derive the same word.
|
|
12
|
+
*
|
|
13
|
+
* @param seedHex - Group seed as a hex string (minimum 32 hex characters / 16 bytes).
|
|
14
|
+
* @param counter - Current time-based or usage counter.
|
|
15
|
+
* @returns A single lowercase word from the en-v1 wordlist.
|
|
16
|
+
*/
|
|
17
|
+
export declare function deriveVerificationWord(seedHex: string, counter: number): string;
|
|
18
|
+
/**
|
|
19
|
+
* Derive a multi-word verification phrase.
|
|
20
|
+
* Each word is derived from a consecutive 2-byte slice of the HMAC-SHA256 digest.
|
|
21
|
+
*
|
|
22
|
+
* @param seedHex - Group seed as a hex string (minimum 32 hex characters / 16 bytes).
|
|
23
|
+
* @param counter - Current time-based or usage counter.
|
|
24
|
+
* @param wordCount - Number of words to produce (1, 2, or 3).
|
|
25
|
+
* @returns Array of lowercase words from the en-v1 wordlist.
|
|
26
|
+
*/
|
|
27
|
+
export declare function deriveVerificationPhrase(seedHex: string, counter: number, wordCount: 1 | 2 | 3): string[];
|
|
28
|
+
/**
|
|
29
|
+
* Derive a member's duress word for a given seed, pubkey, and counter.
|
|
30
|
+
* Unique per member, derivable by all group members who know the seed.
|
|
31
|
+
* Collision avoidance ensures the duress word never matches any verification
|
|
32
|
+
* word within the ±(2 × maxTolerance) window.
|
|
33
|
+
*
|
|
34
|
+
* @param seedHex - Group seed as a hex string (minimum 32 hex characters / 16 bytes).
|
|
35
|
+
* @param memberPubkeyHex - 64-character hex pubkey of the member.
|
|
36
|
+
* @param counter - Current time-based or usage counter.
|
|
37
|
+
* @param maxTolerance - Counter tolerance used by verifiers (default: 1).
|
|
38
|
+
* @param identities - All group member pubkeys for cross-member collision avoidance.
|
|
39
|
+
* @returns A single lowercase duress word distinct from all verification words in the window.
|
|
40
|
+
* @throws {Error} If collision avoidance fails after 255 retries.
|
|
41
|
+
*/
|
|
42
|
+
export declare function deriveDuressWord(seedHex: string, memberPubkeyHex: string, counter: number, maxTolerance?: number, identities?: string[]): string;
|
|
43
|
+
/**
|
|
44
|
+
* Derive a multi-word duress phrase for a given member.
|
|
45
|
+
* Collision avoidance ensures the phrase never matches any verification
|
|
46
|
+
* phrase within the ±(2 × maxTolerance) window.
|
|
47
|
+
*
|
|
48
|
+
* @param seedHex - Group seed as a hex string (minimum 32 hex characters / 16 bytes).
|
|
49
|
+
* @param memberPubkeyHex - 64-character hex pubkey of the member.
|
|
50
|
+
* @param counter - Current time-based or usage counter.
|
|
51
|
+
* @param wordCount - Number of words to produce (1, 2, or 3).
|
|
52
|
+
* @param maxTolerance - Counter tolerance used by verifiers (default: 1).
|
|
53
|
+
* @param identities - All group member pubkeys for cross-member collision avoidance.
|
|
54
|
+
* @returns Array of lowercase duress words distinct from all verification phrases in the window.
|
|
55
|
+
* @throws {Error} If collision avoidance fails after 255 retries.
|
|
56
|
+
*/
|
|
57
|
+
export declare function deriveDuressPhrase(seedHex: string, memberPubkeyHex: string, counter: number, wordCount: 1 | 2 | 3, maxTolerance?: number, identities?: string[]): string[];
|
|
58
|
+
/**
|
|
59
|
+
* Derive the current verification word for a group.
|
|
60
|
+
*
|
|
61
|
+
* @param group - Object with `seed` (hex string) and `counter` (current counter value).
|
|
62
|
+
* @returns A single lowercase verification word from the en-v1 wordlist.
|
|
63
|
+
*/
|
|
64
|
+
export declare function deriveCurrentWord(group: {
|
|
65
|
+
seed: string;
|
|
66
|
+
counter: number;
|
|
67
|
+
}): string;
|
|
68
|
+
//# sourceMappingURL=derive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,2DAA2D;AAC3D,eAAO,MAAM,aAAa,iBAAiB,CAAA;AAS3C;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/E;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GACnB,MAAM,EAAE,CAGV;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,YAAY,GAAE,MAAgC,EAC9C,UAAU,CAAC,EAAE,MAAM,EAAE,GACpB,MAAM,CAER;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,MAAM,EACvB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,EACpB,YAAY,GAAE,MAAgC,EAC9C,UAAU,CAAC,EAAE,MAAM,EAAE,GACpB,MAAM,EAAE,CAGV;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAElF"}
|
package/dist/derive.js
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group-level word derivation — thin wrappers around the universal token API.
|
|
3
|
+
*
|
|
4
|
+
* All derivation uses token.ts (CANARY-DERIVE) with context 'canary:group'.
|
|
5
|
+
* This module provides convenience functions for group word/phrase operations.
|
|
6
|
+
*/
|
|
7
|
+
import { deriveToken, deriveDuressToken } from './token.js';
|
|
8
|
+
/** Context string used for group-level word derivation. */
|
|
9
|
+
export const GROUP_CONTEXT = 'canary:group';
|
|
10
|
+
/** Default tolerance for group verification (matches ±1 counter window). */
|
|
11
|
+
const DEFAULT_GROUP_TOLERANCE = 1;
|
|
12
|
+
function wordEncoding(wordCount) {
|
|
13
|
+
return { format: 'words', count: wordCount };
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Derive the verification word for a given seed and counter.
|
|
17
|
+
* All group members derive the same word.
|
|
18
|
+
*
|
|
19
|
+
* @param seedHex - Group seed as a hex string (minimum 32 hex characters / 16 bytes).
|
|
20
|
+
* @param counter - Current time-based or usage counter.
|
|
21
|
+
* @returns A single lowercase word from the en-v1 wordlist.
|
|
22
|
+
*/
|
|
23
|
+
export function deriveVerificationWord(seedHex, counter) {
|
|
24
|
+
return deriveToken(seedHex, GROUP_CONTEXT, counter);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Derive a multi-word verification phrase.
|
|
28
|
+
* Each word is derived from a consecutive 2-byte slice of the HMAC-SHA256 digest.
|
|
29
|
+
*
|
|
30
|
+
* @param seedHex - Group seed as a hex string (minimum 32 hex characters / 16 bytes).
|
|
31
|
+
* @param counter - Current time-based or usage counter.
|
|
32
|
+
* @param wordCount - Number of words to produce (1, 2, or 3).
|
|
33
|
+
* @returns Array of lowercase words from the en-v1 wordlist.
|
|
34
|
+
*/
|
|
35
|
+
export function deriveVerificationPhrase(seedHex, counter, wordCount) {
|
|
36
|
+
if (wordCount === 1)
|
|
37
|
+
return [deriveVerificationWord(seedHex, counter)];
|
|
38
|
+
return deriveToken(seedHex, GROUP_CONTEXT, counter, wordEncoding(wordCount)).split(' ');
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Derive a member's duress word for a given seed, pubkey, and counter.
|
|
42
|
+
* Unique per member, derivable by all group members who know the seed.
|
|
43
|
+
* Collision avoidance ensures the duress word never matches any verification
|
|
44
|
+
* word within the ±(2 × maxTolerance) window.
|
|
45
|
+
*
|
|
46
|
+
* @param seedHex - Group seed as a hex string (minimum 32 hex characters / 16 bytes).
|
|
47
|
+
* @param memberPubkeyHex - 64-character hex pubkey of the member.
|
|
48
|
+
* @param counter - Current time-based or usage counter.
|
|
49
|
+
* @param maxTolerance - Counter tolerance used by verifiers (default: 1).
|
|
50
|
+
* @param identities - All group member pubkeys for cross-member collision avoidance.
|
|
51
|
+
* @returns A single lowercase duress word distinct from all verification words in the window.
|
|
52
|
+
* @throws {Error} If collision avoidance fails after 255 retries.
|
|
53
|
+
*/
|
|
54
|
+
export function deriveDuressWord(seedHex, memberPubkeyHex, counter, maxTolerance = DEFAULT_GROUP_TOLERANCE, identities) {
|
|
55
|
+
return deriveDuressToken(seedHex, GROUP_CONTEXT, memberPubkeyHex, counter, undefined, maxTolerance, identities);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Derive a multi-word duress phrase for a given member.
|
|
59
|
+
* Collision avoidance ensures the phrase never matches any verification
|
|
60
|
+
* phrase within the ±(2 × maxTolerance) window.
|
|
61
|
+
*
|
|
62
|
+
* @param seedHex - Group seed as a hex string (minimum 32 hex characters / 16 bytes).
|
|
63
|
+
* @param memberPubkeyHex - 64-character hex pubkey of the member.
|
|
64
|
+
* @param counter - Current time-based or usage counter.
|
|
65
|
+
* @param wordCount - Number of words to produce (1, 2, or 3).
|
|
66
|
+
* @param maxTolerance - Counter tolerance used by verifiers (default: 1).
|
|
67
|
+
* @param identities - All group member pubkeys for cross-member collision avoidance.
|
|
68
|
+
* @returns Array of lowercase duress words distinct from all verification phrases in the window.
|
|
69
|
+
* @throws {Error} If collision avoidance fails after 255 retries.
|
|
70
|
+
*/
|
|
71
|
+
export function deriveDuressPhrase(seedHex, memberPubkeyHex, counter, wordCount, maxTolerance = DEFAULT_GROUP_TOLERANCE, identities) {
|
|
72
|
+
if (wordCount === 1)
|
|
73
|
+
return [deriveDuressWord(seedHex, memberPubkeyHex, counter, maxTolerance, identities)];
|
|
74
|
+
return deriveDuressToken(seedHex, GROUP_CONTEXT, memberPubkeyHex, counter, wordEncoding(wordCount), maxTolerance, identities).split(' ');
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Derive the current verification word for a group.
|
|
78
|
+
*
|
|
79
|
+
* @param group - Object with `seed` (hex string) and `counter` (current counter value).
|
|
80
|
+
* @returns A single lowercase verification word from the en-v1 wordlist.
|
|
81
|
+
*/
|
|
82
|
+
export function deriveCurrentWord(group) {
|
|
83
|
+
return deriveVerificationWord(group.seed, group.counter);
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=derive.js.map
|