@wishknish/knishio-client-ts 0.7.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/LICENSE +674 -0
- package/README.md +425 -0
- package/dist/index.cjs +9961 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.iife.js +32241 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.js +9853 -0
- package/dist/index.js.map +1 -0
- package/package.json +113 -0
- package/src/AuthToken.ts +214 -0
- package/src/KnishIOClient.ts +2020 -0
- package/src/constants.ts +398 -0
- package/src/core/Atom.ts +646 -0
- package/src/core/AtomMeta.ts +278 -0
- package/src/core/Meta.ts +428 -0
- package/src/core/Molecule.ts +825 -0
- package/src/core/PolicyMeta.ts +130 -0
- package/src/core/TokenUnit.ts +148 -0
- package/src/core/Wallet.ts +467 -0
- package/src/exception/AtomIndexException.ts +97 -0
- package/src/exception/AtomsMissingException.ts +109 -0
- package/src/exception/AuthorizationRejectedException.ts +63 -0
- package/src/exception/BalanceInsufficientException.ts +58 -0
- package/src/exception/BaseException.ts +275 -0
- package/src/exception/BatchIdException.ts +58 -0
- package/src/exception/CodeException.ts +119 -0
- package/src/exception/DecryptionKeyException.ts +65 -0
- package/src/exception/InvalidResponseException.ts +112 -0
- package/src/exception/MetaMissingException.ts +58 -0
- package/src/exception/MolecularHashMismatchException.ts +115 -0
- package/src/exception/MolecularHashMissingException.ts +58 -0
- package/src/exception/NegativeAmountException.ts +58 -0
- package/src/exception/PolicyInvalidException.ts +58 -0
- package/src/exception/SignatureMalformedException.ts +58 -0
- package/src/exception/SignatureMismatchException.ts +98 -0
- package/src/exception/StackableUnitAmountException.ts +65 -0
- package/src/exception/StackableUnitDecimalsException.ts +65 -0
- package/src/exception/TransferBalanceException.ts +98 -0
- package/src/exception/TransferMalformedException.ts +58 -0
- package/src/exception/TransferMismatchedException.ts +58 -0
- package/src/exception/TransferRemainderException.ts +58 -0
- package/src/exception/TransferToSelfException.ts +58 -0
- package/src/exception/TransferUnbalancedException.ts +58 -0
- package/src/exception/UnauthenticatedException.ts +147 -0
- package/src/exception/WalletCredentialException.ts +108 -0
- package/src/exception/WalletShadowException.ts +65 -0
- package/src/exception/WrongTokenTypeException.ts +58 -0
- package/src/exception/index.ts +272 -0
- package/src/index.ts +512 -0
- package/src/instance/rules/Callback.ts +257 -0
- package/src/instance/rules/Condition.ts +96 -0
- package/src/instance/rules/Meta.ts +163 -0
- package/src/instance/rules/Rule.ts +29 -0
- package/src/instance/rules/exception/RuleArgumentException.ts +65 -0
- package/src/libraries/CheckMolecule.ts +581 -0
- package/src/libraries/Decimal.ts +94 -0
- package/src/libraries/Dot.ts +202 -0
- package/src/libraries/GraphQLClient.ts +276 -0
- package/src/libraries/Hex.ts +155 -0
- package/src/libraries/UrqlClientWrapper.ts +336 -0
- package/src/libraries/array.ts +91 -0
- package/src/libraries/crypto.ts +816 -0
- package/src/libraries/strings.ts +458 -0
- package/src/mutation/Mutation.ts +103 -0
- package/src/mutation/MutationActiveSession.ts +108 -0
- package/src/mutation/MutationClaimShadowWallet.ts +91 -0
- package/src/mutation/MutationCreateIdentifier.ts +86 -0
- package/src/mutation/MutationCreateMeta.ts +92 -0
- package/src/mutation/MutationCreateRule.ts +90 -0
- package/src/mutation/MutationCreateToken.ts +92 -0
- package/src/mutation/MutationCreateWallet.ts +78 -0
- package/src/mutation/MutationDepositBufferToken.ts +72 -0
- package/src/mutation/MutationLinkIdentifier.ts +87 -0
- package/src/mutation/MutationProposeMolecule.ts +147 -0
- package/src/mutation/MutationRequestAuthorization.ts +77 -0
- package/src/mutation/MutationRequestAuthorizationGuest.ts +85 -0
- package/src/mutation/MutationRequestTokens.ts +98 -0
- package/src/mutation/MutationTransferTokens.ts +87 -0
- package/src/mutation/MutationWithdrawBufferToken.ts +73 -0
- package/src/query/Query.ts +187 -0
- package/src/query/QueryActiveSession.ts +89 -0
- package/src/query/QueryAtom.ts +275 -0
- package/src/query/QueryBalance.ts +102 -0
- package/src/query/QueryBatch.ts +145 -0
- package/src/query/QueryBatchHistory.ts +86 -0
- package/src/query/QueryContinuId.ts +91 -0
- package/src/query/QueryMetaType.ts +177 -0
- package/src/query/QueryMetaTypeViaAtom.ts +199 -0
- package/src/query/QueryPolicy.ts +91 -0
- package/src/query/QueryToken.ts +90 -0
- package/src/query/QueryUserActivity.ts +153 -0
- package/src/query/QueryWalletBundle.ts +92 -0
- package/src/query/QueryWalletList.ts +106 -0
- package/src/response/EnhancedResponse.ts +345 -0
- package/src/response/Response.ts +254 -0
- package/src/response/ResponseActiveSession.ts +72 -0
- package/src/response/ResponseAtom.ts +132 -0
- package/src/response/ResponseAuthorizationGuest.ts +119 -0
- package/src/response/ResponseBalance.ts +153 -0
- package/src/response/ResponseClaimShadowWallet.ts +56 -0
- package/src/response/ResponseContinuId.ts +101 -0
- package/src/response/ResponseCreateIdentifier.ts +56 -0
- package/src/response/ResponseCreateMeta.ts +58 -0
- package/src/response/ResponseCreateRule.ts +56 -0
- package/src/response/ResponseCreateToken.ts +58 -0
- package/src/response/ResponseCreateWallet.ts +58 -0
- package/src/response/ResponseLinkIdentifier.ts +87 -0
- package/src/response/ResponseMetaBatch.ts +72 -0
- package/src/response/ResponseMetaType.ts +108 -0
- package/src/response/ResponseMetaTypeViaAtom.ts +108 -0
- package/src/response/ResponsePolicy.ts +90 -0
- package/src/response/ResponseProposeMolecule.ts +155 -0
- package/src/response/ResponseQueryActiveSession.ts +105 -0
- package/src/response/ResponseQueryUserActivity.ts +89 -0
- package/src/response/ResponseRequestAuthorization.ts +100 -0
- package/src/response/ResponseRequestAuthorizationGuest.ts +133 -0
- package/src/response/ResponseRequestTokens.ts +58 -0
- package/src/response/ResponseTransferTokens.ts +72 -0
- package/src/response/ResponseWalletBundle.ts +95 -0
- package/src/response/ResponseWalletList.ts +165 -0
- package/src/schemas/index.ts +457 -0
- package/src/subscribe/ActiveSessionSubscribe.ts +72 -0
- package/src/subscribe/ActiveWalletSubscribe.ts +99 -0
- package/src/subscribe/CreateMoleculeSubscribe.ts +106 -0
- package/src/subscribe/Subscribe.ts +182 -0
- package/src/subscribe/WalletStatusSubscribe.ts +70 -0
- package/src/subscribe/index.ts +59 -0
- package/src/types/assertions.ts +722 -0
- package/src/types/client.ts +567 -0
- package/src/types/crypto.ts +541 -0
- package/src/types/graphql.ts +630 -0
- package/src/types/guards.ts +659 -0
- package/src/types/index.ts +614 -0
- package/src/types/response.ts +133 -0
- package/src/types/template-literals.ts +382 -0
- package/src/validation/UNIVERSAL_CONFIGURATION_INTERFACES.ts +580 -0
- package/src/validation/ValidationService.ts +607 -0
- package/src/validation/schemas.ts +447 -0
- package/src/versions/HashAtom.ts +170 -0
- package/src/versions/Version4.ts +120 -0
- package/src/versions/index.ts +80 -0
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
/*
|
|
2
|
+
(
|
|
3
|
+
(/(
|
|
4
|
+
(//(
|
|
5
|
+
(///(
|
|
6
|
+
(/////(
|
|
7
|
+
(//////( )
|
|
8
|
+
(////////( (/)
|
|
9
|
+
(////////( (///)
|
|
10
|
+
(//////////( (////)
|
|
11
|
+
(//////////( (//////)
|
|
12
|
+
(////////////( (///////)
|
|
13
|
+
(/////////////( (/////////)
|
|
14
|
+
(//////////////( (///////////)
|
|
15
|
+
(///////////////( (/////////////)
|
|
16
|
+
(////////////////( (//////////////)
|
|
17
|
+
((((((((((((((((((( (((((((((((((((
|
|
18
|
+
((((((((((((((((((( ((((((((((((((
|
|
19
|
+
((((((((((((((((((( ((((((((((((((
|
|
20
|
+
(((((((((((((((((((( (((((((((((((
|
|
21
|
+
(((((((((((((((((((( ((((((((((((
|
|
22
|
+
((((((((((((((((((( ((((((((((((
|
|
23
|
+
((((((((((((((((((( ((((((((((
|
|
24
|
+
((((((((((((((((((/ (((((((((
|
|
25
|
+
(((((((((((((((((( ((((((((
|
|
26
|
+
((((((((((((((((( (((((((
|
|
27
|
+
(((((((((((((((((( (((((
|
|
28
|
+
################# ##
|
|
29
|
+
################ #
|
|
30
|
+
################# ##
|
|
31
|
+
%################ ###
|
|
32
|
+
###############( ####
|
|
33
|
+
############### ####
|
|
34
|
+
############### ######
|
|
35
|
+
%#############( (#######
|
|
36
|
+
%############# #########
|
|
37
|
+
############( ##########
|
|
38
|
+
########### #############
|
|
39
|
+
######### ##############
|
|
40
|
+
%######
|
|
41
|
+
|
|
42
|
+
Powered by Knish.IO: Connecting a Decentralized World
|
|
43
|
+
|
|
44
|
+
Please visit https://github.com/WishKnish/KnishIO-Client-TS for information.
|
|
45
|
+
|
|
46
|
+
License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import JsSHA from 'jssha'
|
|
50
|
+
import { randomString, chunkSubstr } from '@/libraries/strings'
|
|
51
|
+
import { generateBundleHash, generateSecret, shake256 } from '@/libraries/crypto'
|
|
52
|
+
import WalletCredentialException from '@/exception/WalletCredentialException'
|
|
53
|
+
import { isWalletAddress, isBundleHash, isPosition } from '@/types'
|
|
54
|
+
// Post-quantum cryptography for ML-KEM768 key encapsulation
|
|
55
|
+
import { ml_kem768 } from '@noble/post-quantum/ml-kem.js'
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Wallet class - Identity and key management for KnishIO DLT
|
|
59
|
+
* Essential implementation for transaction operations
|
|
60
|
+
*/
|
|
61
|
+
export default class Wallet {
|
|
62
|
+
public token: string
|
|
63
|
+
public balance: number
|
|
64
|
+
public address: string | null
|
|
65
|
+
public position: string | null
|
|
66
|
+
public bundle: string | null
|
|
67
|
+
public batchId: string | null
|
|
68
|
+
public characters: string | null
|
|
69
|
+
public key: string | null
|
|
70
|
+
public privkey: any
|
|
71
|
+
public pubkey: any
|
|
72
|
+
public tokenUnits: any[]
|
|
73
|
+
public tradeRates: Record<string, any>
|
|
74
|
+
public molecules: Record<string, any>
|
|
75
|
+
|
|
76
|
+
constructor({
|
|
77
|
+
secret = null,
|
|
78
|
+
bundle = null,
|
|
79
|
+
token = 'USER',
|
|
80
|
+
address = null,
|
|
81
|
+
position = null,
|
|
82
|
+
batchId = null,
|
|
83
|
+
characters = null
|
|
84
|
+
}: {
|
|
85
|
+
secret?: string | null
|
|
86
|
+
bundle?: string | null
|
|
87
|
+
token?: string
|
|
88
|
+
address?: string | null
|
|
89
|
+
position?: string | null
|
|
90
|
+
batchId?: string | null
|
|
91
|
+
characters?: string | null
|
|
92
|
+
} = {}) {
|
|
93
|
+
// TypeScript 2025: Exhaustive validation with type guards
|
|
94
|
+
if (address !== null && !isWalletAddress(address)) {
|
|
95
|
+
throw new WalletCredentialException('Invalid wallet address format')
|
|
96
|
+
}
|
|
97
|
+
if (bundle !== null && !isBundleHash(bundle)) {
|
|
98
|
+
throw new WalletCredentialException('Invalid bundle hash format')
|
|
99
|
+
}
|
|
100
|
+
if (position !== null && !isPosition(position)) {
|
|
101
|
+
throw new WalletCredentialException('Invalid position format')
|
|
102
|
+
}
|
|
103
|
+
this.token = token
|
|
104
|
+
this.balance = 0
|
|
105
|
+
this.molecules = {}
|
|
106
|
+
|
|
107
|
+
// Empty values
|
|
108
|
+
this.key = null
|
|
109
|
+
this.privkey = null
|
|
110
|
+
this.pubkey = null
|
|
111
|
+
this.tokenUnits = []
|
|
112
|
+
this.tradeRates = {}
|
|
113
|
+
|
|
114
|
+
this.address = address
|
|
115
|
+
this.position = position
|
|
116
|
+
this.bundle = bundle
|
|
117
|
+
this.batchId = batchId
|
|
118
|
+
this.characters = characters
|
|
119
|
+
|
|
120
|
+
if (secret) {
|
|
121
|
+
// Set bundle from the secret
|
|
122
|
+
this.bundle = this.bundle || generateBundleHash(secret, 'Wallet::constructor')
|
|
123
|
+
|
|
124
|
+
// Generate a position for non-shadow wallet if not initialized
|
|
125
|
+
this.position = this.position || Wallet.generatePosition()
|
|
126
|
+
|
|
127
|
+
// Key & address initialization
|
|
128
|
+
this.key = Wallet.generateKey({
|
|
129
|
+
secret,
|
|
130
|
+
token: this.token,
|
|
131
|
+
position: this.position
|
|
132
|
+
})
|
|
133
|
+
this.address = this.address || Wallet.generateAddress(this.key)
|
|
134
|
+
|
|
135
|
+
// Set characters
|
|
136
|
+
this.characters = this.characters || 'BASE64'
|
|
137
|
+
|
|
138
|
+
// Initialize ML-KEM768 keys (matches JavaScript SDK)
|
|
139
|
+
this.initializeMLKEM()
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Creates a new Wallet instance
|
|
145
|
+
* Matches JavaScript SDK Wallet.create exactly
|
|
146
|
+
*/
|
|
147
|
+
static create({
|
|
148
|
+
secret = null,
|
|
149
|
+
bundle = null,
|
|
150
|
+
token = 'USER',
|
|
151
|
+
batchId = null,
|
|
152
|
+
characters = null
|
|
153
|
+
}: {
|
|
154
|
+
secret?: string | null
|
|
155
|
+
bundle?: string | null
|
|
156
|
+
token?: string
|
|
157
|
+
batchId?: string | null
|
|
158
|
+
characters?: string | null
|
|
159
|
+
}): Wallet {
|
|
160
|
+
let position = null
|
|
161
|
+
|
|
162
|
+
// No credentials parameters provided?
|
|
163
|
+
if (!secret && !bundle) {
|
|
164
|
+
throw new WalletCredentialException()
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Secret, but no bundle?
|
|
168
|
+
if (secret && !bundle) {
|
|
169
|
+
position = Wallet.generatePosition()
|
|
170
|
+
bundle = generateBundleHash(secret, 'Wallet::create')
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// Wallet initialization
|
|
174
|
+
return new Wallet({
|
|
175
|
+
secret,
|
|
176
|
+
bundle,
|
|
177
|
+
token,
|
|
178
|
+
position,
|
|
179
|
+
batchId,
|
|
180
|
+
characters
|
|
181
|
+
})
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Generates a private key for the given parameters
|
|
187
|
+
* MUST match JavaScript SDK Wallet.generateKey exactly using sponge pattern
|
|
188
|
+
*/
|
|
189
|
+
static generateKey({
|
|
190
|
+
secret,
|
|
191
|
+
token,
|
|
192
|
+
position
|
|
193
|
+
}: {
|
|
194
|
+
secret: string
|
|
195
|
+
token: string
|
|
196
|
+
position: string
|
|
197
|
+
}): string {
|
|
198
|
+
// Converting secret to bigInt
|
|
199
|
+
const bigIntSecret = BigInt(`0x${secret}`)
|
|
200
|
+
|
|
201
|
+
// Adding new position to the user secret to produce the indexed key
|
|
202
|
+
const indexedKey = bigIntSecret + BigInt(`0x${position}`)
|
|
203
|
+
|
|
204
|
+
// Hashing the indexed key to produce the intermediate key
|
|
205
|
+
// CRITICAL FIX: Use sponge pattern exactly like JavaScript SDK
|
|
206
|
+
const intermediateKeySponge = new JsSHA('SHAKE256', 'TEXT')
|
|
207
|
+
intermediateKeySponge.update(indexedKey.toString(16))
|
|
208
|
+
|
|
209
|
+
if (token) {
|
|
210
|
+
// CRITICAL FIX: Update the SAME sponge with token (no concatenation)
|
|
211
|
+
intermediateKeySponge.update(token)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Hashing the intermediate key to produce the private key
|
|
215
|
+
// CRITICAL FIX: Create NEW sponge for private key (matching JS SDK)
|
|
216
|
+
const privateKeySponge = new JsSHA('SHAKE256', 'TEXT')
|
|
217
|
+
privateKeySponge.update(intermediateKeySponge.getHash('HEX', { outputLen: 8192 }))
|
|
218
|
+
|
|
219
|
+
return privateKeySponge.getHash('HEX', { outputLen: 8192 })
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Generates a wallet address
|
|
224
|
+
* Matches JavaScript SDK Wallet.generateAddress exactly
|
|
225
|
+
*/
|
|
226
|
+
static generateAddress(key: string): string {
|
|
227
|
+
// Subdivide private key into 16 fragments of 128 characters each
|
|
228
|
+
const keyFragments = chunkSubstr(key, 128)
|
|
229
|
+
|
|
230
|
+
// Generating wallet digest
|
|
231
|
+
let digestInput = ''
|
|
232
|
+
|
|
233
|
+
for (let index = 0; index < keyFragments.length; index++) {
|
|
234
|
+
let workingFragment = keyFragments[index]
|
|
235
|
+
if (!workingFragment) continue
|
|
236
|
+
|
|
237
|
+
// Hash each fragment 16 times
|
|
238
|
+
for (let fragmentCount = 1; fragmentCount <= 16; fragmentCount++) {
|
|
239
|
+
// Fix: Use 512 bits to get 128 hex chars output (matching JS SDK)
|
|
240
|
+
workingFragment = shake256(workingFragment, 512)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
digestInput += workingFragment
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
// Producing wallet address
|
|
247
|
+
// Fix: Use 8192 bits to get 2048 hex chars for digest (matching JS SDK)
|
|
248
|
+
const digest = shake256(digestInput, 8192)
|
|
249
|
+
// Fix: Use 256 bits to get 64 hex chars for address (matching JS SDK)
|
|
250
|
+
return shake256(digest, 256)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Generate a random position for wallet
|
|
255
|
+
* Matches JavaScript SDK Wallet.generatePosition exactly
|
|
256
|
+
*/
|
|
257
|
+
static generatePosition(saltLength = 64): string {
|
|
258
|
+
return randomString(saltLength, 'abcdef0123456789')
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Determines if the provided string is a bundle hash
|
|
263
|
+
* Uses exhaustive type guard from types system
|
|
264
|
+
* @param maybeBundleHash - String to check
|
|
265
|
+
* @return True if valid bundle hash format
|
|
266
|
+
*/
|
|
267
|
+
static isBundleHash(maybeBundleHash: unknown): maybeBundleHash is string {
|
|
268
|
+
return typeof maybeBundleHash === 'string' && isBundleHash(maybeBundleHash)
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Get formatted token units from raw data
|
|
273
|
+
* Stub implementation for now
|
|
274
|
+
*/
|
|
275
|
+
static getTokenUnits(unitsData: any[]): any[] {
|
|
276
|
+
// TODO: Implement TokenUnit class if needed
|
|
277
|
+
return unitsData
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Create a remainder wallet for transactions
|
|
282
|
+
* Used by Molecule for creating remainder atoms
|
|
283
|
+
*/
|
|
284
|
+
createRemainder(secret: string): Wallet {
|
|
285
|
+
return Wallet.create({
|
|
286
|
+
secret,
|
|
287
|
+
bundle: this.bundle,
|
|
288
|
+
token: this.token,
|
|
289
|
+
batchId: this.batchId,
|
|
290
|
+
characters: this.characters
|
|
291
|
+
})
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Get token units data
|
|
296
|
+
* Stub for compatibility
|
|
297
|
+
*/
|
|
298
|
+
getTokenUnitsData(): any[] {
|
|
299
|
+
return this.tokenUnits
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* Check if this is a shadow wallet
|
|
304
|
+
* Shadow wallets don't have position or address set
|
|
305
|
+
* @return True if this is a shadow wallet
|
|
306
|
+
*/
|
|
307
|
+
isShadow(): boolean {
|
|
308
|
+
return (
|
|
309
|
+
(typeof this.position === 'undefined' || this.position === null) &&
|
|
310
|
+
(typeof this.address === 'undefined' || this.address === null)
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// =============================================================================
|
|
315
|
+
// POST-QUANTUM CRYPTOGRAPHY - ML-KEM768 INTEGRATION
|
|
316
|
+
// =============================================================================
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Initializes the ML-KEM key pair (matches JavaScript SDK exactly)
|
|
320
|
+
*/
|
|
321
|
+
initializeMLKEM(): void {
|
|
322
|
+
// Generate a 64-byte (512-bit) seed from the Knish.IO private key
|
|
323
|
+
// Use deterministic approach: generateSecret(key, 128) → 128 hex chars = 64 bytes
|
|
324
|
+
const seedHex = generateSecret(this.key!, 128) // 128 hex chars = 64 bytes
|
|
325
|
+
|
|
326
|
+
// Convert the hex string to a Uint8Array
|
|
327
|
+
const seed = new Uint8Array(64)
|
|
328
|
+
for (let i = 0; i < 64; i++) {
|
|
329
|
+
seed[i] = parseInt(seedHex.substr(i * 2, 2), 16)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const { publicKey, secretKey } = ml_kem768.keygen(seed)
|
|
333
|
+
this.pubkey = this.serializeKey(publicKey)
|
|
334
|
+
this.privkey = secretKey // Note: We're keeping privkey as UInt8Array for security
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
// =============================================================================
|
|
339
|
+
// HIGH-LEVEL MESSAGE ENCRYPTION (JavaScript SDK Compatibility)
|
|
340
|
+
// =============================================================================
|
|
341
|
+
|
|
342
|
+
async encryptMessage(message: any, recipientPubkey: string): Promise<{ cipherText: string; encryptedMessage: string }> {
|
|
343
|
+
const messageString = JSON.stringify(message)
|
|
344
|
+
const messageUint8 = new TextEncoder().encode(messageString)
|
|
345
|
+
const deserializedPubkey = this.deserializeKey(recipientPubkey)
|
|
346
|
+
const { cipherText, sharedSecret } = ml_kem768.encapsulate(deserializedPubkey)
|
|
347
|
+
const encryptedMessage = await this.encryptWithSharedSecret(messageUint8, sharedSecret)
|
|
348
|
+
return {
|
|
349
|
+
cipherText: this.serializeKey(cipherText),
|
|
350
|
+
encryptedMessage: this.serializeKey(encryptedMessage)
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
async decryptMessage(encryptedData: { cipherText: string; encryptedMessage: string }): Promise<any> {
|
|
355
|
+
const { cipherText, encryptedMessage } = encryptedData
|
|
356
|
+
let sharedSecret
|
|
357
|
+
try {
|
|
358
|
+
sharedSecret = ml_kem768.decapsulate(this.deserializeKey(cipherText), this.privkey)
|
|
359
|
+
} catch (e) {
|
|
360
|
+
console.error('Wallet::decryptMessage() - Decapsulation failed', e)
|
|
361
|
+
console.info('Wallet::decryptMessage() - my public key', this.pubkey)
|
|
362
|
+
return null
|
|
363
|
+
}
|
|
364
|
+
let deserializedEncryptedMessage
|
|
365
|
+
try {
|
|
366
|
+
deserializedEncryptedMessage = this.deserializeKey(encryptedMessage)
|
|
367
|
+
} catch (e) {
|
|
368
|
+
console.warn('Wallet::decryptMessage() - Deserialization failed', e)
|
|
369
|
+
console.info('Wallet::decryptMessage() - my public key', this.pubkey)
|
|
370
|
+
console.info('Wallet::decryptMessage() - our shared secret', sharedSecret)
|
|
371
|
+
return null
|
|
372
|
+
}
|
|
373
|
+
let decryptedUint8
|
|
374
|
+
try {
|
|
375
|
+
decryptedUint8 = await this.decryptWithSharedSecret(deserializedEncryptedMessage, sharedSecret)
|
|
376
|
+
} catch (e) {
|
|
377
|
+
console.warn('Wallet::decryptMessage() - Decryption failed', e)
|
|
378
|
+
console.info('Wallet::decryptMessage() - my public key', this.pubkey)
|
|
379
|
+
console.info('Wallet::decryptMessage() - our shared secret', sharedSecret)
|
|
380
|
+
console.info('Wallet::decryptMessage() - deserialized encrypted message', deserializedEncryptedMessage)
|
|
381
|
+
return null
|
|
382
|
+
}
|
|
383
|
+
let decryptedString
|
|
384
|
+
try {
|
|
385
|
+
decryptedString = new TextDecoder().decode(decryptedUint8)
|
|
386
|
+
} catch (e) {
|
|
387
|
+
console.warn('Wallet::decryptMessage() - Decoding failed', e)
|
|
388
|
+
console.info('Wallet::decryptMessage() - my public key', this.pubkey)
|
|
389
|
+
console.info('Wallet::decryptMessage() - our shared secret', sharedSecret)
|
|
390
|
+
console.info('Wallet::decryptMessage() - deserialized encrypted message', deserializedEncryptedMessage)
|
|
391
|
+
console.info('Wallet::decryptMessage() - decrypted Uint8Array', decryptedUint8)
|
|
392
|
+
return null
|
|
393
|
+
}
|
|
394
|
+
return JSON.parse(decryptedString)
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// =============================================================================
|
|
398
|
+
// SYMMETRIC ENCRYPTION HELPERS (AES-GCM with shared secret)
|
|
399
|
+
// =============================================================================
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Encrypt data using AES-GCM with the given shared secret
|
|
403
|
+
*/
|
|
404
|
+
private async encryptWithSharedSecret(message: Uint8Array, sharedSecret: Uint8Array): Promise<Uint8Array> {
|
|
405
|
+
// Generate random IV for AES-GCM
|
|
406
|
+
const iv = crypto.getRandomValues(new Uint8Array(12))
|
|
407
|
+
|
|
408
|
+
// Import shared secret as CryptoKey
|
|
409
|
+
const key = await crypto.subtle.importKey(
|
|
410
|
+
'raw',
|
|
411
|
+
sharedSecret,
|
|
412
|
+
{ name: 'AES-GCM' },
|
|
413
|
+
false,
|
|
414
|
+
['encrypt']
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
// Encrypt the message
|
|
418
|
+
const encryptedContent = await crypto.subtle.encrypt(
|
|
419
|
+
{ name: 'AES-GCM', iv },
|
|
420
|
+
key,
|
|
421
|
+
message
|
|
422
|
+
)
|
|
423
|
+
|
|
424
|
+
// Combine IV and encrypted content
|
|
425
|
+
const result = new Uint8Array(iv.length + encryptedContent.byteLength)
|
|
426
|
+
result.set(iv)
|
|
427
|
+
result.set(new Uint8Array(encryptedContent), iv.length)
|
|
428
|
+
|
|
429
|
+
return result
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* Decrypt data using AES-GCM with the given shared secret
|
|
434
|
+
*/
|
|
435
|
+
private async decryptWithSharedSecret(encryptedMessage: Uint8Array, sharedSecret: Uint8Array): Promise<Uint8Array> {
|
|
436
|
+
// Extract IV from the encrypted message
|
|
437
|
+
const iv = encryptedMessage.slice(0, 12)
|
|
438
|
+
const ciphertext = encryptedMessage.slice(12)
|
|
439
|
+
|
|
440
|
+
// Import shared secret as CryptoKey
|
|
441
|
+
const key = await crypto.subtle.importKey(
|
|
442
|
+
'raw',
|
|
443
|
+
sharedSecret,
|
|
444
|
+
{ name: 'AES-GCM' },
|
|
445
|
+
false,
|
|
446
|
+
['decrypt']
|
|
447
|
+
)
|
|
448
|
+
|
|
449
|
+
// Decrypt the message
|
|
450
|
+
const decryptedContent = await crypto.subtle.decrypt(
|
|
451
|
+
{ name: 'AES-GCM', iv },
|
|
452
|
+
key,
|
|
453
|
+
ciphertext
|
|
454
|
+
)
|
|
455
|
+
|
|
456
|
+
return new Uint8Array(decryptedContent)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
serializeKey(key: Uint8Array): string {
|
|
460
|
+
return btoa(String.fromCharCode(...key))
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
deserializeKey(serializedKey: string): Uint8Array {
|
|
464
|
+
const binaryString = atob(serializedKey)
|
|
465
|
+
return new Uint8Array([...binaryString].map(char => char.charCodeAt(0)))
|
|
466
|
+
}
|
|
467
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/*
|
|
2
|
+
(
|
|
3
|
+
(/(
|
|
4
|
+
(//(
|
|
5
|
+
(///(
|
|
6
|
+
(/////(
|
|
7
|
+
(//////( )
|
|
8
|
+
(////////( (/)
|
|
9
|
+
(////////( (///)
|
|
10
|
+
(//////////( (////)
|
|
11
|
+
(//////////( (//////)
|
|
12
|
+
(////////////( (///////)
|
|
13
|
+
(/////////////( (/////////)
|
|
14
|
+
(//////////////( (///////////)
|
|
15
|
+
(///////////////( (/////////////)
|
|
16
|
+
(////////////////( (//////////////)
|
|
17
|
+
((((((((((((((((((( (((((((((((((((
|
|
18
|
+
((((((((((((((((((( ((((((((((((((
|
|
19
|
+
((((((((((((((((((( ((((((((((((((
|
|
20
|
+
(((((((((((((((((((( (((((((((((((
|
|
21
|
+
(((((((((((((((((((( ((((((((((((
|
|
22
|
+
((((((((((((((((((( ((((((((((((
|
|
23
|
+
((((((((((((((((((( ((((((((((
|
|
24
|
+
((((((((((((((((((/ (((((((((
|
|
25
|
+
(((((((((((((((((( ((((((((
|
|
26
|
+
((((((((((((((((( (((((((
|
|
27
|
+
(((((((((((((((((( (((((
|
|
28
|
+
################# ##
|
|
29
|
+
################ #
|
|
30
|
+
################# ##
|
|
31
|
+
%################ ###
|
|
32
|
+
###############( ####
|
|
33
|
+
############### ####
|
|
34
|
+
############### ######
|
|
35
|
+
%#############( (#######
|
|
36
|
+
%############# #########
|
|
37
|
+
############( ##########
|
|
38
|
+
########### #############
|
|
39
|
+
######### ##############
|
|
40
|
+
%######
|
|
41
|
+
|
|
42
|
+
Powered by Knish.IO: Connecting a Decentralized World
|
|
43
|
+
|
|
44
|
+
Please visit https://github.com/WishKnish/KnishIO-Client-TS for information.
|
|
45
|
+
|
|
46
|
+
License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import BaseException, { type BaseExceptionOptions } from './BaseException'
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Exception thrown when atom indexing is invalid or conflicts
|
|
53
|
+
* Used in molecular composition when atom indices are incorrect
|
|
54
|
+
*/
|
|
55
|
+
export default class AtomIndexException extends BaseException {
|
|
56
|
+
constructor(message = 'Invalid atom index', options: BaseExceptionOptions = {}) {
|
|
57
|
+
super('ATOM_INDEX_ERROR', message, options)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Factory method for index conflicts
|
|
62
|
+
*/
|
|
63
|
+
static indexConflict(index: number, existingIndex: number): AtomIndexException {
|
|
64
|
+
return new AtomIndexException(
|
|
65
|
+
`Atom index ${index} conflicts with existing index ${existingIndex}`,
|
|
66
|
+
{
|
|
67
|
+
details: { index, existingIndex },
|
|
68
|
+
code: 'INDEX_CONFLICT'
|
|
69
|
+
}
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Factory method for out-of-range indices
|
|
75
|
+
*/
|
|
76
|
+
static indexOutOfRange(index: number, maxIndex: number): AtomIndexException {
|
|
77
|
+
return new AtomIndexException(
|
|
78
|
+
`Atom index ${index} is out of range (max: ${maxIndex})`,
|
|
79
|
+
{
|
|
80
|
+
details: { index, maxIndex },
|
|
81
|
+
code: 'INDEX_OUT_OF_RANGE'
|
|
82
|
+
}
|
|
83
|
+
)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Factory method for missing required index
|
|
88
|
+
*/
|
|
89
|
+
static missingIndex(): AtomIndexException {
|
|
90
|
+
return new AtomIndexException(
|
|
91
|
+
'Atom index is required but not provided',
|
|
92
|
+
{
|
|
93
|
+
code: 'INDEX_MISSING'
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/*
|
|
2
|
+
(
|
|
3
|
+
(/(
|
|
4
|
+
(//(
|
|
5
|
+
(///(
|
|
6
|
+
(/////(
|
|
7
|
+
(//////( )
|
|
8
|
+
(////////( (/)
|
|
9
|
+
(////////( (///)
|
|
10
|
+
(//////////( (////)
|
|
11
|
+
(//////////( (//////)
|
|
12
|
+
(////////////( (///////)
|
|
13
|
+
(/////////////( (/////////)
|
|
14
|
+
(//////////////( (///////////)
|
|
15
|
+
(///////////////( (/////////////)
|
|
16
|
+
(////////////////( (//////////////)
|
|
17
|
+
((((((((((((((((((( (((((((((((((((
|
|
18
|
+
((((((((((((((((((( ((((((((((((((
|
|
19
|
+
((((((((((((((((((( ((((((((((((((
|
|
20
|
+
(((((((((((((((((((( (((((((((((((
|
|
21
|
+
(((((((((((((((((((( ((((((((((((
|
|
22
|
+
((((((((((((((((((( ((((((((((((
|
|
23
|
+
((((((((((((((((((( ((((((((((
|
|
24
|
+
((((((((((((((((((/ (((((((((
|
|
25
|
+
(((((((((((((((((( ((((((((
|
|
26
|
+
((((((((((((((((( (((((((
|
|
27
|
+
(((((((((((((((((( (((((
|
|
28
|
+
################# ##
|
|
29
|
+
################ #
|
|
30
|
+
################# ##
|
|
31
|
+
%################ ###
|
|
32
|
+
###############( ####
|
|
33
|
+
############### ####
|
|
34
|
+
############### ######
|
|
35
|
+
%#############( (#######
|
|
36
|
+
%############# #########
|
|
37
|
+
############( ##########
|
|
38
|
+
########### #############
|
|
39
|
+
######### ##############
|
|
40
|
+
%######
|
|
41
|
+
|
|
42
|
+
Powered by Knish.IO: Connecting a Decentralized World
|
|
43
|
+
|
|
44
|
+
Please visit https://github.com/WishKnish/KnishIO-Client-TS for information.
|
|
45
|
+
|
|
46
|
+
License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import BaseException, { type BaseExceptionOptions } from './BaseException'
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Exception thrown when required atoms are missing from a molecule
|
|
53
|
+
* Used in molecular validation and composition
|
|
54
|
+
*/
|
|
55
|
+
export default class AtomsMissingException extends BaseException {
|
|
56
|
+
constructor(message = 'Required atoms are missing', options: BaseExceptionOptions = {}) {
|
|
57
|
+
super('ATOMS_MISSING_ERROR', message, options)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Factory method for empty molecule
|
|
62
|
+
*/
|
|
63
|
+
static emptyMolecule(): AtomsMissingException {
|
|
64
|
+
return new AtomsMissingException(
|
|
65
|
+
'Molecule cannot be empty - at least one atom is required',
|
|
66
|
+
{
|
|
67
|
+
code: 'EMPTY_MOLECULE'
|
|
68
|
+
}
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Factory method for missing isotope-specific atoms
|
|
74
|
+
*/
|
|
75
|
+
static missingIsotope(isotope: string): AtomsMissingException {
|
|
76
|
+
return new AtomsMissingException(
|
|
77
|
+
`Missing required ${isotope} isotope atoms`,
|
|
78
|
+
{
|
|
79
|
+
details: { isotope },
|
|
80
|
+
code: 'MISSING_ISOTOPE'
|
|
81
|
+
}
|
|
82
|
+
)
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Factory method for missing remainder atoms
|
|
87
|
+
*/
|
|
88
|
+
static missingRemainder(expectedCount: number, actualCount: number): AtomsMissingException {
|
|
89
|
+
return new AtomsMissingException(
|
|
90
|
+
`Missing remainder atoms: expected ${expectedCount}, found ${actualCount}`,
|
|
91
|
+
{
|
|
92
|
+
details: { expectedCount, actualCount },
|
|
93
|
+
code: 'MISSING_REMAINDER'
|
|
94
|
+
}
|
|
95
|
+
)
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Factory method for missing value atoms in transfers
|
|
100
|
+
*/
|
|
101
|
+
static missingValueAtoms(): AtomsMissingException {
|
|
102
|
+
return new AtomsMissingException(
|
|
103
|
+
'Transfer molecules must contain value (V) atoms',
|
|
104
|
+
{
|
|
105
|
+
code: 'MISSING_VALUE_ATOMS'
|
|
106
|
+
}
|
|
107
|
+
)
|
|
108
|
+
}
|
|
109
|
+
}
|