@wishknish/knishio-client-ts 0.9.8 → 1.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wishknish/knishio-client-ts",
3
- "version": "0.9.8",
3
+ "version": "1.0.0",
4
4
  "productName": "Knish.IO TypeScript SDK Client",
5
5
  "description": "TypeScript implementation of the Knish.IO SDK to consume Knish.IO GraphQL APIs with enhanced type safety.",
6
6
  "license": "GPL-3.0-or-later",
@@ -51,7 +51,7 @@
51
51
  "quantum-safe",
52
52
  "sdk",
53
53
  "typescript",
54
- "ml-kem768",
54
+ "ml-kem1024",
55
55
  "cryptography",
56
56
  "crystals-kyber",
57
57
  "fips-202",
@@ -112,6 +112,6 @@
112
112
  ],
113
113
  "packageManager": "yarn@4.15.0",
114
114
  "engines": {
115
- "node": ">=18.0.0"
115
+ "node": ">=20.0.0"
116
116
  }
117
117
  }
package/src/AuthToken.ts CHANGED
@@ -48,6 +48,25 @@ License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
48
48
 
49
49
  import Wallet from '@/core/Wallet'
50
50
 
51
+ /**
52
+ * Persisted session shape. Shared by {@link AuthToken.restore} and {@link AuthToken.toSnapshot}
53
+ * so the two can never drift: a field either round-trips or neither side compiles.
54
+ *
55
+ * `wallet.mlKemParameterSet` is optional because snapshots persisted before ML-KEM-1024 became
56
+ * the default do not carry it — see {@link AuthToken.resolveMlKemParameterSet}.
57
+ */
58
+ export type AuthTokenSnapshot = {
59
+ token: string
60
+ expiresAt: number
61
+ pubkey: string
62
+ encrypt: boolean
63
+ wallet?: {
64
+ position: string | null
65
+ characters: string | null
66
+ mlKemParameterSet?: 1024 | 768
67
+ }
68
+ }
69
+
51
70
  /**
52
71
  * AuthToken class for managing authentication tokens
53
72
  */
@@ -93,25 +112,34 @@ export default class AuthToken {
93
112
  }
94
113
 
95
114
  /**
96
- * Restore AuthToken from snapshot
115
+ * ML-KEM parameter set a restored session must use, resolved in three tiers:
116
+ * an explicit snapshot field, then the stored validator key's length, then ML-KEM-768.
117
+ *
118
+ * The final tier is deliberately NOT the constructor default. A snapshot with neither an
119
+ * explicit field nor a recognisable key can only have come from a pre-bump build, and every
120
+ * pre-bump build was 768-only — defaulting to 1024 would make the restored wallet advertise
121
+ * a public key the validator never recorded for that token.
97
122
  */
