@tacet-ink/journal-core 0.2.5 → 0.3.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 CHANGED
@@ -18,7 +18,7 @@
18
18
  ```sh
19
19
  git clone https://github.com/tacet-ink/journal-core.git && cd journal-core
20
20
  npm ci --ignore-scripts
21
- npm run verify # 491 assertions, all green, run against the real modules (no mocks)
21
+ npm run verify # 492 assertions, all green, run against the real modules (no mocks)
22
22
  ```
23
23
 
24
24
  ```ts
@@ -80,9 +80,14 @@ run: `node --experimental-strip-types example.ts`
80
80
  | `src/server/ratelimit.ts` | per-IP fixed-window 限流(單句 UPSERT…RETURNING;D1 計數,跨 isolate 有效) |
81
81
  | `src/server/cors.ts`/`hash.ts` | 共用 CORS/雜湊工具(`src/server/env.ts` 為內部 Env 介面,不入 exports) |
82
82
 
83
+ 發行形(0.3.0 起):`dist/`=tsc 原生 emit 的 ESM `.js`+`.d.ts`,`exports` 全部子路徑指向 dist;
84
+ `src/` 同包隨附(稽核/閱讀用,import 恆走 dist)。
85
+
83
86
  ## 前綴契約(家族表:13 個資料前綴+閘對照組 jr1g.)
84
87
 
85
88
  前綴是版本契約:payload 佈局與 KDF 由前綴界定,升級 = 新前綴。
89
+ 逐位元組布局、KDF 參數、AAD 與世代契約的完整規格見 [docs/format-spec.md](./docs/format-spec.md),
90
+ 測試向量見 [docs/vectors/](./docs/vectors/)(真原語產生的凍結證據;閘 [26] 檢存在性與 shape)。
86
91
  Tacet 部署實例(config 傳入):
87
92
 
88
93
  | 前綴 | 語意 | KDF | payload |
@@ -119,7 +124,7 @@ jr3d/jr4d 兩入參數同輸入,域分離由 info 承載;凍結 KAT 兩 blob
119
124
 
120
125
  ```sh
121
126
  npm ci --ignore-scripts
122
- npm run verify # 491 斷言對真模組(禁鏡像;限流單句 UPSERT…RETURNING 直載真 SQLite):roundtrip/AAD 防搬移/
127
+ npm run verify # 492 斷言對真模組(禁鏡像;限流單句 UPSERT…RETURNING 直載真 SQLite):roundtrip/AAD 防搬移/
123
128
  # extractable/時代隔離/跨前綴家族隔離/payload 竄改/RFC 9106 KAT/BIP39 @scure 對照 200 組/
124
129
  # server-side(inboundCipher/validWrappedKey/pickKeyPackage/checkRate/timingSafeEq)+ pinlock 全函式
125
130
  # + 密語正規化 v3 世代(normalizePassphrase/jr4w./jr4d./PH1 v3 鹽域分離+帶內版本化舊契約向量)
@@ -131,8 +136,9 @@ npm run verify # 491 斷言對真模組(禁鏡像;限流單句 UPSERT…RE
131
136
  # +KAT 凍結向量 [17](HKDF info 域世代分離+v3/raw 入口契約四 blob)
132
137
  # +包裹前綴快檢 [13-2](錯前綴試探免付 KDF:五入口行為+計時帽+計數錨)
133
138
  # +CI 供應鏈面 [21](npm ci --ignore-scripts+dependabot runner fromJSON 分流+腳本摘除+NIT-1 錨+r2 MINOR-1 URL 直傳;
134
- # 491 帳=repo 樹——發行包內無 .github=[21] 四條 workflow 錨收斂為 1 顯性 SKIP 行→480,SKIP 顯形非靜默)
139
+ # 492 帳=repo 樹——發行包內無 .github=[21] 四條 workflow 錨收斂為 1 顯性 SKIP 行→489,SKIP 顯形非靜默)
135
140
  # +發行 tarball 治理面 [22](pack 白名單零 open-card-pr.sh)
