agent-passport-system 3.0.0 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/src/v2/read_fidelity_receipt/__tests__/read_fidelity_receipt.test.d.ts +2 -0
- package/dist/src/v2/read_fidelity_receipt/__tests__/read_fidelity_receipt.test.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/__tests__/read_fidelity_receipt.test.js +392 -0
- package/dist/src/v2/read_fidelity_receipt/__tests__/read_fidelity_receipt.test.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/index.d.ts +4 -0
- package/dist/src/v2/read_fidelity_receipt/index.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/index.js +16 -0
- package/dist/src/v2/read_fidelity_receipt/index.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/receipt.d.ts +45 -0
- package/dist/src/v2/read_fidelity_receipt/receipt.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/receipt.js +283 -0
- package/dist/src/v2/read_fidelity_receipt/receipt.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/sampler.d.ts +35 -0
- package/dist/src/v2/read_fidelity_receipt/sampler.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/sampler.js +110 -0
- package/dist/src/v2/read_fidelity_receipt/sampler.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/types.d.ts +139 -0
- package/dist/src/v2/read_fidelity_receipt/types.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/types.js +17 -0
- package/dist/src/v2/read_fidelity_receipt/types.js.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/vectors/generate.d.ts +2 -0
- package/dist/src/v2/read_fidelity_receipt/vectors/generate.d.ts.map +1 -0
- package/dist/src/v2/read_fidelity_receipt/vectors/generate.js +261 -0
- package/dist/src/v2/read_fidelity_receipt/vectors/generate.js.map +1 -0
- package/dist/src/v2/word_handles/__tests__/word_handles.test.d.ts +2 -0
- package/dist/src/v2/word_handles/__tests__/word_handles.test.d.ts.map +1 -0
- package/dist/src/v2/word_handles/__tests__/word_handles.test.js +312 -0
- package/dist/src/v2/word_handles/__tests__/word_handles.test.js.map +1 -0
- package/dist/src/v2/word_handles/codec.d.ts +54 -0
- package/dist/src/v2/word_handles/codec.d.ts.map +1 -0
- package/dist/src/v2/word_handles/codec.js +334 -0
- package/dist/src/v2/word_handles/codec.js.map +1 -0
- package/dist/src/v2/word_handles/index.d.ts +4 -0
- package/dist/src/v2/word_handles/index.d.ts.map +1 -0
- package/dist/src/v2/word_handles/index.js +13 -0
- package/dist/src/v2/word_handles/index.js.map +1 -0
- package/dist/src/v2/word_handles/lexicon.d.ts +7 -0
- package/dist/src/v2/word_handles/lexicon.d.ts.map +1 -0
- package/dist/src/v2/word_handles/lexicon.js +276 -0
- package/dist/src/v2/word_handles/lexicon.js.map +1 -0
- package/dist/src/v2/word_handles/types.d.ts +58 -0
- package/dist/src/v2/word_handles/types.d.ts.map +1 -0
- package/dist/src/v2/word_handles/types.js +13 -0
- package/dist/src/v2/word_handles/types.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import type { DecodeResult, WordHandleProfile, WordHandleProfileName } from './types.js';
|
|
2
|
+
/** Identifier of the lexicon layout profile used by this codec. */
|
|
3
|
+
export declare const LEXICON_PROFILE = "single-list-v1";
|
|
4
|
+
/**
|
|
5
|
+
* Built-in word handle profiles. Word count = dataWords + checksumWords;
|
|
6
|
+
* prefixBits = 11 * dataWords.
|
|
7
|
+
*
|
|
8
|
+
* compact: 4+1 (44 bits). Set-scoped display ONLY; render-time
|
|
9
|
+
* uniqueness plus lengthening is mandatory
|
|
10
|
+
* (minUniquePrefixBits is the tool).
|
|
11
|
+
* default: 6+1 (66 bits). Minimum for any cross-set reference.
|
|
12
|
+
* high_assurance: 8+2 (88 bits). Archival and adversarial contexts.
|
|
13
|
+
*/
|
|
14
|
+
export declare const PROFILES: Readonly<Record<WordHandleProfileName, WordHandleProfile>>;
|
|
15
|
+
/**
|
|
16
|
+
* Encode the first `prefixBits` bits of `input` as a word_digest_handle:
|
|
17
|
+
* prefixBits/11 data words followed by `checksumWords` checksum words.
|
|
18
|
+
*
|
|
19
|
+
* `input` is raw bytes or a hex string; a leading "sha256:" prefix on
|
|
20
|
+
* hex input is stripped. Throws when prefixBits is not a positive
|
|
21
|
+
* multiple of 11, when the input supplies fewer than prefixBits bits,
|
|
22
|
+
* or when checksumWords is not 1 or 2.
|
|
23
|
+
*/
|
|
24
|
+
export declare function encode(input: Uint8Array | string, prefixBits?: number, checksumWords?: number): string[];
|
|
25
|
+
/** Encode with a named profile (prefixBits and checksumWords from the table). */
|
|
26
|
+
export declare function encodeProfile(input: Uint8Array | string, profile: WordHandleProfileName): string[];
|
|
27
|
+
/**
|
|
28
|
+
* Decode a word_digest_handle. Never throws on unknown words (reported
|
|
29
|
+
* via `outOfLexicon`); throws when checksumWords is not 1 or 2 or when
|
|
30
|
+
* the word count leaves no data words.
|
|
31
|
+
*
|
|
32
|
+
* `prefixHex` is the full packed prefix, 2*ceil(prefixBits/8) lowercase
|
|
33
|
+
* hex characters with trailing pad bits zero; `prefixBits` is returned
|
|
34
|
+
* so consumers compare BIT-scoped, never by raw string beyond
|
|
35
|
+
* prefixBits. Localization (`failedWordIndex`) is best effort and only
|
|
36
|
+
* attempted when the checksum fails and every word is in the lexicon.
|
|
37
|
+
* See DecodeResult for the exact rules.
|
|
38
|
+
*/
|
|
39
|
+
export declare function decode(words: readonly string[], checksumWords?: number): DecodeResult;
|
|
40
|
+
/**
|
|
41
|
+
* Decode with a named profile. Throws when the word count does not
|
|
42
|
+
* match the profile shape (dataWords + checksumWords).
|
|
43
|
+
*/
|
|
44
|
+
export declare function decodeProfile(words: readonly string[], profile: WordHandleProfileName): DecodeResult;
|
|
45
|
+
/**
|
|
46
|
+
* Smallest multiple of 11 that is >= startBits such that the leading
|
|
47
|
+
* prefixes of all digests are pairwise BIT-distinct at that length.
|
|
48
|
+
*
|
|
49
|
+
* Hex inputs may carry "sha256:" prefixes (stripped) and are compared
|
|
50
|
+
* case-insensitively. Throws on empty input or duplicate full digests
|
|
51
|
+
* (no prefix length can separate identical digests).
|
|
52
|
+
*/
|
|
53
|
+
export declare function minUniquePrefixBits(digestsHex: readonly string[], startBits?: number): number;
|
|
54
|
+
//# sourceMappingURL=codec.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.d.ts","sourceRoot":"","sources":["../../../../src/v2/word_handles/codec.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,YAAY,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAA;AAKxF,mEAAmE;AACnE,eAAO,MAAM,eAAe,mBAAmB,CAAA;AAE/C;;;;;;;;;GASG;AACH,eAAO,MAAM,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,CAI/E,CAAA;AAyGD;;;;;;;;GAQG;AACH,wBAAgB,MAAM,CACpB,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,UAAU,SAAK,EACf,aAAa,SAAI,GAChB,MAAM,EAAE,CAuBV;AAED,iFAAiF;AACjF,wBAAgB,aAAa,CAC3B,KAAK,EAAE,UAAU,GAAG,MAAM,EAC1B,OAAO,EAAE,qBAAqB,GAC7B,MAAM,EAAE,CAMV;AAyBD;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,EAAE,aAAa,SAAI,GAAG,YAAY,CAsEhF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,MAAM,EAAE,EACxB,OAAO,EAAE,qBAAqB,GAC7B,YAAY,CAYd;AAsBD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,EAAE,SAAS,SAAK,GAAG,MAAM,CAuBzF"}
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
// Copyright 2024-2026 Tymofii Pidlisnyi. Apache-2.0 license. See LICENSE.
|
|
2
|
+
// ══════════════════════════════════════════════════════════════════
|
|
3
|
+
// word_handles codec (v2): encode, decode, minUniquePrefixBits,
|
|
4
|
+
// PROFILES, encodeProfile, decodeProfile
|
|
5
|
+
// ══════════════════════════════════════════════════════════════════
|
|
6
|
+
// Deterministic, pure functions: no I/O, no clock, no randomness.
|
|
7
|
+
//
|
|
8
|
+
// Encoding rules (v2):
|
|
9
|
+
// - prefixBits is a positive multiple of 11. checksumWords is 1 or
|
|
10
|
+
// 2. Word count = prefixBits/11 + checksumWords.
|
|
11
|
+
// - Bit order is MSB-first from byte 0. Data word i covers bits
|
|
12
|
+
// [11*i, 11*i + 11) as an integer index into WORDS.
|
|
13
|
+
// - packedPrefix = the first prefixBits bits packed into
|
|
14
|
+
// ceil(prefixBits/8) bytes, MSB-first, unused low-order bits of
|
|
15
|
+
// the final byte set to 0.
|
|
16
|
+
// - checksumDigest = sha256( BE16(prefixBits) || packedPrefix ).
|
|
17
|
+
// BE16 is the two-byte big-endian unsigned encoding of prefixBits.
|
|
18
|
+
// Checksum word j (j = 0..checksumWords-1) = bits [11*j, 11*j+11)
|
|
19
|
+
// of checksumDigest, appended after the data words in order.
|
|
20
|
+
// - The construction is position-dependent: the hash runs over the
|
|
21
|
+
// ordered packed bits, so transposing any two differing data words
|
|
22
|
+
// changes packedPrefix and fails the checksum with probability
|
|
23
|
+
// 1 - 2^-11 per event for one checksum word (1 - 2^-22 for two).
|
|
24
|
+
// ══════════════════════════════════════════════════════════════════
|
|
25
|
+
import { createHash } from 'node:crypto';
|
|
26
|
+
import { WORDS } from './lexicon.js';
|
|
27
|
+
const WORD_BITS = 11;
|
|
28
|
+
const HEX_RE = /^[0-9a-fA-F]*$/;
|
|
29
|
+
/** Identifier of the lexicon layout profile used by this codec. */
|
|
30
|
+
export const LEXICON_PROFILE = 'single-list-v1';
|
|
31
|
+
/**
|
|
32
|
+
* Built-in word handle profiles. Word count = dataWords + checksumWords;
|
|
33
|
+
* prefixBits = 11 * dataWords.
|
|
34
|
+
*
|
|
35
|
+
* compact: 4+1 (44 bits). Set-scoped display ONLY; render-time
|
|
36
|
+
* uniqueness plus lengthening is mandatory
|
|
37
|
+
* (minUniquePrefixBits is the tool).
|
|
38
|
+
* default: 6+1 (66 bits). Minimum for any cross-set reference.
|
|
39
|
+
* high_assurance: 8+2 (88 bits). Archival and adversarial contexts.
|
|
40
|
+
*/
|
|
41
|
+
export const PROFILES = {
|
|
42
|
+
compact: { name: 'compact', dataWords: 4, checksumWords: 1, prefixBits: 44 },
|
|
43
|
+
default: { name: 'default', dataWords: 6, checksumWords: 1, prefixBits: 66 },
|
|
44
|
+
high_assurance: { name: 'high_assurance', dataWords: 8, checksumWords: 2, prefixBits: 88 },
|
|
45
|
+
};
|
|
46
|
+
/** Lexicon word to index, built once. Exact code-unit key equality. */
|
|
47
|
+
const WORD_INDEX = (() => {
|
|
48
|
+
const m = new Map();
|
|
49
|
+
for (let i = 0; i < WORDS.length; i++)
|
|
50
|
+
m.set(WORDS[i], i);
|
|
51
|
+
return m;
|
|
52
|
+
})();
|
|
53
|
+
function validatePrefixBits(prefixBits) {
|
|
54
|
+
if (!Number.isInteger(prefixBits) ||
|
|
55
|
+
prefixBits <= 0 ||
|
|
56
|
+
prefixBits % WORD_BITS !== 0) {
|
|
57
|
+
throw new Error(`prefixBits must be a positive multiple of ${WORD_BITS}, got ${prefixBits}`);
|
|
58
|
+
}
|
|
59
|
+
if (prefixBits > 0xffff) {
|
|
60
|
+
throw new Error(`prefixBits must fit in 16 bits (BE16 header), got ${prefixBits}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function validateChecksumWords(checksumWords) {
|
|
64
|
+
if (checksumWords !== 1 && checksumWords !== 2) {
|
|
65
|
+
throw new Error(`checksumWords must be 1 or 2, got ${checksumWords}`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Strip an optional leading "sha256:" from a hex string. */
|
|
69
|
+
function stripSha256Prefix(hex) {
|
|
70
|
+
return hex.startsWith('sha256:') ? hex.slice('sha256:'.length) : hex;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Normalize encode input to bytes plus the exact number of bits the
|
|
74
|
+
* caller supplied. Hex strings supply 4 bits per character; an
|
|
75
|
+
* odd-length hex string is padded with a zero nibble for byte packing
|
|
76
|
+
* but the padding does not count toward the supplied bits.
|
|
77
|
+
*/
|
|
78
|
+
function toBytes(input) {
|
|
79
|
+
if (typeof input === 'string') {
|
|
80
|
+
const hex = stripSha256Prefix(input);
|
|
81
|
+
if (!HEX_RE.test(hex)) {
|
|
82
|
+
throw new Error('input hex string contains non-hex characters');
|
|
83
|
+
}
|
|
84
|
+
const bitLength = hex.length * 4;
|
|
85
|
+
const padded = hex.length % 2 === 0 ? hex : hex + '0';
|
|
86
|
+
const bytes = new Uint8Array(padded.length / 2);
|
|
87
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
88
|
+
bytes[i] = parseInt(padded.slice(2 * i, 2 * i + 2), 16);
|
|
89
|
+
}
|
|
90
|
+
return { bytes, bitLength };
|
|
91
|
+
}
|
|
92
|
+
return { bytes: input, bitLength: input.length * 8 };
|
|
93
|
+
}
|
|
94
|
+
/** Bit i of a byte array, MSB-first from byte 0. */
|
|
95
|
+
function getBit(bytes, i) {
|
|
96
|
+
return (bytes[i >> 3] >> (7 - (i & 7))) & 1;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Pack the first prefixBits bits of `bytes` into ceil(prefixBits/8)
|
|
100
|
+
* bytes, MSB-first, unused low-order bits of the final byte set to 0.
|
|
101
|
+
*/
|
|
102
|
+
function packPrefix(bytes, prefixBits) {
|
|
103
|
+
const byteLen = Math.ceil(prefixBits / 8);
|
|
104
|
+
const packed = new Uint8Array(byteLen);
|
|
105
|
+
packed.set(bytes.subarray(0, byteLen));
|
|
106
|
+
const rem = prefixBits % 8;
|
|
107
|
+
if (rem !== 0) {
|
|
108
|
+
packed[byteLen - 1] &= (0xff << (8 - rem)) & 0xff;
|
|
109
|
+
}
|
|
110
|
+
return packed;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Checksum word indices: bits [11*j, 11*j + 11) of
|
|
114
|
+
* sha256( BE16(prefixBits) || packedPrefix ) for j = 0..checksumWords-1.
|
|
115
|
+
*/
|
|
116
|
+
function checksumIndicesFor(prefixBits, packedPrefix, checksumWords) {
|
|
117
|
+
const msg = new Uint8Array(2 + packedPrefix.length);
|
|
118
|
+
msg[0] = (prefixBits >> 8) & 0xff;
|
|
119
|
+
msg[1] = prefixBits & 0xff;
|
|
120
|
+
msg.set(packedPrefix, 2);
|
|
121
|
+
const digest = createHash('sha256').update(msg).digest();
|
|
122
|
+
const out = [];
|
|
123
|
+
for (let j = 0; j < checksumWords; j++) {
|
|
124
|
+
let idx = 0;
|
|
125
|
+
for (let b = 0; b < WORD_BITS; b++) {
|
|
126
|
+
idx = (idx << 1) | getBit(digest, WORD_BITS * j + b);
|
|
127
|
+
}
|
|
128
|
+
out.push(idx);
|
|
129
|
+
}
|
|
130
|
+
return out;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Encode the first `prefixBits` bits of `input` as a word_digest_handle:
|
|
134
|
+
* prefixBits/11 data words followed by `checksumWords` checksum words.
|
|
135
|
+
*
|
|
136
|
+
* `input` is raw bytes or a hex string; a leading "sha256:" prefix on
|
|
137
|
+
* hex input is stripped. Throws when prefixBits is not a positive
|
|
138
|
+
* multiple of 11, when the input supplies fewer than prefixBits bits,
|
|
139
|
+
* or when checksumWords is not 1 or 2.
|
|
140
|
+
*/
|
|
141
|
+
export function encode(input, prefixBits = 66, checksumWords = 1) {
|
|
142
|
+
validatePrefixBits(prefixBits);
|
|
143
|
+
validateChecksumWords(checksumWords);
|
|
144
|
+
const { bytes, bitLength } = toBytes(input);
|
|
145
|
+
if (bitLength < prefixBits) {
|
|
146
|
+
throw new Error(`input supplies ${bitLength} bits, need at least ${prefixBits}`);
|
|
147
|
+
}
|
|
148
|
+
const dataWordCount = prefixBits / WORD_BITS;
|
|
149
|
+
const words = [];
|
|
150
|
+
for (let i = 0; i < dataWordCount; i++) {
|
|
151
|
+
let idx = 0;
|
|
152
|
+
for (let b = 0; b < WORD_BITS; b++) {
|
|
153
|
+
idx = (idx << 1) | getBit(bytes, WORD_BITS * i + b);
|
|
154
|
+
}
|
|
155
|
+
words.push(WORDS[idx]);
|
|
156
|
+
}
|
|
157
|
+
const packed = packPrefix(bytes, prefixBits);
|
|
158
|
+
for (const idx of checksumIndicesFor(prefixBits, packed, checksumWords)) {
|
|
159
|
+
words.push(WORDS[idx]);
|
|
160
|
+
}
|
|
161
|
+
return words;
|
|
162
|
+
}
|
|
163
|
+
/** Encode with a named profile (prefixBits and checksumWords from the table). */
|
|
164
|
+
export function encodeProfile(input, profile) {
|
|
165
|
+
const p = PROFILES[profile];
|
|
166
|
+
if (p === undefined) {
|
|
167
|
+
throw new Error(`unknown word handle profile: ${profile}`);
|
|
168
|
+
}
|
|
169
|
+
return encode(input, p.prefixBits, p.checksumWords);
|
|
170
|
+
}
|
|
171
|
+
/** Rebuild the packed prefix bytes from data word indices. */
|
|
172
|
+
function packFromIndices(indices, prefixBits) {
|
|
173
|
+
const packed = new Uint8Array(Math.ceil(prefixBits / 8));
|
|
174
|
+
let bitPos = 0;
|
|
175
|
+
for (const idx of indices) {
|
|
176
|
+
for (let b = WORD_BITS - 1; b >= 0; b--) {
|
|
177
|
+
if ((idx >> b) & 1) {
|
|
178
|
+
packed[bitPos >> 3] |= 0x80 >> (bitPos & 7);
|
|
179
|
+
}
|
|
180
|
+
bitPos++;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return packed;
|
|
184
|
+
}
|
|
185
|
+
function toHex(bytes) {
|
|
186
|
+
let hex = '';
|
|
187
|
+
for (const byte of bytes) {
|
|
188
|
+
hex += byte.toString(16).padStart(2, '0');
|
|
189
|
+
}
|
|
190
|
+
return hex;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Decode a word_digest_handle. Never throws on unknown words (reported
|
|
194
|
+
* via `outOfLexicon`); throws when checksumWords is not 1 or 2 or when
|
|
195
|
+
* the word count leaves no data words.
|
|
196
|
+
*
|
|
197
|
+
* `prefixHex` is the full packed prefix, 2*ceil(prefixBits/8) lowercase
|
|
198
|
+
* hex characters with trailing pad bits zero; `prefixBits` is returned
|
|
199
|
+
* so consumers compare BIT-scoped, never by raw string beyond
|
|
200
|
+
* prefixBits. Localization (`failedWordIndex`) is best effort and only
|
|
201
|
+
* attempted when the checksum fails and every word is in the lexicon.
|
|
202
|
+
* See DecodeResult for the exact rules.
|
|
203
|
+
*/
|
|
204
|
+
export function decode(words, checksumWords = 1) {
|
|
205
|
+
validateChecksumWords(checksumWords);
|
|
206
|
+
const outOfLexicon = [];
|
|
207
|
+
for (let i = 0; i < words.length; i++) {
|
|
208
|
+
if (!WORD_INDEX.has(words[i]))
|
|
209
|
+
outOfLexicon.push(i);
|
|
210
|
+
}
|
|
211
|
+
if (outOfLexicon.length > 0) {
|
|
212
|
+
return {
|
|
213
|
+
prefixHex: null,
|
|
214
|
+
prefixBits: null,
|
|
215
|
+
checksumOk: false,
|
|
216
|
+
failedWordIndex: null,
|
|
217
|
+
outOfLexicon,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
const dataWordCount = words.length - checksumWords;
|
|
221
|
+
if (dataWordCount <= 0) {
|
|
222
|
+
throw new Error(`word count ${words.length} with ${checksumWords} checksum word(s) leaves no data words`);
|
|
223
|
+
}
|
|
224
|
+
const prefixBits = WORD_BITS * dataWordCount;
|
|
225
|
+
validatePrefixBits(prefixBits);
|
|
226
|
+
const indices = words.slice(0, dataWordCount).map((w) => WORD_INDEX.get(w));
|
|
227
|
+
const givenChecksums = words
|
|
228
|
+
.slice(dataWordCount)
|
|
229
|
+
.map((w) => WORD_INDEX.get(w));
|
|
230
|
+
const packed = packFromIndices(indices, prefixBits);
|
|
231
|
+
const prefixHex = toHex(packed);
|
|
232
|
+
const expectedChecksums = checksumIndicesFor(prefixBits, packed, checksumWords);
|
|
233
|
+
const checksumOk = expectedChecksums.every((e, j) => e === givenChecksums[j]);
|
|
234
|
+
let failedWordIndex = null;
|
|
235
|
+
if (!checksumOk) {
|
|
236
|
+
const fixable = [];
|
|
237
|
+
const trial = indices.slice();
|
|
238
|
+
for (let i = 0; i < dataWordCount; i++) {
|
|
239
|
+
const original = trial[i];
|
|
240
|
+
for (let cand = 0; cand < WORDS.length; cand++) {
|
|
241
|
+
if (cand === original)
|
|
242
|
+
continue;
|
|
243
|
+
trial[i] = cand;
|
|
244
|
+
const candPacked = packFromIndices(trial, prefixBits);
|
|
245
|
+
const candChecksums = checksumIndicesFor(prefixBits, candPacked, checksumWords);
|
|
246
|
+
if (candChecksums.every((e, j) => e === givenChecksums[j])) {
|
|
247
|
+
fixable.push(i);
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
trial[i] = original;
|
|
252
|
+
}
|
|
253
|
+
if (fixable.length === 1) {
|
|
254
|
+
failedWordIndex = fixable[0];
|
|
255
|
+
}
|
|
256
|
+
else if (fixable.length === 0) {
|
|
257
|
+
const differing = [];
|
|
258
|
+
for (let j = 0; j < checksumWords; j++) {
|
|
259
|
+
if (givenChecksums[j] !== expectedChecksums[j]) {
|
|
260
|
+
differing.push(dataWordCount + j);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
failedWordIndex = differing.length === 1 ? differing[0] : null;
|
|
264
|
+
}
|
|
265
|
+
else {
|
|
266
|
+
failedWordIndex = null;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
return { prefixHex, prefixBits, checksumOk, failedWordIndex, outOfLexicon };
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Decode with a named profile. Throws when the word count does not
|
|
273
|
+
* match the profile shape (dataWords + checksumWords).
|
|
274
|
+
*/
|
|
275
|
+
export function decodeProfile(words, profile) {
|
|
276
|
+
const p = PROFILES[profile];
|
|
277
|
+
if (p === undefined) {
|
|
278
|
+
throw new Error(`unknown word handle profile: ${profile}`);
|
|
279
|
+
}
|
|
280
|
+
const expected = p.dataWords + p.checksumWords;
|
|
281
|
+
if (words.length !== expected) {
|
|
282
|
+
throw new Error(`profile ${p.name} expects ${expected} words, got ${words.length}`);
|
|
283
|
+
}
|
|
284
|
+
return decode(words, p.checksumWords);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* First `bits` bits of a hex string as a canonical comparison key:
|
|
288
|
+
* ceil(bits/4) hex chars with unused low-order bits of the final
|
|
289
|
+
* nibble masked to zero. Throws when the hex string supplies fewer
|
|
290
|
+
* than `bits` bits.
|
|
291
|
+
*/
|
|
292
|
+
function bitPrefixKey(hex, bits) {
|
|
293
|
+
if (hex.length * 4 < bits) {
|
|
294
|
+
throw new Error(`digest supplies ${hex.length * 4} bits, need at least ${bits} to compare prefixes`);
|
|
295
|
+
}
|
|
296
|
+
const chars = Math.ceil(bits / 4);
|
|
297
|
+
const prefix = hex.slice(0, chars);
|
|
298
|
+
const rem = bits % 4;
|
|
299
|
+
if (rem === 0)
|
|
300
|
+
return prefix;
|
|
301
|
+
const masked = parseInt(prefix[chars - 1], 16) & ((0xf << (4 - rem)) & 0xf);
|
|
302
|
+
return prefix.slice(0, chars - 1) + masked.toString(16);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Smallest multiple of 11 that is >= startBits such that the leading
|
|
306
|
+
* prefixes of all digests are pairwise BIT-distinct at that length.
|
|
307
|
+
*
|
|
308
|
+
* Hex inputs may carry "sha256:" prefixes (stripped) and are compared
|
|
309
|
+
* case-insensitively. Throws on empty input or duplicate full digests
|
|
310
|
+
* (no prefix length can separate identical digests).
|
|
311
|
+
*/
|
|
312
|
+
export function minUniquePrefixBits(digestsHex, startBits = 44) {
|
|
313
|
+
if (digestsHex.length === 0) {
|
|
314
|
+
throw new Error('minUniquePrefixBits requires at least one digest');
|
|
315
|
+
}
|
|
316
|
+
const normalized = digestsHex.map((d) => {
|
|
317
|
+
const hex = stripSha256Prefix(d).toLowerCase();
|
|
318
|
+
if (hex.length === 0 || !/^[0-9a-f]+$/.test(hex)) {
|
|
319
|
+
throw new Error(`digest is not a hex string: ${d}`);
|
|
320
|
+
}
|
|
321
|
+
return hex;
|
|
322
|
+
});
|
|
323
|
+
if (new Set(normalized).size !== normalized.length) {
|
|
324
|
+
throw new Error('duplicate digests: no prefix length can separate them');
|
|
325
|
+
}
|
|
326
|
+
let bits = Math.max(WORD_BITS, Math.ceil(startBits / WORD_BITS) * WORD_BITS);
|
|
327
|
+
for (;;) {
|
|
328
|
+
const prefixes = new Set(normalized.map((d) => bitPrefixKey(d, bits)));
|
|
329
|
+
if (prefixes.size === normalized.length)
|
|
330
|
+
return bits;
|
|
331
|
+
bits += WORD_BITS;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
//# sourceMappingURL=codec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codec.js","sourceRoot":"","sources":["../../../../src/v2/word_handles/codec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { encode, decode, encodeProfile, decodeProfile, minUniquePrefixBits, PROFILES, LEXICON_PROFILE, } from './codec.js';
|
|
2
|
+
export { LEXICON_NAME, LEXICON_ID, WORDS, canonicalWordlistText, } from './lexicon.js';
|
|
3
|
+
export type { DecodeResult, WordHandleProfile, WordHandleProfileName, } from './types.js';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/v2/word_handles/index.ts"],"names":[],"mappings":"AAWA,OAAO,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,QAAQ,EACR,eAAe,GAChB,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,KAAK,EACL,qBAAqB,GACtB,MAAM,cAAc,CAAA;AAErB,YAAY,EACV,YAAY,EACZ,iBAAiB,EACjB,qBAAqB,GACtB,MAAM,YAAY,CAAA"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// Copyright 2024-2026 Tymofii Pidlisnyi. Apache-2.0 license. See LICENSE.
|
|
2
|
+
// ══════════════════════════════════════════════════════════════════
|
|
3
|
+
// word_handles (word_digest_handle codec, v2): public surface
|
|
4
|
+
// ══════════════════════════════════════════════════════════════════
|
|
5
|
+
// Renders the leading bits of a digest as words from the versioned
|
|
6
|
+
// aps-handle-en-v1 lexicon (2048 words, 11 bits per word) plus one or
|
|
7
|
+
// two position-dependent checksum words. Pure functions: no I/O, no
|
|
8
|
+
// clock, no randomness. See README.md for profiles, detection and
|
|
9
|
+
// localization math, and the identifier prohibition.
|
|
10
|
+
// ══════════════════════════════════════════════════════════════════
|
|
11
|
+
export { encode, decode, encodeProfile, decodeProfile, minUniquePrefixBits, PROFILES, LEXICON_PROFILE, } from './codec.js';
|
|
12
|
+
export { LEXICON_NAME, LEXICON_ID, WORDS, canonicalWordlistText, } from './lexicon.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/v2/word_handles/index.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,qEAAqE;AACrE,8DAA8D;AAC9D,qEAAqE;AACrE,mEAAmE;AACnE,sEAAsE;AACtE,oEAAoE;AACpE,kEAAkE;AAClE,qDAAqD;AACrD,qEAAqE;AAErE,OAAO,EACL,MAAM,EACN,MAAM,EACN,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,QAAQ,EACR,eAAe,GAChB,MAAM,YAAY,CAAA;AAEnB,OAAO,EACL,YAAY,EACZ,UAAU,EACV,KAAK,EACL,qBAAqB,GACtB,MAAM,cAAc,CAAA"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare const LEXICON_NAME = "aps-handle-en-v1";
|
|
2
|
+
/** sha256 of the canonical word list text (one word per line, trailing newline). */
|
|
3
|
+
export declare const LEXICON_ID = "sha256:2a9c4de3b5457154e6bde9d40af0da552c2556d8e80a2dec8b82dee4bca74510";
|
|
4
|
+
export declare const WORDS: readonly string[];
|
|
5
|
+
/** Canonical text form of the lexicon; sha256 of this string equals LEXICON_ID. */
|
|
6
|
+
export declare function canonicalWordlistText(): string;
|
|
7
|
+
//# sourceMappingURL=lexicon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lexicon.d.ts","sourceRoot":"","sources":["../../../../src/v2/word_handles/lexicon.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,YAAY,qBAAqB,CAAA;AAE9C,oFAAoF;AACpF,eAAO,MAAM,UAAU,4EACoD,CAAA;AAE3E,eAAO,MAAM,KAAK,EAAE,SAAS,MAAM,EAiQzB,CAAA;AAEV,mFAAmF;AACnF,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C"}
|