98
- static restore(snapshot: {
99
- token: string
100
- expiresAt: number
101
- pubkey: string
102
- encrypt: boolean
103
- wallet: {
104
- position: string
105
- characters: string | null
123
+ static resolveMlKemParameterSet(snapshot: AuthTokenSnapshot): 1024 | 768 {
124
+ const explicit = snapshot.wallet?.mlKemParameterSet
125
+ if (explicit) {
126
+ return Number(explicit) === 768 ? 768 : 1024
106
127
  }
107
- }, secret: string): AuthToken {
128
+ return Wallet.mlKemParameterSetFromPubkey(snapshot.pubkey) ?? 768
129
+ }
130
+
131
+ /**
132
+ * Restore AuthToken from snapshot
133
+ */
134
+ static restore(snapshot: AuthTokenSnapshot, secret: string): AuthToken {
108
135
  const wallet = new Wallet({
109
136
  secret,
110
137
  token: 'AUTH',
111
- position: snapshot.wallet.position,
112
- characters: snapshot.wallet.characters
138
+ position: snapshot.wallet?.position ?? null,
139
+ characters: snapshot.wallet?.characters ?? null,
140
+ mlKemParameterSet: AuthToken.resolveMlKemParameterSet(snapshot)
113
141
  })
114
-
142
+
115
143
  return AuthToken.create({
116
144
  token: snapshot.token,
117
145
  expiresAt: snapshot.expiresAt,
@@ -192,18 +220,11 @@ export default class AuthToken {
192
220
  }
193
221
 
194
222
  /**
195
- * Create snapshot for persistence
223
+ * Create snapshot for persistence. The wallet's ML-KEM parameter set is recorded beside its
224
+ * position and characters so a stepped-back ML-KEM-768 session restores as 768 rather than
225
+ * silently taking the constructor default.
196
226
  */
197
- toSnapshot(): {
198
- token: string
199
- expiresAt: number
200
- pubkey: string
201
- encrypt: boolean
202
- wallet?: {
203
- position: string | null
204
- characters: string | null
205
- }
206
- } {
227
+ toSnapshot(): AuthTokenSnapshot {
207
228
  return {
208
229
  token: this.$__token,
209
230
  expiresAt: this.$__expiresAt,
@@ -212,7 +233,8 @@ export default class AuthToken {
212
233
  ...(this.$__wallet ? {
213
234
  wallet: {
214
235
  position: this.$__wallet.position,
215
- characters: this.$__wallet.characters
236
+ characters: this.$__wallet.characters,
237
+ mlKemParameterSet: this.$__wallet.mlKemParameterSet
216
238
  }
217
239
  } : {})
218
240
  }
@@ -166,6 +166,7 @@ export default class KnishIOClient {
166
166
  private $__authTokenObjects: Record<string, AuthToken | null> = {}
167
167
  private $__authToken: AuthToken | null = null
168
168
  private $__authInProcess: boolean = false
169
+ private $__mlKemParameterSet: 1024 | 768 = 1024
169
170
  private $__remainderWallet: Wallet | null = null
170
171
  private lastMoleculeQuery: Mutation | null = null
171
172
  private abortControllers: Map<string, AbortController> = new Map()
@@ -189,6 +190,7 @@ export default class KnishIOClient {
189
190
  logging?: boolean
190
191
  defaultRequestPolicy?: RequestPolicy | null
191
192
  secretStorage?: ISecretStorageProvider | null
193
+ mlKemParameterSet?: 1024 | 768
192
194
  }) {
193
195
  // Phase 2 Enhancement: Use standardized configuration validation
194
196
  const standardValidationResult = ConfigValidator.validateClientConfig(config)
@@ -238,7 +240,8 @@ export default class KnishIOClient {
238
240
  client: client as GraphQLClient | null,
239
241
  serverSdkVersion,
240
242
  logging,
241
- defaultRequestPolicy
243
+ defaultRequestPolicy,
244
+ mlKemParameterSet: config.mlKemParameterSet ?? 1024
242
245
  })
243
246
 
244
247
  if (config.secretStorage) {
@@ -256,7 +259,8 @@ export default class KnishIOClient {
256
259
  client = null,
257
260
  serverSdkVersion = 3,
258
261
  logging = false,
259
- defaultRequestPolicy = null
262
+ defaultRequestPolicy = null,
263
+ mlKemParameterSet = 1024
260
264
  }: {
261
265
  uri: string | string[]
262
266
  cellSlug?: string | null
@@ -265,10 +269,12 @@ export default class KnishIOClient {
265
269
  serverSdkVersion?: number
266
270
  logging?: boolean
267
271
  defaultRequestPolicy?: RequestPolicy | null
272
+ mlKemParameterSet?: 1024 | 768
268
273
  }): void {
269
274
  this.reset()
270
275
 
271
276
  this.$__logging = logging
277
+ this.setMlKemParameterSet(mlKemParameterSet)
272
278
  this.$__authTokenObjects = {}
273
279
 
274
280
  this.setUri(uri)
@@ -297,6 +303,19 @@ export default class KnishIOClient {
297
303
  // serverSdkVersion. A re-initialize updates it.
298
304
  this.$__defaultRequestPolicy = defaultRequestPolicy
299
305
  }
306
+ getMlKemParameterSet(): 1024 | 768 {
307
+ return this.$__mlKemParameterSet || 1024
308
+ }
309
+
310
+ setMlKemParameterSet(parameterSet: 1024 | 768): this {
311
+ const paramNum = Number(parameterSet) as 1024 | 768
312
+ if (![1024, 768].includes(paramNum)) {
313
+ throw new Error(`KnishIO: unsupported ML-KEM parameter set ${parameterSet}; expected 1024 or 768.`)
314
+ }
315
+ this.$__mlKemParameterSet = paramNum
316
+ return this
317
+ }
318
+
300
319
 
301
320
  /**
302
321
  * Get random uri from specified this.$__uris
@@ -589,7 +608,8 @@ export default class KnishIOClient {
589
608
  bundle,
590
609
  token: 'USER',
591
610
  batchId: sourceWallet!.batchId,
592
- characters: sourceWallet!.characters
611
+ characters: sourceWallet!.characters,
612
+ mlKemParameterSet: this.getMlKemParameterSet()
593
613
  }))
594
614
 
595
615
  return new Molecule({
@@ -599,7 +619,8 @@ export default class KnishIOClient {
599
619
  remainderWallet: this.getRemainderWallet()!,
600
620
  cellSlug: this.getCellSlug(),
601
621
  version: this.getServerSdkVersion(),
602
- continuIdPosition
622
+ continuIdPosition,
623
+ mlKemParameterSet: this.getMlKemParameterSet()
603
624
  })
604
625
  }
605
626
 
@@ -756,7 +777,8 @@ export default class KnishIOClient {
756
777
 
757
778
  if (!sourceWallet) {
758
779
  sourceWallet = new Wallet({
759
- secret: this.getSecret()
780
+ secret: this.getSecret(),
781
+ mlKemParameterSet: this.getMlKemParameterSet()
760
782
  })
761
783
  } else {
762
784
  sourceWallet.key = Wallet.generateKey({
@@ -819,7 +841,8 @@ export default class KnishIOClient {
819
841
  // Attempt to get the recipient's wallet
820
842
  const recipientWallet = Wallet.create({
821
843
  bundle: bundleHash,
822
- token
844
+ token,
845
+ mlKemParameterSet: this.getMlKemParameterSet()
823
846
  })
824
847
 
825
848
  // Compute the batch ID for the recipient (typically used by stackable tokens)
@@ -909,7 +932,8 @@ export default class KnishIOClient {
909
932
  const recipientWallets: Wallet[] = recipients.map(recipient => {
910
933
  const recipientWallet = Wallet.create({
911
934
  bundle: recipient.bundleHash,
912
- token
935
+ token,
936
+ mlKemParameterSet: this.getMlKemParameterSet()
913
937
  })
914
938
  if (recipient.batchId !== null && recipient.batchId !== undefined) {
915
939
  recipientWallet.batchId = recipient.batchId
@@ -1774,7 +1798,8 @@ export default class KnishIOClient {
1774
1798
  secret: this.getSecret(),
1775
1799
  bundle: this.getBundle(),
1776
1800
  token,
1777
- batchId: batchId as any
1801
+ batchId: batchId as any,
1802
+ mlKemParameterSet: this.getMlKemParameterSet()
1778
1803
  })
1779
1804
 
1780
1805
  // Initialize the create token mutation
@@ -1880,7 +1905,8 @@ export default class KnishIOClient {
1880
1905
  const recipientWallet = new Wallet({
1881
1906
  secret: this.getSecret(),
1882
1907
  bundle: '0000000000000000000000000000000000000000000000000000000000000000',
1883
- token
1908
+ token,
1909
+ mlKemParameterSet: this.getMlKemParameterSet()
1884
1910
  })
1885
1911
 
1886
1912
  await mutation.fillMolecule({
@@ -1993,7 +2019,8 @@ export default class KnishIOClient {
1993
2019
  const newWallet = new Wallet({
1994
2020
  secret: this.getSecret(),
1995
2021
  bundle: this.getBundle(),
1996
- token
2022
+ token,
2023
+ mlKemParameterSet: this.getMlKemParameterSet()
1997
2024
  })
1998
2025
 
1999
2026
  // Initialize the create wallet mutation
@@ -2499,7 +2526,8 @@ export default class KnishIOClient {
2499
2526
  // Generate a signing wallet with AUTH token (matching JavaScript SDK)
2500
2527
  const wallet = new Wallet({
2501
2528
  secret,
2502
- token: 'AUTH'
2529
+ token: 'AUTH',
2530
+ mlKemParameterSet: this.getMlKemParameterSet()
2503
2531
  })
2504
2532
 
2505
2533
  // Create a molecule with the AUTH wallet as source
@@ -2515,7 +2543,7 @@ export default class KnishIOClient {
2515
2543
  })
2516
2544
 
2517
2545
  // Initialize the profile auth mutation.
2518
- // PQ-transport Phase E: convey the AUTH source wallet's ML-KEM768 public key as a SIGNED
2546
+ // PQ-transport Phase E: convey the AUTH source wallet's ML-KEM public key as a SIGNED
2519
2547
  // walletPubkey U-atom meta, so the validator can encrypt CipherHash responses back to THIS
2520
2548
  // wallet (the one that decrypts them). Signed → MITM can't swap the target. Conveyed
2521
2549
  // unconditionally (parity with JS/Kotlin/PHP), so even a plaintext auth primes enc_pubkey.
@@ -81,6 +81,7 @@ export default class Molecule {
81
81
  public continuIdPosition: string | null
82
82
  public parentHashes: string[]
83
83
  public local?: number
84
+ public mlKemParameterSet: 1024 | 768 = 1024
84
85
 
85
86
  /**
86
87
  * Create new Molecule instance
@@ -93,7 +94,8 @@ export default class Molecule {
93
94
  remainderWallet = null,
94
95
  cellSlug = null,
95
96
  version = null,
96
- continuIdPosition = null
97
+ continuIdPosition = null,
98
+ mlKemParameterSet = null
97
99
  }: {
98
100
  secret?: string | null
99
101
  bundle?: string | null
@@ -102,6 +104,7 @@ export default class Molecule {
102
104
  cellSlug?: string | null
103
105
  version?: string | number | null
104
106
  continuIdPosition?: string | null
107
+ mlKemParameterSet?: 1024 | 768 | null
105
108
  } = {}) {
106
109
  this.status = null
107
110
  this.molecularHash = null
@@ -113,6 +116,7 @@ export default class Molecule {
113
116
  this.continuIdPosition = continuIdPosition
114
117
  this.atoms = []
115
118
  this.parentHashes = []
119
+ this.mlKemParameterSet = mlKemParameterSet || sourceWallet?.mlKemParameterSet || 1024
116
120
 
117
121
  const versionRegistry = versions as Record<string | number, any>
118
122
  if (version !== null && Object.prototype.hasOwnProperty.call(versionRegistry, version)) {
@@ -129,7 +133,8 @@ export default class Molecule {
129
133
  bundle,
130
134
  token: sourceWallet!.token,
131
135
  batchId: sourceWallet!.batchId,
132
- characters: sourceWallet!.characters
136
+ characters: sourceWallet!.characters,
137
+ mlKemParameterSet: this.mlKemParameterSet
133
138
  })
134
139
  } else {
135
140
  this.remainderWallet = null
@@ -206,7 +211,8 @@ export default class Molecule {
206
211
  if (!this.remainderWallet || this.remainderWallet.token !== 'USER') {
207
212
  this.remainderWallet = Wallet.create({
208
213
  secret: this.secret!,
209
- bundle: this.bundle!
214
+ bundle: this.bundle!,
215
+ mlKemParameterSet: this.mlKemParameterSet
210
216
  })
211
217
  }
212
218
 
@@ -724,7 +730,8 @@ export default class Molecule {
724
730
  // Create burn address wallet (null bundle = token destruction)
725
731
  const burnWallet = new Wallet({
726
732
  bundle: '0000000000000000000000000000000000000000000000000000000000000000',
727
- token: this.sourceWallet.token
733
+ token: this.sourceWallet.token,
734
+ mlKemParameterSet: this.mlKemParameterSet
728
735
  })
729
736
 
730
737
  // V-atom 1: Debit full balance from source
@@ -1099,7 +1106,8 @@ export default class Molecule {
1099
1106
  position: data.sourceWallet.position,
1100
1107
  bundle: data.sourceWallet.bundle,
1101
1108
  batchId: data.sourceWallet.batchId,
1102
- characters: data.sourceWallet.characters
1109
+ characters: data.sourceWallet.characters,
1110
+ mlKemParameterSet: molecule.mlKemParameterSet
1103
1111
  })
1104
1112
 
1105
1113
  // Set additional properties for validation context
@@ -1121,7 +1129,8 @@ export default class Molecule {
1121
1129
  position: data.remainderWallet.position,
1122
1130
  bundle: data.remainderWallet.bundle,
1123
1131
  batchId: data.remainderWallet.batchId,
1124
- characters: data.remainderWallet.characters
1132
+ characters: data.remainderWallet.characters,
1133
+ mlKemParameterSet: molecule.mlKemParameterSet
1125
1134
  })
1126
1135
 
1127
1136
  // Set additional properties for validation context
@@ -1245,7 +1254,8 @@ export default class Molecule {
1245
1254
  secret: this.secret!,
1246
1255
  bundle: this.bundle,
1247
1256
  token: this.sourceWallet.token,
1248
- batchId: this.sourceWallet.batchId
1257
+ batchId: this.sourceWallet.batchId,
1258
+ mlKemParameterSet: this.mlKemParameterSet
1249
1259
  })
1250
1260
  if (tradeRates) {
1251
1261
  bufferWallet.tradeRates = tradeRates