141
+ # +格式規格+測試向量 [26](docs/format-spec.md+docs/vectors 存在性/位元組 shape/欄位名對規格/凍結 KAT 逐字對閘)
136
142
  ```
137
143
 
138
144
  - 產品碼**零執行時依賴**(WebCrypto 原語);devDependencies 僅閘用(typescript、@scure/bip39 對照、workers types)。
@@ -146,8 +152,9 @@ npm run verify # 491 斷言對真模組(禁鏡像;限流單句 UPSERT…RE
146
152
 
147
153
  ## 使用(Usage)
148
154
 
149
- TypeScript 原始碼發行(exports 直指 .ts)。**注意**:Node 的 strip-types 不適用於
150
- node_modules 內的檔案,npm 安裝的消費者請走打包器;源碼 clone 可直接 node --experimental-strip-types。
155
+ 0.3.0 起發行 `dist/`(ESM `.js`+`.d.ts`):npm 安裝後瀏覽器、Node、Deno、Bun、Workers
156
+ 皆可直接 import,不需打包器、不需 strip-types(0.2.x 的「npm 安裝必走打包器」限制已退役)。
157
+ 源碼 clone 仍可直接 `node --experimental-strip-types` 跑 `src/`。
151
158
 
152
159
  ```ts
153
160
  import { makeKeyStore, makeHeldKey, generateNoteKey, encryptNote, decryptNote } from '@tacet-ink/journal-core';
@@ -241,8 +248,8 @@ catch)+套用 `migrations/0011-ph2-ladder.sql`(+0012 索引修正);
241
248
  - `PinLockConfig`:解包輸出的 noteKey 恆 `extractable=true`(鐵律,非可調選項)——
242
249
  config 只帶三個前綴欄(pinLock/pinLockSaltPrefix/pinLockAad),缺任一即拒。
243
250
 
244
- 打包器(vite/esbuild)可直接 alias 到源碼目錄使用;Argon2id 瀏覽器載體需另裝
245
- hash-wasm 並以 `setArgonLoader()` 注入(詳 `src/client/argon2.ts` 檔頭)。
251
+ Argon2id 瀏覽器載體需另裝 hash-wasm 並以 `setArgonLoader()` 注入(詳 `src/client/argon2.ts` 檔頭);
252
+ Node ≥ 24.7 走內建 `node:crypto` 免注入。
246
253
 
247
254
  ## 界限(誠實面)
248
255
 
@@ -309,16 +316,31 @@ carrier: `node:crypto` ≥ Node 24.7 / hash-wasm in browsers, RFC 9106 test vect
309
316
  @scure/bip39), brand-namespaced key storage (`keys.ts`). Server: zero-knowledge auth core with a
310
317
  PH1→PH2 login flow, inbound cipher/package validation and paired key-package selection
311
318
  (`auth.ts`; PH2-UNIQUE conflict and session revocation are caller-owned wiring), per-IP
312
- fixed-window rate limiting on D1 (`ratelimit.ts`), shared CORS/hash utilities.
313
-
314
- **Verification.** `npm run verify` runs 491 assertions against the real modules (no mocks):
319
+ fixed-window rate limiting on D1 (`ratelimit.ts`), shared CORS/hash utilities. Since 0.3.0 the
320
+ package ships `dist/` (tsc-emitted ESM `.js` + `.d.ts`); every `exports` subpath resolves to dist,
321
+ and `src/` is included for reading and auditing only.
322
+
323
+ **Format spec & test vectors.** The byte-level wire format of every prefix family — payload layout
324
+ and field lengths, KDF parameters, AAD strings, and the in-band versioning contract — is specified
325
+ in [docs/format-spec.md](./docs/format-spec.md) (Chinese; transcribed from the source, not a new
326
+ contract). JSON test vectors live in [docs/vectors/](./docs/vectors/): one wrap/encrypt sample per
327
+ prefix family (`families.json`), known-answer vectors (RFC 9106 Argon2id, the gate's frozen
328
+ `jr2w.`/`jr3w.`/`jr3d.`/`jr4w.`/`jr4d.`/`jr1r.`/`jr1w.` blobs, and PH1/PH2 credential samples in
329
+ `kat.json`), and 34 BIP39 samples (`bip39.json`). They were generated once by
330
+ `scripts/generate-vectors.ts` against the real primitives and committed as frozen evidence; the
331
+ verify gate checks their presence and shape (section [26]) and does not regenerate them.
332
+
333
+ **Verification.** `npm run verify` runs 492 assertions against the real modules (no mocks):
315
334
  roundtrips, AAD tamper-evidence, extractability rules, era isolation, cross-prefix family
