@wishknish/knishio-client-ts 0.9.7 → 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/dist/index.cjs +237 -52
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -36
- package/dist/index.d.ts +42 -36
- package/dist/index.iife.js +238 -52
- package/dist/index.iife.js.map +1 -1
- package/dist/index.js +238 -53
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/AuthToken.ts +47 -25
- package/src/KnishIOClient.ts +62 -17
- package/src/core/Molecule.ts +17 -7
- package/src/core/Wallet.ts +161 -32
- package/src/index.ts +2 -2
- package/src/libraries/GraphQLClient.ts +2 -2
- package/src/mutation/MutationProposeMolecule.ts +7 -4
- package/src/schemas/index.ts +2 -1
- package/src/types/crypto.ts +9 -4
- package/src/validation/schemas.ts +2 -1
package/src/core/Wallet.ts
CHANGED
|
@@ -52,8 +52,17 @@ import { generateBundleHash, generateSecret, shake256, generateBatchId } from '@
|
|
|
52
52
|
import WalletCredentialException from '@/exception/WalletCredentialException'
|
|
53
53
|
import { isBundleHash } from '@/types'
|
|
54
54
|
import TokenUnit from '@/core/TokenUnit'
|
|
55
|
-
// Post-quantum cryptography for ML-
|
|
56
|
-
import { ml_kem768 } from '@noble/post-quantum/ml-kem.js'
|
|
55
|
+
// Post-quantum cryptography for ML-KEM key encapsulation
|
|
56
|
+
import { ml_kem768, ml_kem1024 } from '@noble/post-quantum/ml-kem.js'
|
|
57
|
+
|
|
58
|
+
const ML_KEM_PARAMS = {
|
|
59
|
+
1024: { kem: ml_kem1024, pkBytes: 1568, skBytes: 3168, ctBytes: 1568 },
|
|
60
|
+
768: { kem: ml_kem768, pkBytes: 1184, skBytes: 2400, ctBytes: 1088 }
|
|
61
|
+
} as const
|
|
62
|
+
const DEFAULT_ML_KEM_PARAMETER_SET = 1024
|
|
63
|
+
|
|
64
|
+
type MlKemParams = (typeof ML_KEM_PARAMS)[1024 | 768]
|
|
65
|
+
type MlKemKeypair = { pubkey: string; privkey: Uint8Array; params: MlKemParams }
|
|
57
66
|
|
|
58
67
|
/**
|
|
59
68
|
* Wallet class - Identity and key management for KnishIO DLT
|
|
@@ -73,6 +82,7 @@ export default class Wallet {
|
|
|
73
82
|
public tokenUnits: any[]
|
|
74
83
|
public tradeRates: Record<string, any>
|
|
75
84
|
public molecules: Record<string, any>
|
|
85
|
+
public mlKemParameterSet: 1024 | 768
|
|
76
86
|
|
|
77
87
|
// Token metadata (populated from query responses)
|
|
78
88
|
public tokenName?: string
|
|
@@ -88,7 +98,8 @@ export default class Wallet {
|
|
|
88
98
|
address = null,
|
|
89
99
|
position = null,
|
|
90
100
|
batchId = null,
|
|
91
|
-
characters = null
|
|
101
|
+
characters = null,
|
|
102
|
+
mlKemParameterSet = DEFAULT_ML_KEM_PARAMETER_SET
|
|
92
103
|
}: {
|
|
93
104
|
secret?: string | null
|
|
94
105
|
bundle?: string | null
|
|
@@ -97,7 +108,13 @@ export default class Wallet {
|
|
|
97
108
|
position?: string | null
|
|
98
109
|
batchId?: string | null
|
|
99
110
|
characters?: string | null
|
|
111
|
+
mlKemParameterSet?: 1024 | 768
|
|
100
112
|
} = {}) {
|
|
113
|
+
const paramSetNum = Number(mlKemParameterSet) as 1024 | 768
|
|
114
|
+
if (!ML_KEM_PARAMS[paramSetNum]) {
|
|
115
|
+
throw new Error(`KnishIO: unsupported ML-KEM parameter set ${mlKemParameterSet}; expected 1024 or 768.`)
|
|
116
|
+
}
|
|
117
|
+
this.mlKemParameterSet = paramSetNum
|
|
101
118
|
this.token = token
|
|
102
119
|
this.balance = '0'
|
|
103
120
|
this.molecules = {}
|
|
@@ -133,7 +150,7 @@ export default class Wallet {
|
|
|
133
150
|
// Set characters
|
|
134
151
|
this.characters = this.characters || 'BASE64'
|
|
135
152
|
|
|
136
|
-
// Initialize ML-
|
|
153
|
+
// Initialize ML-KEM keys (matches JavaScript SDK)
|
|
137
154
|
this.initializeMLKEM()
|
|
138
155
|
}
|
|
139
156
|
}
|
|
@@ -147,13 +164,15 @@ export default class Wallet {
|
|
|
147
164
|
bundle = null,
|
|
148
165
|
token = 'USER',
|
|
149
166
|
batchId = null,
|
|
150
|
-
characters = null
|
|
167
|
+
characters = null,
|
|
168
|
+
mlKemParameterSet = DEFAULT_ML_KEM_PARAMETER_SET
|
|
151
169
|
}: {
|
|
152
170
|
secret?: string | null
|
|
153
171
|
bundle?: string | null
|
|
154
172
|
token?: string
|
|
155
173
|
batchId?: string | null
|
|
156
174
|
characters?: string | null
|
|
175
|
+
mlKemParameterSet?: 1024 | 768
|
|
157
176
|
}): Wallet {
|
|
158
177
|
let position: string | null = null
|
|
159
178
|
|
|
@@ -176,7 +195,8 @@ export default class Wallet {
|
|
|
176
195
|
token,
|
|
177
196
|
position,
|
|
178
197
|
batchId,
|
|
179
|
-
characters
|
|
198
|
+
characters,
|
|
199
|
+
mlKemParameterSet
|
|
180
200
|
})
|
|
181
201
|
}
|
|
182
202
|
|
|
@@ -408,26 +428,90 @@ export default class Wallet {
|
|
|
408
428
|
}
|
|
409
429
|
|
|
410
430
|
// =============================================================================
|
|
411
|
-
// POST-QUANTUM CRYPTOGRAPHY - ML-
|
|
431
|
+
// POST-QUANTUM CRYPTOGRAPHY - ML-KEM INTEGRATION
|
|
412
432
|
// =============================================================================
|
|
413
433
|
|
|
414
434
|
/**
|
|
415
|
-
*
|
|
435
|
+
* Derive an ML-KEM keypair for an arbitrary parameter set from the wallet's key seed,
|
|
436
|
+
* without mutating the wallet. The 64-byte `d‖z` seed takes no parameter-set input — only
|
|
437
|
+
* the final `keygen` call differs — so one KnishIO wallet owns both an ML-KEM-768 and an
|
|
438
|
+
* ML-KEM-1024 identity and either can be reconstructed on demand.
|
|
439
|
+
*
|
|
440
|
+
* Returns `null` when the wallet holds no key — a secret-less wallet, which is what a molecule
|
|
441
|
+
* deserializer builds for validation context. `generateSecret(null, …)` does NOT throw, so
|
|
442
|
+
* without this the wallet would derive a plausible-looking identity from a bogus seed and fail
|
|
443
|
+
* three layers down at AES-GCM instead of at the missing key. The guard lives here rather than
|
|
444
|
+
* at each call site so a new caller cannot miss it.
|
|
445
|
+
*
|
|
446
|
+
* @param parameterSet - 1024 or 768
|
|
416
447
|
*/
|
|
417
|
-
|
|
448
|
+
private deriveMlKemKeypair(parameterSet: 1024 | 768): MlKemKeypair | null {
|
|
449
|
+
const params = ML_KEM_PARAMS[parameterSet]
|
|
450
|
+
if (!params) {
|
|
451
|
+
throw new Error(`KnishIO: unsupported ML-KEM parameter set ${parameterSet}; expected 1024 or 768.`)
|
|
452
|
+
}
|
|
453
|
+
if (!this.key) {
|
|
454
|
+
return null
|
|
455
|
+
}
|
|
418
456
|
// Generate a 64-byte (512-bit) seed from the Knish.IO private key
|
|
419
457
|
// Use deterministic approach: generateSecret(key, 128) → 128 hex chars = 64 bytes
|
|
420
|
-
const seedHex = generateSecret(this.key
|
|
421
|
-
|
|
422
|
-
// Convert the hex string to a Uint8Array
|
|
458
|
+
const seedHex = generateSecret(this.key, 128) // 128 hex chars = 64 bytes, matches JS SDK
|
|
459
|
+
|
|
460
|
+
// Convert the hex string to a Uint8Array
|
|
423
461
|
const seed = new Uint8Array(64)
|
|
424
462
|
for (let i = 0; i < 64; i++) {
|
|
425
463
|
seed[i] = parseInt(seedHex.substr(i * 2, 2), 16)
|
|
426
464
|
}
|
|
427
|
-
|
|
428
|
-
const { publicKey, secretKey } =
|
|
429
|
-
|
|
430
|
-
|
|
465
|
+
|
|
466
|
+
const { publicKey, secretKey } = params.kem.keygen(seed)
|
|
467
|
+
return {
|
|
468
|
+
pubkey: this.serializeKey(publicKey),
|
|
469
|
+
privkey: secretKey,
|
|
470
|
+
params
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
/**
|
|
475
|
+
* ML-KEM parameter set implied by a serialized public key's raw byte length. FIPS 203's key
|
|
476
|
+
* lengths are disjoint (1568 bytes → ML-KEM-1024, 1184 bytes → ML-KEM-768), so a stored peer
|
|
477
|
+
* key recovers the parameter set of the session it belongs to without a wire-format change.
|
|
478
|
+
* Used by AuthToken.restore to resolve a snapshot that predates the field.
|
|
479
|
+
*
|
|
480
|
+
* @param pubkey - Base64-serialized ML-KEM public key
|
|
481
|
+
* @return 1024, 768, or null when the length matches neither
|
|
482
|
+
*/
|
|
483
|
+
static mlKemParameterSetFromPubkey(pubkey: string | null | undefined): 1024 | 768 | null {
|
|
484
|
+
if (!pubkey) {
|
|
485
|
+
return null
|
|
486
|
+
}
|
|
487
|
+
let byteLength: number
|
|
488
|
+
try {
|
|
489
|
+
byteLength = typeof Buffer !== 'undefined'
|
|
490
|
+
? Buffer.from(pubkey, 'base64').length
|
|
491
|
+
: atob(pubkey).length
|
|
492
|
+
} catch {
|
|
493
|
+
return null
|
|
494
|
+
}
|
|
495
|
+
if (byteLength === ML_KEM_PARAMS[1024].pkBytes) {
|
|
496
|
+
return 1024
|
|
497
|
+
}
|
|
498
|
+
if (byteLength === ML_KEM_PARAMS[768].pkBytes) {
|
|
499
|
+
return 768
|
|
500
|
+
}
|
|
501
|
+
return null
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Initializes the ML-KEM key pair (matches JavaScript SDK exactly). Only ever reached from the
|
|
506
|
+
* constructor's `secret` branch, so the derivation cannot come back empty here.
|
|
507
|
+
*/
|
|
508
|
+
initializeMLKEM(): void {
|
|
509
|
+
const derived = this.deriveMlKemKeypair(this.mlKemParameterSet)
|
|
510
|
+
if (!derived) {
|
|
511
|
+
return
|
|
512
|
+
}
|
|
513
|
+
this.pubkey = derived.pubkey
|
|
514
|
+
this.privkey = derived.privkey // Note: We're keeping privkey as UInt8Array for security
|
|
431
515
|
}
|
|
432
516
|
|
|
433
517
|
|
|
@@ -439,19 +523,20 @@ export default class Wallet {
|
|
|
439
523
|
const messageString = JSON.stringify(message)
|
|
440
524
|
const messageUint8 = new TextEncoder().encode(messageString)
|
|
441
525
|
const deserializedPubkey = this.deserializeKey(recipientPubkey)
|
|
442
|
-
// ML-KEM
|
|
443
|
-
//
|
|
444
|
-
//
|
|
445
|
-
//
|
|
446
|
-
|
|
447
|
-
|
|
526
|
+
// ML-KEM public keys are exactly the configured parameter set's length — 1568 bytes for
|
|
527
|
+
// ML-KEM-1024, 1184 bytes for ML-KEM-768. A wrong-length key here almost always means the
|
|
528
|
+
// node did not advertise an ML-KEM public key in its auth `key` field (e.g. a validator
|
|
529
|
+
// predating the PQ-transport build). Fail with an actionable message rather than @noble's
|
|
530
|
+
// cryptic `"publicKey" expected Uint8Array of length N, got length=M` assertion.
|
|
531
|
+
const params = ML_KEM_PARAMS[this.mlKemParameterSet]
|
|
532
|
+
if (deserializedPubkey.length !== params.pkBytes) {
|
|
448
533
|
throw new Error(
|
|
449
534
|
`KnishIO: cannot ML-KEM-encrypt — recipient public key is ${deserializedPubkey.length} bytes, ` +
|
|
450
|
-
`expected ${
|
|
451
|
-
|
|
535
|
+
`expected ${params.pkBytes} (ML-KEM-${this.mlKemParameterSet}). The peer is not running ML-KEM-${this.mlKemParameterSet}; ` +
|
|
536
|
+
'upgrade the peer, or step this client back to the other parameter set.'
|
|
452
537
|
)
|
|
453
538
|
}
|
|
454
|
-
const { cipherText, sharedSecret } =
|
|
539
|
+
const { cipherText, sharedSecret } = params.kem.encapsulate(deserializedPubkey)
|
|
455
540
|
const encryptedMessage = await this.encryptWithSharedSecret(messageUint8, sharedSecret)
|
|
456
541
|
return {
|
|
457
542
|
cipherText: this.serializeKey(cipherText),
|
|
@@ -465,15 +550,46 @@ export default class Wallet {
|
|
|
465
550
|
}
|
|
466
551
|
|
|
467
552
|
/**
|
|
468
|
-
* ML-
|
|
553
|
+
* ML-KEM decapsulate + AES-256-GCM decrypt → the RAW decrypted UTF-8 string (no JSON.parse).
|
|
469
554
|
* Shared by {@link decryptMessage} (which JSON.parses the result) and the PQ CipherHash transport
|
|
470
|
-
* ({@link
|
|
555
|
+
* ({@link decryptMyMessageML}, which needs the raw response JSON text). PQ-transport Phase E.
|
|
471
556
|
*/
|
|
472
557
|
async _mlkemDecryptToString(encryptedData: { cipherText: string; encryptedMessage: string }): Promise<string | null> {
|
|
473
558
|
const { cipherText, encryptedMessage } = encryptedData
|
|
559
|
+
const configuredParams = ML_KEM_PARAMS[this.mlKemParameterSet]
|
|
560
|
+
const otherSet: 1024 | 768 = this.mlKemParameterSet === 1024 ? 768 : 1024
|
|
561
|
+
const deserializedCipherText = this.deserializeKey(cipherText)
|
|
562
|
+
|
|
563
|
+
// Inbound is PERMISSIVE: a ciphertext at either parameter set decrypts, provided it is addressed
|
|
564
|
+
// to one of THIS wallet's own ML-KEM identities. The 64-byte seed is parameter-set-independent,
|
|
565
|
+
// so the other identity is derived on demand and its private key is released with this call's
|
|
566
|
+
// scope — never cached on the wallet. Outbound encapsulation stays STRICT (see encryptMessage);
|
|
567
|
+
// reading a 768 record we own downgrades nothing, but encapsulating at 768 would.
|
|
568
|
+
let params: MlKemParams = configuredParams
|
|
569
|
+
let decapsPrivkey: Uint8Array = this.privkey
|
|
570
|
+
if (deserializedCipherText.length !== configuredParams.ctBytes) {
|
|
571
|
+
if (deserializedCipherText.length !== ML_KEM_PARAMS[otherSet].ctBytes) {
|
|
572
|
+
console.error(
|
|
573
|
+
`Wallet::decryptMessage() - Ciphertext length mismatch: got ${deserializedCipherText.length}, expected ${configuredParams.ctBytes}`
|
|
574
|
+
)
|
|
575
|
+
return null
|
|
576
|
+
}
|
|
577
|
+
// `null` here means the wallet holds no key to derive from (a secret-less validation
|
|
578
|
+
// wallet); preserve the existing failure observable rather than decapsulating with nothing.
|
|
579
|
+
const derived = this.deriveMlKemKeypair(otherSet)
|
|
580
|
+
if (!derived) {
|
|
581
|
+
console.error(
|
|
582
|
+
`Wallet::decryptMessage() - cannot derive the ML-KEM-${otherSet} identity: wallet has no key`
|
|
583
|
+
)
|
|
584
|
+
return null
|
|
585
|
+
}
|
|
586
|
+
params = derived.params
|
|
587
|
+
decapsPrivkey = derived.privkey
|
|
588
|
+
}
|
|
589
|
+
|
|
474
590
|
let sharedSecret
|
|
475
591
|
try {
|
|
476
|
-
sharedSecret =
|
|
592
|
+
sharedSecret = params.kem.decapsulate(deserializedCipherText, decapsPrivkey)
|
|
477
593
|
} catch (e) {
|
|
478
594
|
console.error('Wallet::decryptMessage() - Decapsulation failed', e)
|
|
479
595
|
console.info('Wallet::decryptMessage() - my public key', this.pubkey)
|
|
@@ -525,11 +641,11 @@ export default class Wallet {
|
|
|
525
641
|
}
|
|
526
642
|
|
|
527
643
|
/**
|
|
528
|
-
* Post-quantum (ML-
|
|
644
|
+
* Post-quantum (ML-KEM) CipherHash request envelope: a stringified single-recipient map
|
|
529
645
|
* `{ "<hashShare(recipientPubkey)>": {cipherText, encryptedMessage} }` (object-valued, via
|
|
530
646
|
* {@link encryptMessage}). Matches the Rust validator's CipherHash handler. PQ-transport Phase E.
|
|
531
647
|
*/
|
|
532
|
-
async
|
|
648
|
+
async encryptStringML(message: any, recipientPubkey: string): Promise<string> {
|
|
533
649
|
const envelope = await this.encryptMessage(message, recipientPubkey)
|
|
534
650
|
return JSON.stringify({ [this.hashShare(recipientPubkey)]: envelope })
|
|
535
651
|
}
|
|
@@ -538,9 +654,22 @@ export default class Wallet {
|
|
|
538
654
|
* Decrypt a CipherHash response map addressed to THIS wallet's ML-KEM pubkey
|
|
539
655
|
* (`hashShare(this.pubkey)`) → the RAW decrypted GraphQL response JSON text (NOT JSON.parsed;
|
|
540
656
|
* it replaces the HTTP response body for the normal parser). `null` if no entry / decrypt fails.
|
|
657
|
+
*
|
|
658
|
+
* A pre-bump peer addressed its envelope to `hashShare(our_768_pubkey)`, which a wallet
|
|
659
|
+
* configured at ML-KEM-1024 would never find — so the other identity's share is tried too.
|
|
660
|
+
* Without this, the permissive length dispatch in {@link _mlkemDecryptToString} is
|
|
661
|
+
* unreachable on the transport path.
|
|
541
662
|
*/
|
|
542
|
-
async
|
|
543
|
-
|
|
663
|
+
async decryptMyMessageML(map: Record<string, { cipherText: string; encryptedMessage: string }>): Promise<string | null> {
|
|
664
|
+
let envelope = map[this.hashShare(this.pubkey)]
|
|
665
|
+
if (!envelope) {
|
|
666
|
+
// A secret-less wallet derives nothing, so the lookup is simply skipped.
|
|
667
|
+
const otherSet: 1024 | 768 = this.mlKemParameterSet === 1024 ? 768 : 1024
|
|
668
|
+
const other = this.deriveMlKemKeypair(otherSet)
|
|
669
|
+
if (other) {
|
|
670
|
+
envelope = map[this.hashShare(other.pubkey)]
|
|
671
|
+
}
|
|
672
|
+
}
|
|
544
673
|
if (!envelope) {
|
|
545
674
|
return null
|
|
546
675
|
}
|
package/src/index.ts
CHANGED
|
@@ -389,7 +389,7 @@ export {
|
|
|
389
389
|
// MUST equal package.json's "version". The CI `version consistency` job enforces this via
|
|
390
390
|
// .github/scripts/check-version.sh, which parses this exact line — keep the literal form
|
|
391
391
|
// `export const SDK_VERSION = '<semver>'` intact so the gate can read it.
|
|
392
|
-
export const SDK_VERSION = '0.
|
|
392
|
+
export const SDK_VERSION = '1.0.0'
|
|
393
393
|
export const SDK_NAME = 'KnishIO-Client-TS'
|
|
394
394
|
export const COMPATIBLE_SERVER_VERSIONS = [4, 5]
|
|
395
395
|
|
|
@@ -402,7 +402,7 @@ export const SDK_INFO = {
|
|
|
402
402
|
description: 'TypeScript SDK for Knish.IO post-blockchain distributed ledger',
|
|
403
403
|
compatibleServerVersions: COMPATIBLE_SERVER_VERSIONS,
|
|
404
404
|
features: [
|
|
405
|
-
'Post-quantum cryptography (XMSS, ML-
|
|
405
|
+
'Post-quantum cryptography (XMSS, ML-KEM-1024)',
|
|
406
406
|
'Cross-platform compatibility',
|
|
407
407
|
'Type-safe APIs',
|
|
408
408
|
'DAG-based transaction processing',
|
|
@@ -204,7 +204,7 @@ export default class GraphQLClient implements IGraphQLClient {
|
|
|
204
204
|
let requestInit = init
|
|
205
205
|
|
|
206
206
|
if (wallet && serverPubkey && init && typeof init.body === 'string' && this.shouldEncrypt(init.body)) {
|
|
207
|
-
const hashVar = await wallet.
|
|
207
|
+
const hashVar = await wallet.encryptStringML(init.body, serverPubkey)
|
|
208
208
|
requestInit = { ...init, body: JSON.stringify({ query: CIPHER_HASH_QUERY, variables: { Hash: hashVar } }) }
|
|
209
209
|
encryptedRequest = true
|
|
210
210
|
}
|
|
@@ -228,7 +228,7 @@ export default class GraphQLClient implements IGraphQLClient {
|
|
|
228
228
|
// Plaintext (e.g. a validator-side error response) — pass through unchanged.
|
|
229
229
|
return new Response(text, init2)
|
|
230
230
|
}
|
|
231
|
-
const decrypted = await wallet!.
|
|
231
|
+
const decrypted = await wallet!.decryptMyMessageML(JSON.parse(hash))
|
|
232
232
|
return new Response(decrypted != null ? decrypted : text, init2)
|
|
233
233
|
}
|
|
234
234
|
|
|
@@ -57,7 +57,7 @@ import type Molecule from '../core/Molecule'
|
|
|
57
57
|
* MutationProposeMolecule - Foundation for all molecular proposals
|
|
58
58
|
* Matches JavaScript SDK MutationProposeMolecule implementation exactly
|
|
59
59
|
*/
|
|
60
|
-
export default
|
|
60
|
+
export default class MutationProposeMolecule extends Mutation {
|
|
61
61
|
protected $__molecule: Molecule
|
|
62
62
|
protected $__remainderWallet: any | null = null
|
|
63
63
|
|
|
@@ -141,8 +141,11 @@ export default abstract class MutationProposeMolecule extends Mutation {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
/**
|
|
144
|
-
*
|
|
145
|
-
*
|
|
144
|
+
* Fills the molecule with specific mutation data.
|
|
145
|
+
* Subclasses override to build domain-specific atoms.
|
|
146
|
+
* Default implementation is a no-op for pre-assembled molecules.
|
|
146
147
|
*/
|
|
147
|
-
|
|
148
|
+
fillMolecule(_params?: any): void {
|
|
149
|
+
// Intentionally empty for pre-assembled molecules proposed directly
|
|
150
|
+
}
|
|
148
151
|
}
|
package/src/schemas/index.ts
CHANGED
|
@@ -208,7 +208,8 @@ export const KnishIOClientConfigSchema = z.object({
|
|
|
208
208
|
serverSdkVersion: z.number().int().min(1).optional(),
|
|
209
209
|
logging: z.boolean().optional(),
|
|
210
210
|
defaultRequestPolicy: z.enum(['cache-first', 'cache-only', 'network-only', 'cache-and-network']).nullable().optional(),
|
|
211
|
-
secretStorage: z.unknown().optional()
|
|
211
|
+
secretStorage: z.unknown().optional(),
|
|
212
|
+
mlKemParameterSet: z.union([z.literal(1024), z.literal(768)]).optional()
|
|
212
213
|
}).strict()
|
|
213
214
|
|
|
214
215
|
// =============================================================================
|
package/src/types/crypto.ts
CHANGED
|
@@ -58,8 +58,8 @@ import type { WalletAddress, BundleHash, Position, TokenSlug } from './index'
|
|
|
58
58
|
// =============================================================================
|
|
59
59
|
|
|
60
60
|
export type HashAlgorithm = 'SHAKE256' | 'SHA3-256' | 'BLAKE2B'
|
|
61
|
-
export type SignatureAlgorithm = 'XMSS' | '
|
|
62
|
-
export type EncryptionAlgorithm = 'ML-
|
|
61
|
+
export type SignatureAlgorithm = 'XMSS' | 'SPHINCS+'
|
|
62
|
+
export type EncryptionAlgorithm = 'ML-KEM-1024' | 'ML-KEM-768'
|
|
63
63
|
|
|
64
64
|
// =============================================================================
|
|
65
65
|
// SHAKE256 SPECIFIC TYPES
|
|
@@ -139,13 +139,13 @@ export interface XMSSSignature {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
// =============================================================================
|
|
142
|
-
// ML-
|
|
142
|
+
// ML-KEM (Post-Quantum Key Encapsulation) TYPES
|
|
143
143
|
// =============================================================================
|
|
144
144
|
|
|
145
145
|
export interface MLKEMKeyPair {
|
|
146
146
|
privateKey: Uint8Array
|
|
147
147
|
publicKey: Uint8Array
|
|
148
|
-
algorithm:
|
|
148
|
+
algorithm: EncryptionAlgorithm
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
export interface MLKEMEncapsulationResult {
|
|
@@ -475,6 +475,11 @@ export const CRYPTO_CONSTANTS = {
|
|
|
475
475
|
ML_KEM768_PRIVATE_KEY_SIZE: 2400,
|
|
476
476
|
ML_KEM768_CIPHERTEXT_SIZE: 1088,
|
|
477
477
|
ML_KEM768_SHARED_SECRET_SIZE: 32,
|
|
478
|
+
|
|
479
|
+
ML_KEM1024_PUBLIC_KEY_SIZE: 1568,
|
|
480
|
+
ML_KEM1024_PRIVATE_KEY_SIZE: 3168,
|
|
481
|
+
ML_KEM1024_CIPHERTEXT_SIZE: 1568,
|
|
482
|
+
ML_KEM1024_SHARED_SECRET_SIZE: 32,
|
|
478
483
|
|
|
479
484
|
KEY_FRAGMENT_SIZE: 128,
|
|
480
485
|
OTS_FRAGMENT_COUNT: 16,
|
|
@@ -231,7 +231,8 @@ export const KnishIOClientConfigSchema = z.object({
|
|
|
231
231
|
// isn't rejected.
|
|
232
232
|
defaultRequestPolicy: z.enum(['cache-first', 'cache-only', 'network-only', 'cache-and-network']).nullable().optional(),
|
|
233
233
|
// Pluggable hardware envelope encryption secret storage provider
|
|
234
|
-
secretStorage: z.unknown().optional()
|
|
234
|
+
secretStorage: z.unknown().optional(),
|
|
235
|
+
mlKemParameterSet: z.union([z.literal(1024), z.literal(768)]).optional()
|
|
235
236
|
}).strict()
|
|
236
237
|
|
|
237
238
|
// Environment configuration with validation.
|