316
335
  isolation, payload tampering, RFC 9106 KAT, a 200-vector BIP39 cross-check, and the
317
- login ladder-guard behavior suite (external audit #8).
318
-
319
- **Usage.** TypeScript source is published (exports point at `.ts`). If you install from npm you
320
- must bundle it (vite/esbuild etc.); Node's strip-types does not apply inside `node_modules`.
321
- See the code sample in the 使用 section above.
336
+ login ladder-guard behavior suite (external audit #8), and presence/shape checks for the format
337
+ spec and test vectors.
338
+
339
+ **Usage.** Since 0.3.0 the npm package ships compiled ESM in `dist/`, so browsers, Node, Deno, Bun
340
+ and Workers can import it directly — no bundler and no strip-types needed (the 0.2.x "must bundle"
341
+ requirement is retired). A source checkout can still run `src/` with `node --experimental-strip-types`.
342
+ In browsers, inject the hash-wasm Argon2id carrier via `setArgonLoader()`; Node ≥ 24.7 uses the
343
+ built-in `node:crypto`. See the code sample in the 使用 section above.
322
344
 
323
345
  **Honest limits.** The guest era is obfuscation-grade, not E2E. PH1 derivation is defined by each
324
346
  product (fast hash or Argon2id); this layer only validates its hex64 form. Product concerns
@@ -0,0 +1,166 @@
1
+ /**
2
+ * argon2.ts — Argon2id 包裹原語(jr3w./jr3d.,安全路線第 2 步,2026-09-14)。
3
+ *
4
+ * 動機(安全路線定案):離線 oracle 的戰利品是 wrapped(/auth/login 回應帶 wrapped+salt,
5
+ * 拿到一次回應即可永久離線猜)。PBKDF2-SHA256 600k 對 GPU 友善;Argon2id 的記憶體困難
6
+ * 讓每猜成本上升一至兩個數量級,oracle 實際價值大幅中和。OPAQUE 降級為後續精益求精。
7
+ *
8
+ * 帶內版本化契約(不變量 5):升級 KDF = 換新前綴,禁原地改語意。
9
+ * jr3w. 單因子:結構與 jr1w. 同構(salt 獨立存 users.salt;wrapped = prefix + b64(iv[12] ‖ ct),
10
+ * ct = AES-GCM(KEK, hex(noteKey), aad='notekey')),只換 KEK 派生:
11
+ * KEK = Argon2id(pass, salt, m=64MiB, t=3, p=1, tag=32B) → AES-GCM key。
12
+ * jr3d. 雙因子(jr2w. 後繼):payload 同 jr2w.(pinSalt[16] ‖ iv[12] ‖ GCM(KEK2, hex(noteKey), aad='notekey2')),
13
+ * KEK2 = HKDF-SHA256( ikm = Argon2id(pass, salt1)[32] ‖ Argon2id(pinNorm, pinSalt3Prefix‖hex(pinSalt))[32],
14
+ * salt = pinSalt, info = 'journal-kek2-v1:' + wrapDual3, L = 32 )。
15
+ * 兩 payload 長度相同(皆 108B):客戶端按前綴分流(jr3w.→單因子、jr3d.→雙因子),形狀互斥由
16
+ * AAD 與長度把關,跨前綴呼叫一律回 null(unwrap 有前綴守衛,驗證閘有跨協議斷言)。
17
+ *
18
+ * 雙載體(同一 spec 兩端一致,交叉驗證逐位元一致):
19
+ * - node(驗證閘/prod smoke):node:crypto.argon2(24.7.0 落地版,26.8.1 實測)
20
+ * - 瀏覽器:hash-wasm argon2id(純 wasm 內嵌 base64,零網路請求,4.12.0 實測 64MiB t=3 ≈ 180ms)
21
+ * 標準向量:RFC 9106 無 secret/associated-data Argon2id(t=3, m=32, p=4, pwd=32B 0x01, salt=16B 0x00)
22
+ * = 72d2a36fd5c266bcc96121b24937bc253338cdfcbd273713655748c54b4dd503(兩載體實測 MATCH)。
23
+ *
24
+ * 遷移契約(禁強制重置):既有 jr1w./jr2w. 帳戶在下次成功 unwrap 後由客戶端靜默
25
+ * re-wrap 推 jr3w./jr3d.(手上有 noteKey、同一 noteKey 重包,資料零換鑰);舊前綴照解。
26
+ *
27
+ * ⚠️ 鐵律:unwrap 輸出 noteKey 一律 extractable=true(要能再包裹);KEK/KEK2 nonextractable。
28
+ * ⚠️ deriveArgon2id 禁 fallback(零知識):無載體即 throw,禁降級 PBKDF2 或 zeros 兜底。
29
+ * ⚠️ wrappedRec(復原套件)世代化:KEK_rec 派生世代(HKDF,recKekHkdf 配置面)
30
+ * +專用前綴 jr1r.(wrapRec)落地在 note-crypto.ts;本檔 recToken 256-bit 實體因子、
31
+ * KEK 強度無意義的原判不變(世代收的是派生域+契約面分離)。檢查對齊收口:wrapRec+
32
+ * recKekHkdf 兩欄一體(部分配置=ERR_REC_CFG_PARTIAL 拒寫);HKDF 世代前綴面專屬 jr1r.
33
+ * +AAD 'notekey-rec',jr1w. 前綴回歸僅 carrying passphrase-PBKDF2 派生(未配置世代
34
+ * wrappedRec 續走 jr1w.+PBKDF2+'notekey')。
35
+ */
36
+ /** RFC 9106 無 secret/ad 標準向量(Argon2id v=0x13, t=3, m=32, p=4, T=32, pwd=32B 0x01, salt=16B 0x00)。 */
37
+ export declare const ARGON_RFC9106_EXPECTED = "72d2a36fd5c266bcc96121b24937bc253338cdfcbd273713655748c54b4dd503";
38
+ /**
39
+ * PH1 v2 固定域鹽(登入憑證 Argon2id 派生,2026-09-10 安全路線第 4 步)。
40
+ *
41
+ * 固定鹽是被迫設計:per-user 鹽會摧毀 PH2 UNIQUE(同一密語必須恒生同一 ph2,
42
+ * 幽靈帳號機制與「同密語不可開第二帳戶」都靠它)。帶內版本化:改參數 = 換鹽尾碼
43
+ * (v2/v3…)重遷移,禁原地改語意。實長 12B(RFC 9106 鹽最小 8B;Task 0 探針實證)。
44
+ */
45
+ export declare const PH1_V2_SALT = "tacet-ph1-v1";
46
+ /**
47
+ * PH1 v2:登入憑證 = Argon2id(pass, 固定域鹽, m=64MiB, t=3, p=1) → hex64。
48
+ *
49
+ * 動機:DB 全洩後 ph2 = sha256(ph1) 是離線爆破讀日記的最後一個快雜湊面(候選密語
50
+ * 重算 sha256(sha256(g)) 對 ph2 命中即 g 是密語)。ph1 改 Argon2id 派生後每猜成本
51
+ * ×10⁴-10⁶。參數沿 jr3w. 同一組常數(單一碼路);無載體即 throw(禁 fallback 鐵律)。
52
+ */
53
+ export declare function derivePh1Argon(passphrase: string, saltArg?: Uint8Array): Promise<string>;
54
+ /**
55
+ * PH1 v3 鹽(密語正規化 v3 世代):'tacet-ph1-v2'——鹽域版本代沿
56
+ * PH1_V2_SALT(常數名='tacet-ph1-v1')既有先例模式:常數名=PH1 規格代、鹽域值=鹽域代。
57
+ * 鹽域世代分離:若續用 v2 鹽域,v3 世代(normalizePassphrase 後 'PASS'→'PASS')與
58
+ * v2 世代 raw 'PASS' 會派生出同一 ph2=跨世代帳戶空間混合;新鹽域把跨世代 identity
59
+ * 問題留在遷移層查表(v2-first 三腿查表職責),核心層零承擔。
60
+ * ⚠️ 鹽撞位警告(NFKC-effective 帳):`PH1_V3_SALT` 禁當 `derivePh1Argon` 的
61
+ * `saltArg` 餵入——v3 派生輸入吃 normalizePassphrase,同鹽域值錯面餵入=NFKC-effective
62
+ * 密語與 v2 raw 密語同值撞 ph2。fork 對兩面自選鹽時兩值必須互異(README PH1 節同款警告)。
63
+ */
64
+ export declare const PH1_V3_SALT = "tacet-ph1-v2";
65
+ /**
66
+ * PH1 v3:登入憑證 = Argon2id(normalizePassphrase(pass), 固定域鹽, m=64MiB, t=3, p=1) → hex64。
67
+ * 正規化收口在入口(密語 v3 契約 NFKC-only——normalizePassphrase 檔頭三面單一真相);
68
+ * 鹽可注入(saltArg 慣例:預設 PH1_V3_SALT;per-product 恆固定=PH2 UNIQUE 約束同 v2 母型)。
69
+ * 參數沿 jr3w./PH1 v2 同一組常數(單一碼路);無載體即 throw(禁 fallback 鐵律)。
70
+ * v2/legacy 契約面零動:derivePh1Argon 不吃正規化(舊世代 raw 派生,帶內版本化)。
71
+ */
72
+ export declare function derivePh1ArgonV3(passphrase: string, saltArg?: Uint8Array): Promise<string>;
73
+ /** Argon2id 參數(jr3w./jr3d. pass 段;前綴即版本,參數寫死本模組)。 */
74
+ export declare const ARGON_MEMORY_KIB = 65536;
75
+ export declare const ARGON_ITERATIONS = 3;
76
+ export declare const ARGON_PARALLELISM = 1;
77
+ export declare const ARGON_TAG_LEN = 32;
78
+ /** 雙因子 pin 段 Argon2id 參數(PIN 弱 → 記憶體補償;與 pass 段同級)。 */
79
+ export declare const ARGON_PIN_MEMORY_KIB = 65536;
80
+ export declare const ARGON_PIN_ITERATIONS = 3;
81
+ export declare const ARGON_PIN_PARALLELISM = 1;
82
+ /** jr3w 家族前綴(各 fork config 注入;未配置 = jr3w API 拒絕,兄弟 fork 行為不變)。 */
83
+ export interface Argon3Config {
84
+ /** 單因子包裹前綴,如 'jr3w.'。未配置 = 拒絕。 */
85
+ wrap3?: string;
86
+ /** 雙因子包裹前綴,如 'jr3d.'。未配置 = 拒絕。 */
87
+ wrapDual3?: string;
88
+ /** 雙因子 pin 段 Argon2id salt 前綴,如 'tacet-note-pin3:'(拼接 hex(pinSalt) 後整串當 salt)。 */
89
+ pinSalt3Prefix?: string;
90
+ /** 分享包裹前綴(jr3s.,單篇分享連結 Argon2id 版)。未配置 = 分享 API 拒絕(兄弟 fork 行為不變)。 */
91
+ wrapShare3?: string;
92
+ /** 密語正規化 v3 世代單因子包裹前綴(jr4w.,KEK=Argon2id(normalizePassphrase(pass)))。未配置 = 拒絕。 */
93
+ wrap4?: string;
94
+ /** 密語正規化 v3 世代雙因子包裹前綴(jr4d.,pass 段正規化+PIN 段照舊)。未配置 = 拒絕。 */
95
+ wrapDual4?: string;
96
+ }
97
+ interface HashWasmArgon2id {
98
+ (params: {
99
+ password: string | Uint8Array;
100
+ salt: Uint8Array;
101
+ iterations: number;
102
+ parallelism: number;
103
+ memorySize: number;
104
+ hashLength: number;
105
+ outputType: 'binary' | 'hex' | 'encoded';
106
+ }): Promise<Uint8Array | string>;
107
+ }
108
+ type ArgonLoader = () => Promise<{
109
+ argon2id: HashWasmArgon2id;
110
+ }>;
111
+ /** 載體注入(瀏覽器端由接線層指定 hash-wasm;node 端不注入走 node:crypto 原生)。 */
112
+ export declare function setArgonLoader(loader: ArgonLoader | null): void;
113
+ /** 標準向量 KAT:驗證當前載體的 Argon2id 實作正確性(驗證閘起手式)。 */
114
+ export declare function verifyArgonKat(): Promise<boolean>;
115
+ /** KEK = Argon2id(pass, salt, m=64MiB, t=3, p=1) → AES-GCM key(nonextractable)。 */
116
+ export declare function deriveKekArgon(password: string, salt: Uint8Array): Promise<CryptoKey>;
117
+ /** jr3w. 包裹:payload = salt[16] ‖ iv[12] ‖ AES-GCM(KEK, hex(noteKey), aad='notekey');salt 由呼叫端存 users.salt。 */
118
+ export declare function wrapNoteKey3(cfg: Argon3Config, noteKey: CryptoKey, passphrase: string): Promise<{
119
+ wrapped: string;
120
+ salt: string;
121
+ }>;
122
+ /** jr3w. 解包:任何不符(前綴/salt 形/長度/AAD)回 null 不拋;成功 → noteKey extractable=true(鐵律 4)。
123
+ * 快速前綴快檢在場(deriveKekArgon 前——t_87ef62dd;unwrapNoteKey4 母型):錯前綴 junk 免付 Argon。
124
+ * 收口 openNoteKey:嚴格 92B+rawHex 形+hex fail-closed 全在共用核心;本函式只做
125
+ * 家族守衛(wrap3 未配置回 null)、salt1 hex-形檢查與 KEK 派生——payload 形是鹽外置家族(iv‖ct),
126
+ * own 92B 檢已隨收口摘除(jr3s 同;鹽內嵌族 own 108B 保留)。 */
127
+ export declare function unwrapNoteKey3(cfg: Argon3Config, wrapped: string, passphrase: string, saltHex: string): Promise<CryptoKey | null>;
128
+ /** jr4w. 包裹(v3 密語):payload = salt[16] ‖ iv[12] ‖ GCM(KEK, hex(noteKey), aad='notekey');salt 呼叫端存 users.salt。 */
129
+ export declare function wrapNoteKey4(cfg: Argon3Config, noteKey: CryptoKey, passphrase: string): Promise<{
130
+ wrapped: string;
131
+ salt: string;
132
+ }>;
133
+ /** jr4w. 解包(v3 密語):任何不符(前綴/salt 形/長度/AAD)回 null 不拋;成功 → noteKey extractable=true(鐵律 4)。
134
+ * 家族守衛(wrap4 未配置回 null)+快速前綴快檢(錯前綴 junk 免付 64 MiB Argon)+salt hex-形檢+
135
+ * KEK 派生(normalizePassphrase 收口在入口)——payload 形檢在 openNoteKey 本體(鹽外置家族:嚴格 92B+
136
+ * rawHex 形+hex fail-closed)。 */
137
+ export declare function unwrapNoteKey4(cfg: Argon3Config, wrapped: string, passphrase: string, saltHex: string): Promise<CryptoKey | null>;
138
+ /** jr3d. 包裹:payload = pinSalt[16] ‖ iv[12] ‖ GCM(KEK2, hex(noteKey), aad='notekey2');salt1 由呼叫端存 users.salt。 */
139
+ export declare function wrapNoteKeyDual3(cfg: Argon3Config, noteKey: CryptoKey, passphrase: string, pin: string): Promise<{
140
+ wrapped: string;
141
+ salt: string;
142
+ }>;
143
+ /** jr3d. 解包:pinSalt 內嵌自描述,salt1 取自 login 回應;任何不符回 null,不拋。
144
+ * 嚴格檢查為鹽內嵌族自有——payload 嚴格 108B(pinSalt 16
145
+ * + iv 12+ct 80)+ decryptWithKey 後 rawHex hex 形檢查(hexToBytes fail-closed),
146
+ * 不經 openNoteKey 本體(鹽外置 92B 形);與 openNoteKey 同嚴格度。 */
147
+ export declare function unwrapNoteKeyDual3(cfg: Argon3Config, wrapped: string, passphrase: string, pin: string, salt1Hex: string): Promise<CryptoKey | null>;
148
+ /** jr4d. 包裹(v3 密語):payload = pinSalt[16] ‖ iv[12] ‖ GCM(KEK2, hex(noteKey), aad='notekey2');salt1 呼叫端存 users.salt。 */
149
+ export declare function wrapNoteKeyDual4(cfg: Argon3Config, noteKey: CryptoKey, passphrase: string, pin: string): Promise<{
150
+ wrapped: string;
151
+ salt: string;
152
+ }>;
153
+ export declare function unwrapNoteKeyDual4(cfg: Argon3Config, wrapped: string, passphrase: string, pin: string, salt1Hex: string): Promise<CryptoKey | null>;
154
+ /** jr3s. 包裹:salt 隨機 16 bytes(hex 由呼叫端存 shares.salt)。 */
155
+ export declare function wrapNoteKeyShare3(cfg: Argon3Config, noteKey: CryptoKey, sharePass: string): Promise<{
156
+ wrapped: string;
157
+ salt: string;
158
+ }>;
159
+ /** jr3s. 解包:salt 取自 GET /shares/:hash 回應(與 jr1w 同形);任何不符回 null,不拋。
160
+ * 快速前綴快檢在場(deriveKekArgon 前——t_87ef62dd;unwrapNoteKey4 母型):錯前綴 junk 免付 Argon。
161
+ * 收口 openNoteKey:鹽外置家族(payload 嚴格 92B+rawHex 形+hex fail-closed
162
+ * 全在共用核心);本函式只做家族守衛、salt hex-形檢查與 KEK 派生——own 92B 檢已隨收口摘除。 */
163
+ export declare function unwrapNoteKeyShare3(cfg: Argon3Config, wrapped: string, sharePass: string, saltHex: string): Promise<CryptoKey | null>;
164
+ /** jr4d. 解包(重取 salt1 面):pinSalt 內嵌自描述,salt1 由呼叫端重取後帶入(ladder 遷移後的新値);任何不符回 null,不拋。 */
165
+ export declare function unwrapNoteKeyDual4WithSalt(cfg: Argon3Config, wrapped: string, passphrase: string, pin: string, salt1Hex: string): Promise<CryptoKey | null>;
166
+ export {};