@sip-protocol/sdk 0.6.26 → 0.7.1
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/browser.d.mts +2 -1
- package/dist/browser.d.ts +2 -1
- package/dist/browser.js +5723 -4957
- package/dist/browser.mjs +94 -46
- package/dist/{chunk-ZEYNCEIE.mjs → chunk-3OVABDRH.mjs} +12 -0
- package/dist/chunk-6WGN57S2.mjs +218 -0
- package/dist/chunk-DLDWZFYC.mjs +1495 -0
- package/dist/chunk-E6SZWREQ.mjs +57 -0
- package/dist/{chunk-GFSLU6SP.mjs → chunk-G33LB27A.mjs} +496 -1407
- package/dist/chunk-HOR7PM3M.mjs +15 -0
- package/dist/chunk-L2K34JCU.mjs +1496 -0
- package/dist/{chunk-EMOAOF5P.mjs → chunk-SN4ZDTVW.mjs} +489 -1407
- package/dist/constants-VOI7BSLK.mjs +27 -0
- package/dist/{index-DO9Az5n4.d.ts → index-CHB3KuOB.d.mts} +483 -14
- package/dist/{index-CRz9S3eE.d.mts → index-CzWPI6Le.d.ts} +483 -14
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +5658 -4895
- package/dist/index.mjs +91 -43
- package/dist/proofs/noir.mjs +4 -2
- package/dist/solana-5EMCTPTS.mjs +46 -0
- package/dist/solana-Q4NAVBTS.mjs +46 -0
- package/package.json +4 -2
- package/src/chains/solana/constants.ts +101 -0
- package/src/chains/solana/index.ts +87 -0
- package/src/chains/solana/scan.ts +382 -0
- package/src/chains/solana/transfer.ts +266 -0
- package/src/chains/solana/types.ts +169 -0
- package/src/executors/index.ts +18 -0
- package/src/executors/same-chain.ts +154 -0
- package/src/index.ts +58 -1
- package/src/intent.ts +10 -0
- package/src/sip.ts +127 -0
- package/src/stealth.ts +12 -2
- package/dist/chunk-46TH5SRE.mjs +0 -17077
- package/dist/chunk-C7RM67TH.mjs +0 -17047
- package/dist/chunk-GE566OLO.mjs +0 -17059
- package/dist/chunk-JK4FDH74.mjs +0 -17059
- package/dist/chunk-TSOCBT73.mjs +0 -17067
- package/dist/index-BZxo_8F3.d.ts +0 -11388
- package/dist/index-DKJ81T9L.d.mts +0 -11388
- package/dist/index-Dex_NSYv.d.mts +0 -11390
- package/dist/index-DhThjSB5.d.ts +0 -11390
|
@@ -1,1089 +1,81 @@
|
|
|
1
1
|
import {
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
function isValidPrivacyLevel(level) {
|
|
57
|
-
if (typeof level !== "string") return false;
|
|
58
|
-
return ["transparent", "shielded", "compliant"].includes(level);
|
|
59
|
-
}
|
|
60
|
-
function isValidHex(value) {
|
|
61
|
-
if (typeof value !== "string") return false;
|
|
62
|
-
if (!value.startsWith("0x")) return false;
|
|
63
|
-
const hex = value.slice(2);
|
|
64
|
-
if (hex.length === 0) return false;
|
|
65
|
-
return /^[0-9a-fA-F]+$/.test(hex);
|
|
66
|
-
}
|
|
67
|
-
function isValidHexLength(value, byteLength) {
|
|
68
|
-
if (!isValidHex(value)) return false;
|
|
69
|
-
const hex = value.slice(2);
|
|
70
|
-
return hex.length === byteLength * 2;
|
|
71
|
-
}
|
|
72
|
-
function isValidAmount(value) {
|
|
73
|
-
return typeof value === "bigint" && value > 0n;
|
|
74
|
-
}
|
|
75
|
-
function isNonNegativeAmount(value) {
|
|
76
|
-
return typeof value === "bigint" && value >= 0n;
|
|
77
|
-
}
|
|
78
|
-
function isValidSlippage(value) {
|
|
79
|
-
return typeof value === "number" && !isNaN(value) && value >= 0 && value < 1;
|
|
80
|
-
}
|
|
81
|
-
var STEALTH_META_ADDRESS_REGEX = /^sip:[a-z]+:0x[0-9a-fA-F]{64,66}:0x[0-9a-fA-F]{64,66}$/;
|
|
82
|
-
function isValidStealthMetaAddress(addr) {
|
|
83
|
-
if (typeof addr !== "string") return false;
|
|
84
|
-
return STEALTH_META_ADDRESS_REGEX.test(addr);
|
|
85
|
-
}
|
|
86
|
-
function isValidCompressedPublicKey(key) {
|
|
87
|
-
if (!isValidHexLength(key, 33)) return false;
|
|
88
|
-
const prefix = key.slice(2, 4);
|
|
89
|
-
return prefix === "02" || prefix === "03";
|
|
90
|
-
}
|
|
91
|
-
function isValidEd25519PublicKey(key) {
|
|
92
|
-
return isValidHexLength(key, 32);
|
|
93
|
-
}
|
|
94
|
-
function isValidPrivateKey(key) {
|
|
95
|
-
return isValidHexLength(key, 32);
|
|
96
|
-
}
|
|
97
|
-
function validateAsset(asset, field) {
|
|
98
|
-
if (!asset || typeof asset !== "object") {
|
|
99
|
-
throw new ValidationError("must be an object", field);
|
|
100
|
-
}
|
|
101
|
-
const a = asset;
|
|
102
|
-
if (!a.chain || !isValidChainId(a.chain)) {
|
|
103
|
-
throw new ValidationError(
|
|
104
|
-
`invalid chain '${a.chain}', must be one of: ${VALID_CHAIN_IDS.join(", ")}`,
|
|
105
|
-
`${field}.chain`
|
|
106
|
-
);
|
|
107
|
-
}
|
|
108
|
-
if (typeof a.symbol !== "string" || a.symbol.length === 0) {
|
|
109
|
-
throw new ValidationError("symbol must be a non-empty string", `${field}.symbol`);
|
|
110
|
-
}
|
|
111
|
-
if (a.address !== null && !isValidHex(a.address)) {
|
|
112
|
-
throw new ValidationError("address must be null or valid hex string", `${field}.address`);
|
|
113
|
-
}
|
|
114
|
-
if (typeof a.decimals !== "number" || !Number.isInteger(a.decimals) || a.decimals < 0) {
|
|
115
|
-
throw new ValidationError("decimals must be a non-negative integer", `${field}.decimals`);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
function validateIntentInput(input, field = "input") {
|
|
119
|
-
if (!input || typeof input !== "object") {
|
|
120
|
-
throw new ValidationError("must be an object", field);
|
|
121
|
-
}
|
|
122
|
-
const i = input;
|
|
123
|
-
validateAsset(i.asset, `${field}.asset`);
|
|
124
|
-
if (!isValidAmount(i.amount)) {
|
|
125
|
-
throw new ValidationError(
|
|
126
|
-
"amount must be a positive bigint",
|
|
127
|
-
`${field}.amount`,
|
|
128
|
-
{ received: typeof i.amount, value: String(i.amount) }
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
function validateIntentOutput(output, field = "output") {
|
|
133
|
-
if (!output || typeof output !== "object") {
|
|
134
|
-
throw new ValidationError("must be an object", field);
|
|
135
|
-
}
|
|
136
|
-
const o = output;
|
|
137
|
-
validateAsset(o.asset, `${field}.asset`);
|
|
138
|
-
if (!isNonNegativeAmount(o.minAmount)) {
|
|
139
|
-
throw new ValidationError(
|
|
140
|
-
"minAmount must be a non-negative bigint",
|
|
141
|
-
`${field}.minAmount`,
|
|
142
|
-
{ received: typeof o.minAmount, value: String(o.minAmount) }
|
|
143
|
-
);
|
|
144
|
-
}
|
|
145
|
-
if (!isValidSlippage(o.maxSlippage)) {
|
|
146
|
-
throw new ValidationError(
|
|
147
|
-
"maxSlippage must be a number between 0 and 1 (exclusive)",
|
|
148
|
-
`${field}.maxSlippage`,
|
|
149
|
-
{ received: o.maxSlippage }
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
function validateCreateIntentParams(params) {
|
|
154
|
-
if (!params || typeof params !== "object") {
|
|
155
|
-
throw new ValidationError("params must be an object");
|
|
156
|
-
}
|
|
157
|
-
const p = params;
|
|
158
|
-
if (!p.input) {
|
|
159
|
-
throw new ValidationError("input is required", "input");
|
|
160
|
-
}
|
|
161
|
-
validateIntentInput(p.input, "input");
|
|
162
|
-
if (!p.output) {
|
|
163
|
-
throw new ValidationError("output is required", "output");
|
|
164
|
-
}
|
|
165
|
-
validateIntentOutput(p.output, "output");
|
|
166
|
-
if (!p.privacy) {
|
|
167
|
-
throw new ValidationError("privacy is required", "privacy");
|
|
168
|
-
}
|
|
169
|
-
if (!isValidPrivacyLevel(p.privacy)) {
|
|
170
|
-
throw new ValidationError(
|
|
171
|
-
`invalid privacy level '${p.privacy}', must be one of: transparent, shielded, compliant`,
|
|
172
|
-
"privacy"
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
if ((p.privacy === "shielded" || p.privacy === "compliant") && p.recipientMetaAddress) {
|
|
176
|
-
if (!isValidStealthMetaAddress(p.recipientMetaAddress)) {
|
|
177
|
-
throw new ValidationError(
|
|
178
|
-
"invalid stealth meta-address format, expected: sip:<chain>:<spendingKey>:<viewingKey>",
|
|
179
|
-
"recipientMetaAddress"
|
|
180
|
-
);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
if (p.privacy === "compliant" && !p.viewingKey) {
|
|
184
|
-
throw new ValidationError(
|
|
185
|
-
"viewingKey is required for compliant mode",
|
|
186
|
-
"viewingKey"
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
if (p.viewingKey && !isValidHex(p.viewingKey)) {
|
|
190
|
-
throw new ValidationError(
|
|
191
|
-
"viewingKey must be a valid hex string",
|
|
192
|
-
"viewingKey"
|
|
193
|
-
);
|
|
194
|
-
}
|
|
195
|
-
if (p.ttl !== void 0) {
|
|
196
|
-
if (typeof p.ttl !== "number" || !Number.isInteger(p.ttl) || p.ttl <= 0) {
|
|
197
|
-
throw new ValidationError(
|
|
198
|
-
"ttl must be a positive integer (seconds)",
|
|
199
|
-
"ttl",
|
|
200
|
-
{ received: p.ttl }
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
function validateViewingKey(key, field = "viewingKey") {
|
|
206
|
-
if (!key || typeof key !== "string") {
|
|
207
|
-
throw new ValidationError("must be a string", field);
|
|
208
|
-
}
|
|
209
|
-
if (!isValidHex(key)) {
|
|
210
|
-
throw new ValidationError("must be a valid hex string with 0x prefix", field);
|
|
211
|
-
}
|
|
212
|
-
if (!isValidHexLength(key, 32)) {
|
|
213
|
-
throw new ValidationError("must be 32 bytes (64 hex characters)", field);
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
var SECP256K1_ORDER = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141n;
|
|
217
|
-
function isValidScalar(value) {
|
|
218
|
-
return value > 0n && value < SECP256K1_ORDER;
|
|
219
|
-
}
|
|
220
|
-
function validateScalar(value, field) {
|
|
221
|
-
if (typeof value !== "bigint") {
|
|
222
|
-
throw new ValidationError("must be a bigint", field);
|
|
223
|
-
}
|
|
224
|
-
if (!isValidScalar(value)) {
|
|
225
|
-
throw new ValidationError(
|
|
226
|
-
"must be in range (0, curve order)",
|
|
227
|
-
field,
|
|
228
|
-
{ curveOrder: SECP256K1_ORDER.toString(16) }
|
|
229
|
-
);
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
function isValidEvmAddress(address) {
|
|
233
|
-
if (typeof address !== "string") return false;
|
|
234
|
-
return /^0x[0-9a-fA-F]{40}$/.test(address);
|
|
235
|
-
}
|
|
236
|
-
function isValidSolanaAddressFormat(address) {
|
|
237
|
-
if (typeof address !== "string") return false;
|
|
238
|
-
return /^[1-9A-HJ-NP-Za-km-z]{32,44}$/.test(address);
|
|
239
|
-
}
|
|
240
|
-
function isValidNearAddressFormat(address) {
|
|
241
|
-
if (typeof address !== "string") return false;
|
|
242
|
-
if (/^[0-9a-f]{64}$/.test(address)) return true;
|
|
243
|
-
if (address.length < 2 || address.length > 64) return false;
|
|
244
|
-
if (!/^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$/.test(address)) return false;
|
|
245
|
-
if (address.includes("..")) return false;
|
|
246
|
-
return true;
|
|
247
|
-
}
|
|
248
|
-
function isValidCosmosAddressFormat(address) {
|
|
249
|
-
if (typeof address !== "string") return false;
|
|
250
|
-
if (address.length < 39 || address.length > 90) return false;
|
|
251
|
-
const bech32Pattern = /^[a-z]+1[qpzry9x8gf2tvdw0s3jn54khce6mua7l]{38,}$/;
|
|
252
|
-
return bech32Pattern.test(address);
|
|
253
|
-
}
|
|
254
|
-
function getChainAddressType(chain) {
|
|
255
|
-
switch (chain) {
|
|
256
|
-
case "ethereum":
|
|
257
|
-
case "polygon":
|
|
258
|
-
case "arbitrum":
|
|
259
|
-
case "optimism":
|
|
260
|
-
case "base":
|
|
261
|
-
return "evm";
|
|
262
|
-
case "solana":
|
|
263
|
-
return "solana";
|
|
264
|
-
case "near":
|
|
265
|
-
return "near";
|
|
266
|
-
case "zcash":
|
|
267
|
-
return "zcash";
|
|
268
|
-
case "cosmos":
|
|
269
|
-
case "osmosis":
|
|
270
|
-
case "injective":
|
|
271
|
-
case "celestia":
|
|
272
|
-
case "sei":
|
|
273
|
-
case "dydx":
|
|
274
|
-
return "cosmos";
|
|
275
|
-
default:
|
|
276
|
-
return "unknown";
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
function validateAddressForChain(address, chain, field = "address") {
|
|
280
|
-
const addressType = getChainAddressType(chain);
|
|
281
|
-
switch (addressType) {
|
|
282
|
-
case "evm":
|
|
283
|
-
if (!isValidEvmAddress(address)) {
|
|
284
|
-
throw new ValidationError(
|
|
285
|
-
`Invalid address format for ${chain}. Expected EVM address (0x + 40 hex chars), got: ${address.slice(0, 20)}...`,
|
|
286
|
-
field,
|
|
287
|
-
{ chain, expectedFormat: "0x...", receivedFormat: address.startsWith("0x") ? "hex but wrong length" : "not hex" }
|
|
288
|
-
);
|
|
289
|
-
}
|
|
290
|
-
break;
|
|
291
|
-
case "solana":
|
|
292
|
-
if (!isValidSolanaAddressFormat(address)) {
|
|
293
|
-
throw new ValidationError(
|
|
294
|
-
`Invalid address format for ${chain}. Expected Solana address (base58, 32-44 chars), got: ${address.slice(0, 20)}...`,
|
|
295
|
-
field,
|
|
296
|
-
{ chain, expectedFormat: "base58", receivedFormat: address.startsWith("0x") ? "looks like EVM" : "unknown" }
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
break;
|
|
300
|
-
case "near":
|
|
301
|
-
if (!isValidNearAddressFormat(address)) {
|
|
302
|
-
throw new ValidationError(
|
|
303
|
-
`Invalid address format for ${chain}. Expected NEAR account ID (named or implicit), got: ${address.slice(0, 20)}...`,
|
|
304
|
-
field,
|
|
305
|
-
{ chain, expectedFormat: "alice.near or 64 hex chars" }
|
|
306
|
-
);
|
|
307
|
-
}
|
|
308
|
-
break;
|
|
309
|
-
case "zcash":
|
|
310
|
-
if (!address || address.length === 0) {
|
|
311
|
-
throw new ValidationError(
|
|
312
|
-
`Invalid address format for ${chain}. Expected Zcash address.`,
|
|
313
|
-
field,
|
|
314
|
-
{ chain }
|
|
315
|
-
);
|
|
316
|
-
}
|
|
317
|
-
break;
|
|
318
|
-
case "cosmos":
|
|
319
|
-
if (!isValidCosmosAddressFormat(address)) {
|
|
320
|
-
throw new ValidationError(
|
|
321
|
-
`Invalid address format for ${chain}. Expected Cosmos bech32 address, got: ${address.slice(0, 20)}...`,
|
|
322
|
-
field,
|
|
323
|
-
{ chain, expectedFormat: "bech32" }
|
|
324
|
-
);
|
|
325
|
-
}
|
|
326
|
-
break;
|
|
327
|
-
default:
|
|
328
|
-
break;
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
function isAddressValidForChain(address, chain) {
|
|
332
|
-
try {
|
|
333
|
-
validateAddressForChain(address, chain);
|
|
334
|
-
return true;
|
|
335
|
-
} catch {
|
|
336
|
-
return false;
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
// src/secure-memory.ts
|
|
341
|
-
import { randomBytes } from "@noble/hashes/utils";
|
|
342
|
-
function secureWipe(buffer) {
|
|
343
|
-
if (!buffer || buffer.length === 0) {
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
const random = randomBytes(buffer.length);
|
|
347
|
-
buffer.set(random);
|
|
348
|
-
buffer.fill(0);
|
|
349
|
-
}
|
|
350
|
-
async function withSecureBuffer(createSecret, useSecret) {
|
|
351
|
-
const secret = createSecret();
|
|
352
|
-
try {
|
|
353
|
-
return await useSecret(secret);
|
|
354
|
-
} finally {
|
|
355
|
-
secureWipe(secret);
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
function withSecureBufferSync(createSecret, useSecret) {
|
|
359
|
-
const secret = createSecret();
|
|
360
|
-
try {
|
|
361
|
-
return useSecret(secret);
|
|
362
|
-
} finally {
|
|
363
|
-
secureWipe(secret);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
function secureWipeAll(...buffers) {
|
|
367
|
-
for (const buffer of buffers) {
|
|
368
|
-
if (buffer) {
|
|
369
|
-
secureWipe(buffer);
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
// src/stealth.ts
|
|
375
|
-
function generateStealthMetaAddress(chain, label) {
|
|
376
|
-
if (!isValidChainId(chain)) {
|
|
377
|
-
throw new ValidationError(
|
|
378
|
-
`invalid chain '${chain}', must be one of: solana, ethereum, near, zcash, polygon, arbitrum, optimism, base, bitcoin, aptos, sui, cosmos, osmosis, injective, celestia, sei, dydx`,
|
|
379
|
-
"chain"
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
const spendingPrivateKey = randomBytes2(32);
|
|
383
|
-
const viewingPrivateKey = randomBytes2(32);
|
|
384
|
-
try {
|
|
385
|
-
const spendingKey = secp256k1.getPublicKey(spendingPrivateKey, true);
|
|
386
|
-
const viewingKey = secp256k1.getPublicKey(viewingPrivateKey, true);
|
|
387
|
-
const result = {
|
|
388
|
-
metaAddress: {
|
|
389
|
-
spendingKey: `0x${bytesToHex(spendingKey)}`,
|
|
390
|
-
viewingKey: `0x${bytesToHex(viewingKey)}`,
|
|
391
|
-
chain,
|
|
392
|
-
label
|
|
393
|
-
},
|
|
394
|
-
spendingPrivateKey: `0x${bytesToHex(spendingPrivateKey)}`,
|
|
395
|
-
viewingPrivateKey: `0x${bytesToHex(viewingPrivateKey)}`
|
|
396
|
-
};
|
|
397
|
-
return result;
|
|
398
|
-
} finally {
|
|
399
|
-
secureWipeAll(spendingPrivateKey, viewingPrivateKey);
|
|
400
|
-
}
|
|
401
|
-
}
|
|
402
|
-
function validateStealthMetaAddress(metaAddress, field = "recipientMetaAddress") {
|
|
403
|
-
if (!metaAddress || typeof metaAddress !== "object") {
|
|
404
|
-
throw new ValidationError("must be an object", field);
|
|
405
|
-
}
|
|
406
|
-
if (!isValidChainId(metaAddress.chain)) {
|
|
407
|
-
throw new ValidationError(
|
|
408
|
-
`invalid chain '${metaAddress.chain}'`,
|
|
409
|
-
`${field}.chain`
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
const isEd25519 = isEd25519Chain(metaAddress.chain);
|
|
413
|
-
if (isEd25519) {
|
|
414
|
-
if (!isValidEd25519PublicKey(metaAddress.spendingKey)) {
|
|
415
|
-
throw new ValidationError(
|
|
416
|
-
"spendingKey must be a valid ed25519 public key (32 bytes)",
|
|
417
|
-
`${field}.spendingKey`
|
|
418
|
-
);
|
|
419
|
-
}
|
|
420
|
-
if (!isValidEd25519PublicKey(metaAddress.viewingKey)) {
|
|
421
|
-
throw new ValidationError(
|
|
422
|
-
"viewingKey must be a valid ed25519 public key (32 bytes)",
|
|
423
|
-
`${field}.viewingKey`
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
} else {
|
|
427
|
-
if (!isValidCompressedPublicKey(metaAddress.spendingKey)) {
|
|
428
|
-
throw new ValidationError(
|
|
429
|
-
"spendingKey must be a valid compressed secp256k1 public key (33 bytes, starting with 02 or 03)",
|
|
430
|
-
`${field}.spendingKey`
|
|
431
|
-
);
|
|
432
|
-
}
|
|
433
|
-
if (!isValidCompressedPublicKey(metaAddress.viewingKey)) {
|
|
434
|
-
throw new ValidationError(
|
|
435
|
-
"viewingKey must be a valid compressed secp256k1 public key (33 bytes, starting with 02 or 03)",
|
|
436
|
-
`${field}.viewingKey`
|
|
437
|
-
);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
function generateStealthAddress(recipientMetaAddress) {
|
|
442
|
-
validateStealthMetaAddress(recipientMetaAddress);
|
|
443
|
-
const ephemeralPrivateKey = randomBytes2(32);
|
|
444
|
-
try {
|
|
445
|
-
const ephemeralPublicKey = secp256k1.getPublicKey(ephemeralPrivateKey, true);
|
|
446
|
-
const spendingKeyBytes = hexToBytes(recipientMetaAddress.spendingKey.slice(2));
|
|
447
|
-
const viewingKeyBytes = hexToBytes(recipientMetaAddress.viewingKey.slice(2));
|
|
448
|
-
const sharedSecretPoint = secp256k1.getSharedSecret(
|
|
449
|
-
ephemeralPrivateKey,
|
|
450
|
-
spendingKeyBytes
|
|
451
|
-
);
|
|
452
|
-
const sharedSecretHash = sha256(sharedSecretPoint);
|
|
453
|
-
const hashTimesG = secp256k1.getPublicKey(sharedSecretHash, true);
|
|
454
|
-
const viewingKeyPoint = secp256k1.ProjectivePoint.fromHex(viewingKeyBytes);
|
|
455
|
-
const hashTimesGPoint = secp256k1.ProjectivePoint.fromHex(hashTimesG);
|
|
456
|
-
const stealthPoint = viewingKeyPoint.add(hashTimesGPoint);
|
|
457
|
-
const stealthAddressBytes = stealthPoint.toRawBytes(true);
|
|
458
|
-
const viewTag = sharedSecretHash[0];
|
|
459
|
-
return {
|
|
460
|
-
stealthAddress: {
|
|
461
|
-
address: `0x${bytesToHex(stealthAddressBytes)}`,
|
|
462
|
-
ephemeralPublicKey: `0x${bytesToHex(ephemeralPublicKey)}`,
|
|
463
|
-
viewTag
|
|
464
|
-
},
|
|
465
|
-
sharedSecret: `0x${bytesToHex(sharedSecretHash)}`
|
|
466
|
-
};
|
|
467
|
-
} finally {
|
|
468
|
-
secureWipe(ephemeralPrivateKey);
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
|
-
function validateStealthAddress(stealthAddress, field = "stealthAddress") {
|
|
472
|
-
if (!stealthAddress || typeof stealthAddress !== "object") {
|
|
473
|
-
throw new ValidationError("must be an object", field);
|
|
474
|
-
}
|
|
475
|
-
if (!isValidCompressedPublicKey(stealthAddress.address)) {
|
|
476
|
-
throw new ValidationError(
|
|
477
|
-
"address must be a valid compressed secp256k1 public key",
|
|
478
|
-
`${field}.address`
|
|
479
|
-
);
|
|
480
|
-
}
|
|
481
|
-
if (!isValidCompressedPublicKey(stealthAddress.ephemeralPublicKey)) {
|
|
482
|
-
throw new ValidationError(
|
|
483
|
-
"ephemeralPublicKey must be a valid compressed secp256k1 public key",
|
|
484
|
-
`${field}.ephemeralPublicKey`
|
|
485
|
-
);
|
|
486
|
-
}
|
|
487
|
-
if (typeof stealthAddress.viewTag !== "number" || !Number.isInteger(stealthAddress.viewTag) || stealthAddress.viewTag < 0 || stealthAddress.viewTag > 255) {
|
|
488
|
-
throw new ValidationError(
|
|
489
|
-
"viewTag must be an integer between 0 and 255",
|
|
490
|
-
`${field}.viewTag`
|
|
491
|
-
);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
function deriveStealthPrivateKey(stealthAddress, spendingPrivateKey, viewingPrivateKey) {
|
|
495
|
-
validateStealthAddress(stealthAddress);
|
|
496
|
-
if (!isValidPrivateKey(spendingPrivateKey)) {
|
|
497
|
-
throw new ValidationError(
|
|
498
|
-
"must be a valid 32-byte hex string",
|
|
499
|
-
"spendingPrivateKey"
|
|
500
|
-
);
|
|
501
|
-
}
|
|
502
|
-
if (!isValidPrivateKey(viewingPrivateKey)) {
|
|
503
|
-
throw new ValidationError(
|
|
504
|
-
"must be a valid 32-byte hex string",
|
|
505
|
-
"viewingPrivateKey"
|
|
506
|
-
);
|
|
507
|
-
}
|
|
508
|
-
const spendingPrivBytes = hexToBytes(spendingPrivateKey.slice(2));
|
|
509
|
-
const viewingPrivBytes = hexToBytes(viewingPrivateKey.slice(2));
|
|
510
|
-
const ephemeralPubBytes = hexToBytes(stealthAddress.ephemeralPublicKey.slice(2));
|
|
511
|
-
try {
|
|
512
|
-
const sharedSecretPoint = secp256k1.getSharedSecret(
|
|
513
|
-
spendingPrivBytes,
|
|
514
|
-
ephemeralPubBytes
|
|
515
|
-
);
|
|
516
|
-
const sharedSecretHash = sha256(sharedSecretPoint);
|
|
517
|
-
const viewingScalar = bytesToBigInt(viewingPrivBytes);
|
|
518
|
-
const hashScalar = bytesToBigInt(sharedSecretHash);
|
|
519
|
-
const stealthPrivateScalar = (viewingScalar + hashScalar) % secp256k1.CURVE.n;
|
|
520
|
-
const stealthPrivateKey = bigIntToBytes(stealthPrivateScalar, 32);
|
|
521
|
-
const result = {
|
|
522
|
-
stealthAddress: stealthAddress.address,
|
|
523
|
-
ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
|
|
524
|
-
privateKey: `0x${bytesToHex(stealthPrivateKey)}`
|
|
525
|
-
};
|
|
526
|
-
secureWipe(stealthPrivateKey);
|
|
527
|
-
return result;
|
|
528
|
-
} finally {
|
|
529
|
-
secureWipeAll(spendingPrivBytes, viewingPrivBytes);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
function checkStealthAddress(stealthAddress, spendingPrivateKey, viewingPrivateKey) {
|
|
533
|
-
validateStealthAddress(stealthAddress);
|
|
534
|
-
if (!isValidPrivateKey(spendingPrivateKey)) {
|
|
535
|
-
throw new ValidationError(
|
|
536
|
-
"must be a valid 32-byte hex string",
|
|
537
|
-
"spendingPrivateKey"
|
|
538
|
-
);
|
|
539
|
-
}
|
|
540
|
-
if (!isValidPrivateKey(viewingPrivateKey)) {
|
|
541
|
-
throw new ValidationError(
|
|
542
|
-
"must be a valid 32-byte hex string",
|
|
543
|
-
"viewingPrivateKey"
|
|
544
|
-
);
|
|
545
|
-
}
|
|
546
|
-
const spendingPrivBytes = hexToBytes(spendingPrivateKey.slice(2));
|
|
547
|
-
const viewingPrivBytes = hexToBytes(viewingPrivateKey.slice(2));
|
|
548
|
-
const ephemeralPubBytes = hexToBytes(stealthAddress.ephemeralPublicKey.slice(2));
|
|
549
|
-
try {
|
|
550
|
-
const sharedSecretPoint = secp256k1.getSharedSecret(
|
|
551
|
-
spendingPrivBytes,
|
|
552
|
-
ephemeralPubBytes
|
|
553
|
-
);
|
|
554
|
-
const sharedSecretHash = sha256(sharedSecretPoint);
|
|
555
|
-
if (sharedSecretHash[0] !== stealthAddress.viewTag) {
|
|
556
|
-
return false;
|
|
557
|
-
}
|
|
558
|
-
const viewingScalar = bytesToBigInt(viewingPrivBytes);
|
|
559
|
-
const hashScalar = bytesToBigInt(sharedSecretHash);
|
|
560
|
-
const stealthPrivateScalar = (viewingScalar + hashScalar) % secp256k1.CURVE.n;
|
|
561
|
-
const derivedKeyBytes = bigIntToBytes(stealthPrivateScalar, 32);
|
|
562
|
-
const expectedPubKey = secp256k1.getPublicKey(derivedKeyBytes, true);
|
|
563
|
-
secureWipe(derivedKeyBytes);
|
|
564
|
-
const providedAddress = hexToBytes(stealthAddress.address.slice(2));
|
|
565
|
-
return bytesToHex(expectedPubKey) === bytesToHex(providedAddress);
|
|
566
|
-
} finally {
|
|
567
|
-
secureWipeAll(spendingPrivBytes, viewingPrivBytes);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
function encodeStealthMetaAddress(metaAddress) {
|
|
571
|
-
return `sip:${metaAddress.chain}:${metaAddress.spendingKey}:${metaAddress.viewingKey}`;
|
|
572
|
-
}
|
|
573
|
-
function decodeStealthMetaAddress(encoded) {
|
|
574
|
-
if (typeof encoded !== "string") {
|
|
575
|
-
throw new ValidationError("must be a string", "encoded");
|
|
576
|
-
}
|
|
577
|
-
const parts = encoded.split(":");
|
|
578
|
-
if (parts.length < 4 || parts[0] !== "sip") {
|
|
579
|
-
throw new ValidationError(
|
|
580
|
-
"invalid format, expected: sip:<chain>:<spendingKey>:<viewingKey>",
|
|
581
|
-
"encoded"
|
|
582
|
-
);
|
|
583
|
-
}
|
|
584
|
-
const [, chain, spendingKey, viewingKey] = parts;
|
|
585
|
-
if (!isValidChainId(chain)) {
|
|
586
|
-
throw new ValidationError(
|
|
587
|
-
`invalid chain '${chain}'`,
|
|
588
|
-
"encoded.chain"
|
|
589
|
-
);
|
|
590
|
-
}
|
|
591
|
-
const chainId = chain;
|
|
592
|
-
if (isEd25519Chain(chainId)) {
|
|
593
|
-
if (!isValidEd25519PublicKey(spendingKey)) {
|
|
594
|
-
throw new ValidationError(
|
|
595
|
-
"spendingKey must be a valid 32-byte ed25519 public key",
|
|
596
|
-
"encoded.spendingKey"
|
|
597
|
-
);
|
|
598
|
-
}
|
|
599
|
-
if (!isValidEd25519PublicKey(viewingKey)) {
|
|
600
|
-
throw new ValidationError(
|
|
601
|
-
"viewingKey must be a valid 32-byte ed25519 public key",
|
|
602
|
-
"encoded.viewingKey"
|
|
603
|
-
);
|
|
604
|
-
}
|
|
605
|
-
} else {
|
|
606
|
-
if (!isValidCompressedPublicKey(spendingKey)) {
|
|
607
|
-
throw new ValidationError(
|
|
608
|
-
"spendingKey must be a valid compressed secp256k1 public key",
|
|
609
|
-
"encoded.spendingKey"
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
if (!isValidCompressedPublicKey(viewingKey)) {
|
|
613
|
-
throw new ValidationError(
|
|
614
|
-
"viewingKey must be a valid compressed secp256k1 public key",
|
|
615
|
-
"encoded.viewingKey"
|
|
616
|
-
);
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
return {
|
|
620
|
-
chain,
|
|
621
|
-
spendingKey,
|
|
622
|
-
viewingKey
|
|
623
|
-
};
|
|
624
|
-
}
|
|
625
|
-
function bytesToBigInt(bytes) {
|
|
626
|
-
let result = 0n;
|
|
627
|
-
for (const byte of bytes) {
|
|
628
|
-
result = (result << 8n) + BigInt(byte);
|
|
629
|
-
}
|
|
630
|
-
return result;
|
|
631
|
-
}
|
|
632
|
-
function bigIntToBytes(value, length) {
|
|
633
|
-
const bytes = new Uint8Array(length);
|
|
634
|
-
for (let i = length - 1; i >= 0; i--) {
|
|
635
|
-
bytes[i] = Number(value & 0xffn);
|
|
636
|
-
value >>= 8n;
|
|
637
|
-
}
|
|
638
|
-
return bytes;
|
|
639
|
-
}
|
|
640
|
-
function publicKeyToEthAddress(publicKey) {
|
|
641
|
-
const keyHex = publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey;
|
|
642
|
-
const keyBytes = hexToBytes(keyHex);
|
|
643
|
-
let uncompressedBytes;
|
|
644
|
-
if (keyBytes.length === 33) {
|
|
645
|
-
const point = secp256k1.ProjectivePoint.fromHex(keyBytes);
|
|
646
|
-
uncompressedBytes = point.toRawBytes(false);
|
|
647
|
-
} else if (keyBytes.length === 65) {
|
|
648
|
-
uncompressedBytes = keyBytes;
|
|
649
|
-
} else {
|
|
650
|
-
throw new ValidationError(
|
|
651
|
-
`invalid public key length: ${keyBytes.length}, expected 33 (compressed) or 65 (uncompressed)`,
|
|
652
|
-
"publicKey"
|
|
653
|
-
);
|
|
654
|
-
}
|
|
655
|
-
const pubKeyWithoutPrefix = uncompressedBytes.slice(1);
|
|
656
|
-
const hash2 = keccak_256(pubKeyWithoutPrefix);
|
|
657
|
-
const addressBytes = hash2.slice(-20);
|
|
658
|
-
return toChecksumAddress(`0x${bytesToHex(addressBytes)}`);
|
|
659
|
-
}
|
|
660
|
-
function toChecksumAddress(address) {
|
|
661
|
-
const addr = address.toLowerCase().replace("0x", "");
|
|
662
|
-
const hash2 = bytesToHex(keccak_256(new TextEncoder().encode(addr)));
|
|
663
|
-
let checksummed = "0x";
|
|
664
|
-
for (let i = 0; i < addr.length; i++) {
|
|
665
|
-
if (parseInt(hash2[i], 16) >= 8) {
|
|
666
|
-
checksummed += addr[i].toUpperCase();
|
|
667
|
-
} else {
|
|
668
|
-
checksummed += addr[i];
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
return checksummed;
|
|
672
|
-
}
|
|
673
|
-
var ED25519_ORDER = 2n ** 252n + 27742317777372353535851937790883648493n;
|
|
674
|
-
var ED25519_CHAINS = ["solana", "near", "aptos", "sui"];
|
|
675
|
-
function isEd25519Chain(chain) {
|
|
676
|
-
return ED25519_CHAINS.includes(chain);
|
|
677
|
-
}
|
|
678
|
-
function getCurveForChain(chain) {
|
|
679
|
-
return isEd25519Chain(chain) ? "ed25519" : "secp256k1";
|
|
680
|
-
}
|
|
681
|
-
function validateEd25519StealthMetaAddress(metaAddress, field = "recipientMetaAddress") {
|
|
682
|
-
if (!metaAddress || typeof metaAddress !== "object") {
|
|
683
|
-
throw new ValidationError("must be an object", field);
|
|
684
|
-
}
|
|
685
|
-
if (!isValidChainId(metaAddress.chain)) {
|
|
686
|
-
throw new ValidationError(
|
|
687
|
-
`invalid chain '${metaAddress.chain}'`,
|
|
688
|
-
`${field}.chain`
|
|
689
|
-
);
|
|
690
|
-
}
|
|
691
|
-
if (!isEd25519Chain(metaAddress.chain)) {
|
|
692
|
-
throw new ValidationError(
|
|
693
|
-
`chain '${metaAddress.chain}' does not use ed25519, use secp256k1 functions instead`,
|
|
694
|
-
`${field}.chain`
|
|
695
|
-
);
|
|
696
|
-
}
|
|
697
|
-
if (!isValidEd25519PublicKey(metaAddress.spendingKey)) {
|
|
698
|
-
throw new ValidationError(
|
|
699
|
-
"spendingKey must be a valid ed25519 public key (32 bytes)",
|
|
700
|
-
`${field}.spendingKey`
|
|
701
|
-
);
|
|
702
|
-
}
|
|
703
|
-
if (!isValidEd25519PublicKey(metaAddress.viewingKey)) {
|
|
704
|
-
throw new ValidationError(
|
|
705
|
-
"viewingKey must be a valid ed25519 public key (32 bytes)",
|
|
706
|
-
`${field}.viewingKey`
|
|
707
|
-
);
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
function validateEd25519StealthAddress(stealthAddress, field = "stealthAddress") {
|
|
711
|
-
if (!stealthAddress || typeof stealthAddress !== "object") {
|
|
712
|
-
throw new ValidationError("must be an object", field);
|
|
713
|
-
}
|
|
714
|
-
if (!isValidEd25519PublicKey(stealthAddress.address)) {
|
|
715
|
-
throw new ValidationError(
|
|
716
|
-
"address must be a valid ed25519 public key (32 bytes)",
|
|
717
|
-
`${field}.address`
|
|
718
|
-
);
|
|
719
|
-
}
|
|
720
|
-
if (!isValidEd25519PublicKey(stealthAddress.ephemeralPublicKey)) {
|
|
721
|
-
throw new ValidationError(
|
|
722
|
-
"ephemeralPublicKey must be a valid ed25519 public key (32 bytes)",
|
|
723
|
-
`${field}.ephemeralPublicKey`
|
|
724
|
-
);
|
|
725
|
-
}
|
|
726
|
-
if (typeof stealthAddress.viewTag !== "number" || !Number.isInteger(stealthAddress.viewTag) || stealthAddress.viewTag < 0 || stealthAddress.viewTag > 255) {
|
|
727
|
-
throw new ValidationError(
|
|
728
|
-
"viewTag must be an integer between 0 and 255",
|
|
729
|
-
`${field}.viewTag`
|
|
730
|
-
);
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
function getEd25519Scalar(privateKey) {
|
|
734
|
-
const hash2 = sha512(privateKey);
|
|
735
|
-
const scalar = hash2.slice(0, 32);
|
|
736
|
-
scalar[0] &= 248;
|
|
737
|
-
scalar[31] &= 127;
|
|
738
|
-
scalar[31] |= 64;
|
|
739
|
-
return bytesToBigIntLE(scalar);
|
|
740
|
-
}
|
|
741
|
-
function bytesToBigIntLE(bytes) {
|
|
742
|
-
let result = 0n;
|
|
743
|
-
for (let i = bytes.length - 1; i >= 0; i--) {
|
|
744
|
-
result = (result << 8n) + BigInt(bytes[i]);
|
|
745
|
-
}
|
|
746
|
-
return result;
|
|
747
|
-
}
|
|
748
|
-
function bigIntToBytesLE(value, length) {
|
|
749
|
-
const bytes = new Uint8Array(length);
|
|
750
|
-
for (let i = 0; i < length; i++) {
|
|
751
|
-
bytes[i] = Number(value & 0xffn);
|
|
752
|
-
value >>= 8n;
|
|
753
|
-
}
|
|
754
|
-
return bytes;
|
|
755
|
-
}
|
|
756
|
-
function generateEd25519StealthMetaAddress(chain, label) {
|
|
757
|
-
if (!isValidChainId(chain)) {
|
|
758
|
-
throw new ValidationError(
|
|
759
|
-
`invalid chain '${chain}', must be one of: solana, ethereum, near, zcash, polygon, arbitrum, optimism, base, bitcoin, aptos, sui, cosmos, osmosis, injective, celestia, sei, dydx`,
|
|
760
|
-
"chain"
|
|
761
|
-
);
|
|
762
|
-
}
|
|
763
|
-
if (!isEd25519Chain(chain)) {
|
|
764
|
-
throw new ValidationError(
|
|
765
|
-
`chain '${chain}' does not use ed25519, use generateStealthMetaAddress() for secp256k1 chains`,
|
|
766
|
-
"chain"
|
|
767
|
-
);
|
|
768
|
-
}
|
|
769
|
-
const spendingPrivateKey = randomBytes2(32);
|
|
770
|
-
const viewingPrivateKey = randomBytes2(32);
|
|
771
|
-
try {
|
|
772
|
-
const spendingKey = ed25519.getPublicKey(spendingPrivateKey);
|
|
773
|
-
const viewingKey = ed25519.getPublicKey(viewingPrivateKey);
|
|
774
|
-
const result = {
|
|
775
|
-
metaAddress: {
|
|
776
|
-
spendingKey: `0x${bytesToHex(spendingKey)}`,
|
|
777
|
-
viewingKey: `0x${bytesToHex(viewingKey)}`,
|
|
778
|
-
chain,
|
|
779
|
-
label
|
|
780
|
-
},
|
|
781
|
-
spendingPrivateKey: `0x${bytesToHex(spendingPrivateKey)}`,
|
|
782
|
-
viewingPrivateKey: `0x${bytesToHex(viewingPrivateKey)}`
|
|
783
|
-
};
|
|
784
|
-
return result;
|
|
785
|
-
} finally {
|
|
786
|
-
secureWipeAll(spendingPrivateKey, viewingPrivateKey);
|
|
787
|
-
}
|
|
788
|
-
}
|
|
789
|
-
function generateEd25519StealthAddress(recipientMetaAddress) {
|
|
790
|
-
validateEd25519StealthMetaAddress(recipientMetaAddress);
|
|
791
|
-
const ephemeralPrivateKey = randomBytes2(32);
|
|
792
|
-
try {
|
|
793
|
-
const ephemeralPublicKey = ed25519.getPublicKey(ephemeralPrivateKey);
|
|
794
|
-
const spendingKeyBytes = hexToBytes(recipientMetaAddress.spendingKey.slice(2));
|
|
795
|
-
const viewingKeyBytes = hexToBytes(recipientMetaAddress.viewingKey.slice(2));
|
|
796
|
-
const rawEphemeralScalar = getEd25519Scalar(ephemeralPrivateKey);
|
|
797
|
-
const ephemeralScalar = rawEphemeralScalar % ED25519_ORDER;
|
|
798
|
-
if (ephemeralScalar === 0n) {
|
|
799
|
-
throw new Error("CRITICAL: Zero ephemeral scalar after reduction - investigate RNG");
|
|
800
|
-
}
|
|
801
|
-
const spendingPoint = ed25519.ExtendedPoint.fromHex(spendingKeyBytes);
|
|
802
|
-
const sharedSecretPoint = spendingPoint.multiply(ephemeralScalar);
|
|
803
|
-
const sharedSecretHash = sha256(sharedSecretPoint.toRawBytes());
|
|
804
|
-
const hashScalar = bytesToBigInt(sharedSecretHash) % ED25519_ORDER;
|
|
805
|
-
if (hashScalar === 0n) {
|
|
806
|
-
throw new Error("CRITICAL: Zero hash scalar after reduction - investigate hash computation");
|
|
807
|
-
}
|
|
808
|
-
const hashTimesG = ed25519.ExtendedPoint.BASE.multiply(hashScalar);
|
|
809
|
-
const viewingPoint = ed25519.ExtendedPoint.fromHex(viewingKeyBytes);
|
|
810
|
-
const stealthPoint = viewingPoint.add(hashTimesG);
|
|
811
|
-
const stealthAddressBytes = stealthPoint.toRawBytes();
|
|
812
|
-
const viewTag = sharedSecretHash[0];
|
|
813
|
-
return {
|
|
814
|
-
stealthAddress: {
|
|
815
|
-
address: `0x${bytesToHex(stealthAddressBytes)}`,
|
|
816
|
-
ephemeralPublicKey: `0x${bytesToHex(ephemeralPublicKey)}`,
|
|
817
|
-
viewTag
|
|
818
|
-
},
|
|
819
|
-
sharedSecret: `0x${bytesToHex(sharedSecretHash)}`
|
|
820
|
-
};
|
|
821
|
-
} finally {
|
|
822
|
-
secureWipe(ephemeralPrivateKey);
|
|
823
|
-
}
|
|
824
|
-
}
|
|
825
|
-
function deriveEd25519StealthPrivateKey(stealthAddress, spendingPrivateKey, viewingPrivateKey) {
|
|
826
|
-
validateEd25519StealthAddress(stealthAddress);
|
|
827
|
-
if (!isValidPrivateKey(spendingPrivateKey)) {
|
|
828
|
-
throw new ValidationError(
|
|
829
|
-
"must be a valid 32-byte hex string",
|
|
830
|
-
"spendingPrivateKey"
|
|
831
|
-
);
|
|
832
|
-
}
|
|
833
|
-
if (!isValidPrivateKey(viewingPrivateKey)) {
|
|
834
|
-
throw new ValidationError(
|
|
835
|
-
"must be a valid 32-byte hex string",
|
|
836
|
-
"viewingPrivateKey"
|
|
837
|
-
);
|
|
838
|
-
}
|
|
839
|
-
const spendingPrivBytes = hexToBytes(spendingPrivateKey.slice(2));
|
|
840
|
-
const viewingPrivBytes = hexToBytes(viewingPrivateKey.slice(2));
|
|
841
|
-
const ephemeralPubBytes = hexToBytes(stealthAddress.ephemeralPublicKey.slice(2));
|
|
842
|
-
try {
|
|
843
|
-
const rawSpendingScalar = getEd25519Scalar(spendingPrivBytes);
|
|
844
|
-
const spendingScalar = rawSpendingScalar % ED25519_ORDER;
|
|
845
|
-
if (spendingScalar === 0n) {
|
|
846
|
-
throw new Error("CRITICAL: Zero spending scalar after reduction - investigate key derivation");
|
|
847
|
-
}
|
|
848
|
-
const ephemeralPoint = ed25519.ExtendedPoint.fromHex(ephemeralPubBytes);
|
|
849
|
-
const sharedSecretPoint = ephemeralPoint.multiply(spendingScalar);
|
|
850
|
-
const sharedSecretHash = sha256(sharedSecretPoint.toRawBytes());
|
|
851
|
-
const rawViewingScalar = getEd25519Scalar(viewingPrivBytes);
|
|
852
|
-
const viewingScalar = rawViewingScalar % ED25519_ORDER;
|
|
853
|
-
if (viewingScalar === 0n) {
|
|
854
|
-
throw new Error("CRITICAL: Zero viewing scalar after reduction - investigate key derivation");
|
|
855
|
-
}
|
|
856
|
-
const hashScalar = bytesToBigInt(sharedSecretHash) % ED25519_ORDER;
|
|
857
|
-
if (hashScalar === 0n) {
|
|
858
|
-
throw new Error("CRITICAL: Zero hash scalar after reduction - investigate hash computation");
|
|
859
|
-
}
|
|
860
|
-
const stealthPrivateScalar = (viewingScalar + hashScalar) % ED25519_ORDER;
|
|
861
|
-
if (stealthPrivateScalar === 0n) {
|
|
862
|
-
throw new Error("CRITICAL: Zero stealth scalar after reduction - investigate key derivation");
|
|
863
|
-
}
|
|
864
|
-
const stealthPrivateKey = bigIntToBytesLE(stealthPrivateScalar, 32);
|
|
865
|
-
const result = {
|
|
866
|
-
stealthAddress: stealthAddress.address,
|
|
867
|
-
ephemeralPublicKey: stealthAddress.ephemeralPublicKey,
|
|
868
|
-
privateKey: `0x${bytesToHex(stealthPrivateKey)}`
|
|
869
|
-
};
|
|
870
|
-
secureWipe(stealthPrivateKey);
|
|
871
|
-
return result;
|
|
872
|
-
} finally {
|
|
873
|
-
secureWipeAll(spendingPrivBytes, viewingPrivBytes);
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
function checkEd25519StealthAddress(stealthAddress, spendingPrivateKey, viewingPrivateKey) {
|
|
877
|
-
validateEd25519StealthAddress(stealthAddress);
|
|
878
|
-
if (!isValidPrivateKey(spendingPrivateKey)) {
|
|
879
|
-
throw new ValidationError(
|
|
880
|
-
"must be a valid 32-byte hex string",
|
|
881
|
-
"spendingPrivateKey"
|
|
882
|
-
);
|
|
883
|
-
}
|
|
884
|
-
if (!isValidPrivateKey(viewingPrivateKey)) {
|
|
885
|
-
throw new ValidationError(
|
|
886
|
-
"must be a valid 32-byte hex string",
|
|
887
|
-
"viewingPrivateKey"
|
|
888
|
-
);
|
|
889
|
-
}
|
|
890
|
-
const spendingPrivBytes = hexToBytes(spendingPrivateKey.slice(2));
|
|
891
|
-
const viewingPrivBytes = hexToBytes(viewingPrivateKey.slice(2));
|
|
892
|
-
const ephemeralPubBytes = hexToBytes(stealthAddress.ephemeralPublicKey.slice(2));
|
|
893
|
-
try {
|
|
894
|
-
const rawSpendingScalar = getEd25519Scalar(spendingPrivBytes);
|
|
895
|
-
const spendingScalar = rawSpendingScalar % ED25519_ORDER;
|
|
896
|
-
if (spendingScalar === 0n) {
|
|
897
|
-
throw new Error("CRITICAL: Zero spending scalar after reduction - investigate key derivation");
|
|
898
|
-
}
|
|
899
|
-
const ephemeralPoint = ed25519.ExtendedPoint.fromHex(ephemeralPubBytes);
|
|
900
|
-
const sharedSecretPoint = ephemeralPoint.multiply(spendingScalar);
|
|
901
|
-
const sharedSecretHash = sha256(sharedSecretPoint.toRawBytes());
|
|
902
|
-
if (sharedSecretHash[0] !== stealthAddress.viewTag) {
|
|
903
|
-
return false;
|
|
904
|
-
}
|
|
905
|
-
const rawViewingScalar = getEd25519Scalar(viewingPrivBytes);
|
|
906
|
-
const viewingScalar = rawViewingScalar % ED25519_ORDER;
|
|
907
|
-
if (viewingScalar === 0n) {
|
|
908
|
-
throw new Error("CRITICAL: Zero viewing scalar after reduction - investigate key derivation");
|
|
909
|
-
}
|
|
910
|
-
const hashScalar = bytesToBigInt(sharedSecretHash) % ED25519_ORDER;
|
|
911
|
-
if (hashScalar === 0n) {
|
|
912
|
-
throw new Error("CRITICAL: Zero hash scalar after reduction - investigate hash computation");
|
|
913
|
-
}
|
|
914
|
-
const stealthPrivateScalar = (viewingScalar + hashScalar) % ED25519_ORDER;
|
|
915
|
-
if (stealthPrivateScalar === 0n) {
|
|
916
|
-
throw new Error("CRITICAL: Zero stealth scalar after reduction - investigate key derivation");
|
|
917
|
-
}
|
|
918
|
-
const expectedPubKey = ed25519.ExtendedPoint.BASE.multiply(stealthPrivateScalar);
|
|
919
|
-
const expectedPubKeyBytes = expectedPubKey.toRawBytes();
|
|
920
|
-
const providedAddress = hexToBytes(stealthAddress.address.slice(2));
|
|
921
|
-
return bytesToHex(expectedPubKeyBytes) === bytesToHex(providedAddress);
|
|
922
|
-
} finally {
|
|
923
|
-
secureWipeAll(spendingPrivBytes, viewingPrivBytes);
|
|
924
|
-
}
|
|
925
|
-
}
|
|
926
|
-
var BASE58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
|
|
927
|
-
function bytesToBase58(bytes) {
|
|
928
|
-
let leadingZeros = 0;
|
|
929
|
-
for (let i = 0; i < bytes.length && bytes[i] === 0; i++) {
|
|
930
|
-
leadingZeros++;
|
|
931
|
-
}
|
|
932
|
-
let value = 0n;
|
|
933
|
-
for (const byte of bytes) {
|
|
934
|
-
value = value * 256n + BigInt(byte);
|
|
935
|
-
}
|
|
936
|
-
let result = "";
|
|
937
|
-
while (value > 0n) {
|
|
938
|
-
const remainder = value % 58n;
|
|
939
|
-
value = value / 58n;
|
|
940
|
-
result = BASE58_ALPHABET[Number(remainder)] + result;
|
|
941
|
-
}
|
|
942
|
-
return "1".repeat(leadingZeros) + result;
|
|
943
|
-
}
|
|
944
|
-
function base58ToBytes(str) {
|
|
945
|
-
let leadingOnes = 0;
|
|
946
|
-
for (let i = 0; i < str.length && str[i] === "1"; i++) {
|
|
947
|
-
leadingOnes++;
|
|
948
|
-
}
|
|
949
|
-
let value = 0n;
|
|
950
|
-
for (const char of str) {
|
|
951
|
-
const index = BASE58_ALPHABET.indexOf(char);
|
|
952
|
-
if (index === -1) {
|
|
953
|
-
throw new ValidationError(`Invalid base58 character: ${char}`, "address");
|
|
954
|
-
}
|
|
955
|
-
value = value * 58n + BigInt(index);
|
|
956
|
-
}
|
|
957
|
-
const bytes = [];
|
|
958
|
-
while (value > 0n) {
|
|
959
|
-
bytes.unshift(Number(value % 256n));
|
|
960
|
-
value = value / 256n;
|
|
961
|
-
}
|
|
962
|
-
const result = new Uint8Array(leadingOnes + bytes.length);
|
|
963
|
-
for (let i = 0; i < leadingOnes; i++) {
|
|
964
|
-
result[i] = 0;
|
|
965
|
-
}
|
|
966
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
967
|
-
result[leadingOnes + i] = bytes[i];
|
|
968
|
-
}
|
|
969
|
-
return result;
|
|
970
|
-
}
|
|
971
|
-
function ed25519PublicKeyToSolanaAddress(publicKey) {
|
|
972
|
-
if (!isValidHex(publicKey)) {
|
|
973
|
-
throw new ValidationError(
|
|
974
|
-
"publicKey must be a valid hex string with 0x prefix",
|
|
975
|
-
"publicKey"
|
|
976
|
-
);
|
|
977
|
-
}
|
|
978
|
-
if (!isValidEd25519PublicKey(publicKey)) {
|
|
979
|
-
throw new ValidationError(
|
|
980
|
-
"publicKey must be 32 bytes (64 hex characters)",
|
|
981
|
-
"publicKey"
|
|
982
|
-
);
|
|
983
|
-
}
|
|
984
|
-
const publicKeyBytes = hexToBytes(publicKey.slice(2));
|
|
985
|
-
return bytesToBase58(publicKeyBytes);
|
|
986
|
-
}
|
|
987
|
-
function isValidSolanaAddress(address) {
|
|
988
|
-
if (typeof address !== "string" || address.length === 0) {
|
|
989
|
-
return false;
|
|
990
|
-
}
|
|
991
|
-
if (address.length < 32 || address.length > 44) {
|
|
992
|
-
return false;
|
|
993
|
-
}
|
|
994
|
-
try {
|
|
995
|
-
const decoded = base58ToBytes(address);
|
|
996
|
-
return decoded.length === 32;
|
|
997
|
-
} catch {
|
|
998
|
-
return false;
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
function solanaAddressToEd25519PublicKey(address) {
|
|
1002
|
-
if (!isValidSolanaAddress(address)) {
|
|
1003
|
-
throw new ValidationError(
|
|
1004
|
-
"Invalid Solana address format",
|
|
1005
|
-
"address"
|
|
1006
|
-
);
|
|
1007
|
-
}
|
|
1008
|
-
const decoded = base58ToBytes(address);
|
|
1009
|
-
return `0x${bytesToHex(decoded)}`;
|
|
1010
|
-
}
|
|
1011
|
-
function ed25519PublicKeyToNearAddress(publicKey) {
|
|
1012
|
-
if (!isValidHex(publicKey)) {
|
|
1013
|
-
throw new ValidationError(
|
|
1014
|
-
"publicKey must be a valid hex string with 0x prefix",
|
|
1015
|
-
"publicKey"
|
|
1016
|
-
);
|
|
1017
|
-
}
|
|
1018
|
-
if (!isValidEd25519PublicKey(publicKey)) {
|
|
1019
|
-
throw new ValidationError(
|
|
1020
|
-
"publicKey must be 32 bytes (64 hex characters)",
|
|
1021
|
-
"publicKey"
|
|
1022
|
-
);
|
|
1023
|
-
}
|
|
1024
|
-
return publicKey.slice(2).toLowerCase();
|
|
1025
|
-
}
|
|
1026
|
-
function nearAddressToEd25519PublicKey(address) {
|
|
1027
|
-
if (!isValidNearImplicitAddress(address)) {
|
|
1028
|
-
throw new ValidationError(
|
|
1029
|
-
"Invalid NEAR implicit address format",
|
|
1030
|
-
"address"
|
|
1031
|
-
);
|
|
1032
|
-
}
|
|
1033
|
-
return `0x${address.toLowerCase()}`;
|
|
1034
|
-
}
|
|
1035
|
-
function isValidNearImplicitAddress(address) {
|
|
1036
|
-
if (typeof address !== "string" || address.length === 0) {
|
|
1037
|
-
return false;
|
|
1038
|
-
}
|
|
1039
|
-
if (address.length !== 64) {
|
|
1040
|
-
return false;
|
|
1041
|
-
}
|
|
1042
|
-
return /^[0-9a-f]{64}$/.test(address);
|
|
1043
|
-
}
|
|
1044
|
-
function isValidNearAccountId(accountId) {
|
|
1045
|
-
if (typeof accountId !== "string" || accountId.length === 0) {
|
|
1046
|
-
return false;
|
|
1047
|
-
}
|
|
1048
|
-
if (isValidNearImplicitAddress(accountId)) {
|
|
1049
|
-
return true;
|
|
1050
|
-
}
|
|
1051
|
-
if (accountId.length < 2 || accountId.length > 64) {
|
|
1052
|
-
return false;
|
|
1053
|
-
}
|
|
1054
|
-
const nearAccountPattern = /^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$/;
|
|
1055
|
-
if (!nearAccountPattern.test(accountId)) {
|
|
1056
|
-
return false;
|
|
1057
|
-
}
|
|
1058
|
-
if (accountId.includes("..")) {
|
|
1059
|
-
return false;
|
|
1060
|
-
}
|
|
1061
|
-
return true;
|
|
1062
|
-
}
|
|
2
|
+
ProofGenerationError
|
|
3
|
+
} from "./chunk-HOR7PM3M.mjs";
|
|
4
|
+
import {
|
|
5
|
+
checkEd25519StealthAddress,
|
|
6
|
+
checkStealthAddress,
|
|
7
|
+
decodeStealthMetaAddress,
|
|
8
|
+
deriveEd25519StealthPrivateKey,
|
|
9
|
+
deriveStealthPrivateKey,
|
|
10
|
+
ed25519PublicKeyToNearAddress,
|
|
11
|
+
ed25519PublicKeyToSolanaAddress,
|
|
12
|
+
encodeStealthMetaAddress,
|
|
13
|
+
estimatePrivateTransferFee,
|
|
14
|
+
generateEd25519StealthAddress,
|
|
15
|
+
generateStealthAddress,
|
|
16
|
+
generateStealthMetaAddress,
|
|
17
|
+
getChainAddressType,
|
|
18
|
+
isAddressValidForChain,
|
|
19
|
+
isEd25519Chain,
|
|
20
|
+
isValidAmount,
|
|
21
|
+
isValidChainId,
|
|
22
|
+
isValidEd25519PublicKey,
|
|
23
|
+
isValidHex,
|
|
24
|
+
isValidPrivacyLevel,
|
|
25
|
+
isValidPrivateKey,
|
|
26
|
+
isValidSlippage,
|
|
27
|
+
isValidStealthMetaAddress,
|
|
28
|
+
publicKeyToEthAddress,
|
|
29
|
+
secureWipe,
|
|
30
|
+
sendPrivateSPLTransfer,
|
|
31
|
+
validateCreateIntentParams
|
|
32
|
+
} from "./chunk-L2K34JCU.mjs";
|
|
33
|
+
import {
|
|
34
|
+
CryptoError,
|
|
35
|
+
IntentError,
|
|
36
|
+
NetworkError,
|
|
37
|
+
ProofError,
|
|
38
|
+
SIPError,
|
|
39
|
+
ValidationError
|
|
40
|
+
} from "./chunk-6WGN57S2.mjs";
|
|
41
|
+
|
|
42
|
+
// src/sip.ts
|
|
43
|
+
import {
|
|
44
|
+
PrivacyLevel as PrivacyLevel2,
|
|
45
|
+
IntentStatus as IntentStatus2,
|
|
46
|
+
OneClickSwapStatus as OneClickSwapStatus3
|
|
47
|
+
} from "@sip-protocol/types";
|
|
48
|
+
|
|
49
|
+
// src/intent.ts
|
|
50
|
+
import {
|
|
51
|
+
SIP_VERSION,
|
|
52
|
+
IntentStatus,
|
|
53
|
+
PrivacyLevel as PrivacyLevelEnum
|
|
54
|
+
} from "@sip-protocol/types";
|
|
1063
55
|
|
|
1064
56
|
// src/crypto.ts
|
|
1065
|
-
import { sha256 as
|
|
1066
|
-
import { bytesToHex as
|
|
57
|
+
import { sha256 as sha2562 } from "@noble/hashes/sha256";
|
|
58
|
+
import { bytesToHex as bytesToHex2, randomBytes as randomBytes2 } from "@noble/hashes/utils";
|
|
1067
59
|
|
|
1068
60
|
// src/commitment.ts
|
|
1069
|
-
import { secp256k1
|
|
1070
|
-
import { sha256
|
|
1071
|
-
import { bytesToHex
|
|
61
|
+
import { secp256k1 } from "@noble/curves/secp256k1";
|
|
62
|
+
import { sha256 } from "@noble/hashes/sha256";
|
|
63
|
+
import { bytesToHex, hexToBytes, randomBytes } from "@noble/hashes/utils";
|
|
1072
64
|
var H_DOMAIN = "SIP-PEDERSEN-GENERATOR-H-v1";
|
|
1073
|
-
var G =
|
|
65
|
+
var G = secp256k1.ProjectivePoint.BASE;
|
|
1074
66
|
var H = generateH();
|
|
1075
|
-
var CURVE_ORDER =
|
|
67
|
+
var CURVE_ORDER = secp256k1.CURVE.n;
|
|
1076
68
|
function generateH() {
|
|
1077
69
|
let counter = 0;
|
|
1078
70
|
while (counter < 256) {
|
|
1079
71
|
const input = new TextEncoder().encode(`${H_DOMAIN}:${counter}`);
|
|
1080
|
-
const hashBytes =
|
|
72
|
+
const hashBytes = sha256(input);
|
|
1081
73
|
try {
|
|
1082
74
|
const pointBytes = new Uint8Array(33);
|
|
1083
75
|
pointBytes[0] = 2;
|
|
1084
76
|
pointBytes.set(hashBytes, 1);
|
|
1085
|
-
const point =
|
|
1086
|
-
if (!point.equals(
|
|
77
|
+
const point = secp256k1.ProjectivePoint.fromHex(pointBytes);
|
|
78
|
+
if (!point.equals(secp256k1.ProjectivePoint.ZERO) && !point.equals(G)) {
|
|
1087
79
|
return point;
|
|
1088
80
|
}
|
|
1089
81
|
} catch {
|
|
@@ -1110,17 +102,17 @@ function commit(value, blinding) {
|
|
|
1110
102
|
{ curveOrder: CURVE_ORDER.toString(16) }
|
|
1111
103
|
);
|
|
1112
104
|
}
|
|
1113
|
-
const r = blinding ??
|
|
105
|
+
const r = blinding ?? randomBytes(32);
|
|
1114
106
|
if (r.length !== 32) {
|
|
1115
107
|
throw new ValidationError("must be 32 bytes", "blinding", { received: r.length });
|
|
1116
108
|
}
|
|
1117
|
-
const rScalar =
|
|
109
|
+
const rScalar = bytesToBigInt(r) % CURVE_ORDER;
|
|
1118
110
|
if (rScalar === 0n) {
|
|
1119
111
|
throw new Error("CRITICAL: Zero blinding scalar after reduction - investigate RNG");
|
|
1120
112
|
}
|
|
1121
113
|
let C;
|
|
1122
114
|
if (value === 0n && rScalar === 0n) {
|
|
1123
|
-
C =
|
|
115
|
+
C = secp256k1.ProjectivePoint.ZERO;
|
|
1124
116
|
} else if (value === 0n) {
|
|
1125
117
|
C = H.multiply(rScalar);
|
|
1126
118
|
} else if (rScalar === 0n) {
|
|
@@ -1131,8 +123,8 @@ function commit(value, blinding) {
|
|
|
1131
123
|
C = vG.add(rH);
|
|
1132
124
|
}
|
|
1133
125
|
return {
|
|
1134
|
-
commitment: `0x${
|
|
1135
|
-
blinding: `0x${
|
|
126
|
+
commitment: `0x${bytesToHex(C.toRawBytes(true))}`,
|
|
127
|
+
blinding: `0x${bytesToHex(r)}`
|
|
1136
128
|
};
|
|
1137
129
|
}
|
|
1138
130
|
function verifyOpening(commitment, value, blinding) {
|
|
@@ -1140,9 +132,9 @@ function verifyOpening(commitment, value, blinding) {
|
|
|
1140
132
|
if (commitment === "0x00") {
|
|
1141
133
|
return value === 0n && blinding === "0x" + "0".repeat(64);
|
|
1142
134
|
}
|
|
1143
|
-
const C =
|
|
1144
|
-
const blindingBytes =
|
|
1145
|
-
const rScalar =
|
|
135
|
+
const C = secp256k1.ProjectivePoint.fromHex(commitment.slice(2));
|
|
136
|
+
const blindingBytes = hexToBytes(blinding.slice(2));
|
|
137
|
+
const rScalar = bytesToBigInt(blindingBytes) % CURVE_ORDER;
|
|
1146
138
|
if (rScalar === 0n) {
|
|
1147
139
|
throw new Error("CRITICAL: Zero blinding scalar after reduction - investigate RNG");
|
|
1148
140
|
}
|
|
@@ -1174,18 +166,18 @@ function addCommitments(c1, c2) {
|
|
|
1174
166
|
let point1;
|
|
1175
167
|
let point2;
|
|
1176
168
|
try {
|
|
1177
|
-
point1 =
|
|
169
|
+
point1 = secp256k1.ProjectivePoint.fromHex(c1.slice(2));
|
|
1178
170
|
} catch {
|
|
1179
171
|
throw new ValidationError("must be a valid curve point", "c1");
|
|
1180
172
|
}
|
|
1181
173
|
try {
|
|
1182
|
-
point2 =
|
|
174
|
+
point2 = secp256k1.ProjectivePoint.fromHex(c2.slice(2));
|
|
1183
175
|
} catch {
|
|
1184
176
|
throw new ValidationError("must be a valid curve point", "c2");
|
|
1185
177
|
}
|
|
1186
178
|
const sum = point1.add(point2);
|
|
1187
179
|
return {
|
|
1188
|
-
commitment: `0x${
|
|
180
|
+
commitment: `0x${bytesToHex(sum.toRawBytes(true))}`
|
|
1189
181
|
};
|
|
1190
182
|
}
|
|
1191
183
|
function subtractCommitments(c1, c2) {
|
|
@@ -1198,38 +190,38 @@ function subtractCommitments(c1, c2) {
|
|
|
1198
190
|
let point1;
|
|
1199
191
|
let point2;
|
|
1200
192
|
try {
|
|
1201
|
-
point1 =
|
|
193
|
+
point1 = secp256k1.ProjectivePoint.fromHex(c1.slice(2));
|
|
1202
194
|
} catch {
|
|
1203
195
|
throw new ValidationError("must be a valid curve point", "c1");
|
|
1204
196
|
}
|
|
1205
197
|
try {
|
|
1206
|
-
point2 =
|
|
198
|
+
point2 = secp256k1.ProjectivePoint.fromHex(c2.slice(2));
|
|
1207
199
|
} catch {
|
|
1208
200
|
throw new ValidationError("must be a valid curve point", "c2");
|
|
1209
201
|
}
|
|
1210
202
|
const diff = point1.subtract(point2);
|
|
1211
|
-
if (diff.equals(
|
|
203
|
+
if (diff.equals(secp256k1.ProjectivePoint.ZERO)) {
|
|
1212
204
|
return {
|
|
1213
205
|
commitment: "0x00"
|
|
1214
206
|
};
|
|
1215
207
|
}
|
|
1216
208
|
return {
|
|
1217
|
-
commitment: `0x${
|
|
209
|
+
commitment: `0x${bytesToHex(diff.toRawBytes(true))}`
|
|
1218
210
|
};
|
|
1219
211
|
}
|
|
1220
212
|
function addBlindings(b1, b2) {
|
|
1221
|
-
const r1 =
|
|
1222
|
-
const r2 =
|
|
213
|
+
const r1 = bytesToBigInt(hexToBytes(b1.slice(2)));
|
|
214
|
+
const r2 = bytesToBigInt(hexToBytes(b2.slice(2)));
|
|
1223
215
|
const sum = (r1 + r2) % CURVE_ORDER;
|
|
1224
|
-
const sumBytes =
|
|
1225
|
-
return `0x${
|
|
216
|
+
const sumBytes = bigIntToBytes(sum, 32);
|
|
217
|
+
return `0x${bytesToHex(sumBytes)}`;
|
|
1226
218
|
}
|
|
1227
219
|
function subtractBlindings(b1, b2) {
|
|
1228
|
-
const r1 =
|
|
1229
|
-
const r2 =
|
|
220
|
+
const r1 = bytesToBigInt(hexToBytes(b1.slice(2)));
|
|
221
|
+
const r2 = bytesToBigInt(hexToBytes(b2.slice(2)));
|
|
1230
222
|
const diff = (r1 - r2 + CURVE_ORDER) % CURVE_ORDER;
|
|
1231
|
-
const diffBytes =
|
|
1232
|
-
return `0x${
|
|
223
|
+
const diffBytes = bigIntToBytes(diff, 32);
|
|
224
|
+
return `0x${bytesToHex(diffBytes)}`;
|
|
1233
225
|
}
|
|
1234
226
|
function getGenerators() {
|
|
1235
227
|
const gAffine = G.toAffine();
|
|
@@ -1246,16 +238,16 @@ function getGenerators() {
|
|
|
1246
238
|
};
|
|
1247
239
|
}
|
|
1248
240
|
function generateBlinding() {
|
|
1249
|
-
return `0x${
|
|
241
|
+
return `0x${bytesToHex(randomBytes(32))}`;
|
|
1250
242
|
}
|
|
1251
|
-
function
|
|
243
|
+
function bytesToBigInt(bytes) {
|
|
1252
244
|
let result = 0n;
|
|
1253
245
|
for (const byte of bytes) {
|
|
1254
246
|
result = (result << 8n) + BigInt(byte);
|
|
1255
247
|
}
|
|
1256
248
|
return result;
|
|
1257
249
|
}
|
|
1258
|
-
function
|
|
250
|
+
function bigIntToBytes(value, length) {
|
|
1259
251
|
const bytes = new Uint8Array(length);
|
|
1260
252
|
let v = value;
|
|
1261
253
|
for (let i = length - 1; i >= 0; i--) {
|
|
@@ -1291,27 +283,27 @@ function verifyCommitment(commitment, expectedValue) {
|
|
|
1291
283
|
return verifyOpening(commitment.value, expectedValue, commitment.blindingFactor);
|
|
1292
284
|
}
|
|
1293
285
|
function generateIntentId() {
|
|
1294
|
-
const bytes =
|
|
1295
|
-
return `sip-${
|
|
286
|
+
const bytes = randomBytes2(16);
|
|
287
|
+
return `sip-${bytesToHex2(bytes)}`;
|
|
1296
288
|
}
|
|
1297
289
|
function hash(data) {
|
|
1298
290
|
const input = typeof data === "string" ? new TextEncoder().encode(data) : data;
|
|
1299
|
-
return `0x${
|
|
291
|
+
return `0x${bytesToHex2(sha2562(input))}`;
|
|
1300
292
|
}
|
|
1301
293
|
function generateRandomBytes(length) {
|
|
1302
|
-
return `0x${
|
|
294
|
+
return `0x${bytesToHex2(randomBytes2(length))}`;
|
|
1303
295
|
}
|
|
1304
296
|
|
|
1305
297
|
// src/intent.ts
|
|
1306
|
-
import { hexToBytes as
|
|
1307
|
-
import { sha256 as
|
|
298
|
+
import { hexToBytes as hexToBytes3, bytesToHex as bytesToHex4, randomBytes as randomBytes4 } from "@noble/hashes/utils";
|
|
299
|
+
import { sha256 as sha2564 } from "@noble/hashes/sha256";
|
|
1308
300
|
|
|
1309
301
|
// src/privacy.ts
|
|
1310
|
-
import { sha256 as
|
|
1311
|
-
import { sha512
|
|
302
|
+
import { sha256 as sha2563 } from "@noble/hashes/sha256";
|
|
303
|
+
import { sha512 } from "@noble/hashes/sha512";
|
|
1312
304
|
import { hmac } from "@noble/hashes/hmac";
|
|
1313
305
|
import { hkdf } from "@noble/hashes/hkdf";
|
|
1314
|
-
import { bytesToHex as
|
|
306
|
+
import { bytesToHex as bytesToHex3, hexToBytes as hexToBytes2, randomBytes as randomBytes3, utf8ToBytes } from "@noble/hashes/utils";
|
|
1315
307
|
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
|
|
1316
308
|
var MAX_TRANSACTION_DATA_SIZE = 1024 * 1024;
|
|
1317
309
|
function getPrivacyConfig(level, viewingKey) {
|
|
@@ -1353,14 +345,14 @@ function getPrivacyConfig(level, viewingKey) {
|
|
|
1353
345
|
}
|
|
1354
346
|
}
|
|
1355
347
|
function generateViewingKey(path = "m/0") {
|
|
1356
|
-
const keyBytes =
|
|
348
|
+
const keyBytes = randomBytes3(32);
|
|
1357
349
|
try {
|
|
1358
|
-
const key = `0x${
|
|
1359
|
-
const hashBytes =
|
|
350
|
+
const key = `0x${bytesToHex3(keyBytes)}`;
|
|
351
|
+
const hashBytes = sha2563(keyBytes);
|
|
1360
352
|
return {
|
|
1361
353
|
key,
|
|
1362
354
|
path,
|
|
1363
|
-
hash: `0x${
|
|
355
|
+
hash: `0x${bytesToHex3(hashBytes)}`
|
|
1364
356
|
};
|
|
1365
357
|
} finally {
|
|
1366
358
|
secureWipe(keyBytes);
|
|
@@ -1368,17 +360,17 @@ function generateViewingKey(path = "m/0") {
|
|
|
1368
360
|
}
|
|
1369
361
|
function deriveViewingKey(masterKey, childPath) {
|
|
1370
362
|
const masterKeyHex = masterKey.key.startsWith("0x") ? masterKey.key.slice(2) : masterKey.key;
|
|
1371
|
-
const masterKeyBytes =
|
|
363
|
+
const masterKeyBytes = hexToBytes2(masterKeyHex);
|
|
1372
364
|
const childPathBytes = utf8ToBytes(childPath);
|
|
1373
|
-
const derivedFull = hmac(
|
|
365
|
+
const derivedFull = hmac(sha512, masterKeyBytes, childPathBytes);
|
|
1374
366
|
try {
|
|
1375
367
|
const derivedBytes = derivedFull.slice(0, 32);
|
|
1376
|
-
const derived = `0x${
|
|
1377
|
-
const hashBytes =
|
|
368
|
+
const derived = `0x${bytesToHex3(derivedBytes)}`;
|
|
369
|
+
const hashBytes = sha2563(derivedBytes);
|
|
1378
370
|
const result = {
|
|
1379
371
|
key: derived,
|
|
1380
372
|
path: `${masterKey.path}/${childPath}`,
|
|
1381
|
-
hash: `0x${
|
|
373
|
+
hash: `0x${bytesToHex3(hashBytes)}`
|
|
1382
374
|
};
|
|
1383
375
|
secureWipe(derivedBytes);
|
|
1384
376
|
return result;
|
|
@@ -1391,11 +383,11 @@ var ENCRYPTION_DOMAIN = "SIP-VIEWING-KEY-ENCRYPTION-V1";
|
|
|
1391
383
|
var NONCE_SIZE = 24;
|
|
1392
384
|
function deriveEncryptionKey(viewingKey) {
|
|
1393
385
|
const keyHex = viewingKey.key.startsWith("0x") ? viewingKey.key.slice(2) : viewingKey.key;
|
|
1394
|
-
const keyBytes =
|
|
386
|
+
const keyBytes = hexToBytes2(keyHex);
|
|
1395
387
|
try {
|
|
1396
388
|
const salt = utf8ToBytes(ENCRYPTION_DOMAIN);
|
|
1397
389
|
const info = utf8ToBytes(viewingKey.path);
|
|
1398
|
-
return hkdf(
|
|
390
|
+
return hkdf(sha2563, keyBytes, salt, info, 32);
|
|
1399
391
|
} finally {
|
|
1400
392
|
secureWipe(keyBytes);
|
|
1401
393
|
}
|
|
@@ -1403,13 +395,13 @@ function deriveEncryptionKey(viewingKey) {
|
|
|
1403
395
|
function encryptForViewing(data, viewingKey) {
|
|
1404
396
|
const key = deriveEncryptionKey(viewingKey);
|
|
1405
397
|
try {
|
|
1406
|
-
const nonce =
|
|
398
|
+
const nonce = randomBytes3(NONCE_SIZE);
|
|
1407
399
|
const plaintext = utf8ToBytes(JSON.stringify(data));
|
|
1408
400
|
const cipher = xchacha20poly1305(key, nonce);
|
|
1409
401
|
const ciphertext = cipher.encrypt(plaintext);
|
|
1410
402
|
return {
|
|
1411
|
-
ciphertext: `0x${
|
|
1412
|
-
nonce: `0x${
|
|
403
|
+
ciphertext: `0x${bytesToHex3(ciphertext)}`,
|
|
404
|
+
nonce: `0x${bytesToHex3(nonce)}`,
|
|
1413
405
|
viewingKeyHash: viewingKey.hash
|
|
1414
406
|
};
|
|
1415
407
|
} finally {
|
|
@@ -1427,9 +419,9 @@ function decryptWithViewing(encrypted, viewingKey) {
|
|
|
1427
419
|
const key = deriveEncryptionKey(viewingKey);
|
|
1428
420
|
try {
|
|
1429
421
|
const nonceHex = encrypted.nonce.startsWith("0x") ? encrypted.nonce.slice(2) : encrypted.nonce;
|
|
1430
|
-
const nonce =
|
|
422
|
+
const nonce = hexToBytes2(nonceHex);
|
|
1431
423
|
const ciphertextHex = encrypted.ciphertext.startsWith("0x") ? encrypted.ciphertext.slice(2) : encrypted.ciphertext;
|
|
1432
|
-
const ciphertext =
|
|
424
|
+
const ciphertext = hexToBytes2(ciphertextHex);
|
|
1433
425
|
const cipher = xchacha20poly1305(key, nonce);
|
|
1434
426
|
let plaintext;
|
|
1435
427
|
try {
|
|
@@ -1724,8 +716,8 @@ async function createShieldedIntent(params, options) {
|
|
|
1724
716
|
let viewingKeyHash;
|
|
1725
717
|
if (viewingKey) {
|
|
1726
718
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
1727
|
-
const keyBytes =
|
|
1728
|
-
viewingKeyHash = `0x${
|
|
719
|
+
const keyBytes = hexToBytes3(keyHex);
|
|
720
|
+
viewingKeyHash = `0x${bytesToHex4(sha2564(keyBytes))}`;
|
|
1729
721
|
}
|
|
1730
722
|
const privacyConfig = getPrivacyConfig(
|
|
1731
723
|
privacy,
|
|
@@ -1771,10 +763,16 @@ async function createShieldedIntent(params, options) {
|
|
|
1771
763
|
}
|
|
1772
764
|
const hexToUint8 = (hex) => {
|
|
1773
765
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
1774
|
-
return
|
|
766
|
+
return hexToBytes3(cleanHex);
|
|
1775
767
|
};
|
|
1776
|
-
|
|
1777
|
-
|
|
768
|
+
if (allowPlaceholders && typeof process !== "undefined" && process.env?.NODE_ENV === "production") {
|
|
769
|
+
throw new ValidationError(
|
|
770
|
+
"allowPlaceholders cannot be used in production environment. Provide valid senderSecret and signatures for production use.",
|
|
771
|
+
"options.allowPlaceholders"
|
|
772
|
+
);
|
|
773
|
+
}
|
|
774
|
+
const effectiveSenderSecret = senderSecret ?? randomBytes4(32);
|
|
775
|
+
const rawIntentHashBytes = sha2564(new TextEncoder().encode(intentId));
|
|
1778
776
|
const intentHashHex = hash(intentId);
|
|
1779
777
|
const BN254_MODULUS = 21888242871839275222246405745257275088548364400416034343698204186575808495617n;
|
|
1780
778
|
let hashValue = 0n;
|
|
@@ -1794,18 +792,18 @@ async function createShieldedIntent(params, options) {
|
|
|
1794
792
|
effectiveOwnershipSig = ownershipSignature;
|
|
1795
793
|
effectiveAuthSig = authorizationSignature;
|
|
1796
794
|
} else if (allowPlaceholders && !senderSecret) {
|
|
1797
|
-
effectiveOwnershipSig =
|
|
1798
|
-
effectiveAuthSig =
|
|
795
|
+
effectiveOwnershipSig = randomBytes4(64);
|
|
796
|
+
effectiveAuthSig = randomBytes4(64);
|
|
1799
797
|
console.warn(
|
|
1800
798
|
"[createShieldedIntent] WARNING: Using placeholder signatures for proof generation. These proofs are NOT cryptographically valid. Do NOT use in production!"
|
|
1801
799
|
);
|
|
1802
800
|
} else {
|
|
1803
|
-
const { secp256k1:
|
|
1804
|
-
const publicKey =
|
|
1805
|
-
const senderAddressBytes =
|
|
1806
|
-
const ownershipSig =
|
|
801
|
+
const { secp256k1: secp256k18 } = await import("@noble/curves/secp256k1");
|
|
802
|
+
const publicKey = secp256k18.getPublicKey(effectiveSenderSecret, true);
|
|
803
|
+
const senderAddressBytes = sha2564(publicKey);
|
|
804
|
+
const ownershipSig = secp256k18.sign(senderAddressBytes, effectiveSenderSecret);
|
|
1807
805
|
effectiveOwnershipSig = ownershipSig.toCompactRawBytes();
|
|
1808
|
-
const authSig =
|
|
806
|
+
const authSig = secp256k18.sign(intentHashBytes, effectiveSenderSecret);
|
|
1809
807
|
effectiveAuthSig = authSig.toCompactRawBytes();
|
|
1810
808
|
}
|
|
1811
809
|
const fundingResult = await proofProvider.generateFundingProof({
|
|
@@ -1824,7 +822,7 @@ async function createShieldedIntent(params, options) {
|
|
|
1824
822
|
senderBlinding: hexToUint8(senderCommitment.blindingFactor),
|
|
1825
823
|
senderSecret: effectiveSenderSecret,
|
|
1826
824
|
authorizationSignature: effectiveAuthSig,
|
|
1827
|
-
nonce:
|
|
825
|
+
nonce: randomBytes4(32),
|
|
1828
826
|
timestamp: now,
|
|
1829
827
|
expiry: now + ttl
|
|
1830
828
|
});
|
|
@@ -1986,7 +984,7 @@ var OneClickClient = class {
|
|
|
1986
984
|
*
|
|
1987
985
|
* @param depositAddress - Deposit address from quote
|
|
1988
986
|
* @param depositMemo - Optional memo for memo-based deposits
|
|
1989
|
-
* @returns Current swap status
|
|
987
|
+
* @returns Current swap status with normalized transaction hashes
|
|
1990
988
|
*/
|
|
1991
989
|
async getStatus(depositAddress, depositMemo) {
|
|
1992
990
|
if (!depositAddress) {
|
|
@@ -1996,7 +994,14 @@ var OneClickClient = class {
|
|
|
1996
994
|
if (depositMemo) {
|
|
1997
995
|
params.set("depositMemo", depositMemo);
|
|
1998
996
|
}
|
|
1999
|
-
|
|
997
|
+
const rawStatus = await this.get(`/v0/status?${params.toString()}`);
|
|
998
|
+
const settlementTxHash = rawStatus.settlementTxHash ?? rawStatus.swapDetails?.destinationChainTxHashes?.[0]?.hash ?? rawStatus.destinationChainTxHashes?.[0]?.hash;
|
|
999
|
+
const depositTxHash = rawStatus.depositTxHash ?? rawStatus.swapDetails?.originChainTxHashes?.[0]?.hash ?? rawStatus.originChainTxHashes?.[0]?.hash;
|
|
1000
|
+
return {
|
|
1001
|
+
...rawStatus,
|
|
1002
|
+
settlementTxHash,
|
|
1003
|
+
depositTxHash
|
|
1004
|
+
};
|
|
2000
1005
|
}
|
|
2001
1006
|
/**
|
|
2002
1007
|
* Poll status until terminal state or timeout
|
|
@@ -2194,7 +1199,7 @@ import {
|
|
|
2194
1199
|
|
|
2195
1200
|
// src/move/aptos.ts
|
|
2196
1201
|
import { sha3_256 } from "@noble/hashes/sha3";
|
|
2197
|
-
import { bytesToHex as
|
|
1202
|
+
import { bytesToHex as bytesToHex5, hexToBytes as hexToBytes4 } from "@noble/hashes/utils";
|
|
2198
1203
|
var APTOS_SINGLE_ED25519_SCHEME = 0;
|
|
2199
1204
|
function ed25519PublicKeyToAptosAddress(publicKey) {
|
|
2200
1205
|
if (!isValidHex(publicKey)) {
|
|
@@ -2209,12 +1214,12 @@ function ed25519PublicKeyToAptosAddress(publicKey) {
|
|
|
2209
1214
|
"publicKey"
|
|
2210
1215
|
);
|
|
2211
1216
|
}
|
|
2212
|
-
const publicKeyBytes =
|
|
1217
|
+
const publicKeyBytes = hexToBytes4(publicKey.slice(2));
|
|
2213
1218
|
const authKeyInput = new Uint8Array(publicKeyBytes.length + 1);
|
|
2214
1219
|
authKeyInput.set(publicKeyBytes, 0);
|
|
2215
1220
|
authKeyInput[publicKeyBytes.length] = APTOS_SINGLE_ED25519_SCHEME;
|
|
2216
1221
|
const addressHash = sha3_256(authKeyInput);
|
|
2217
|
-
return `0x${
|
|
1222
|
+
return `0x${bytesToHex5(addressHash)}`;
|
|
2218
1223
|
}
|
|
2219
1224
|
function isValidAptosAddress(address) {
|
|
2220
1225
|
if (typeof address !== "string" || address.length === 0) {
|
|
@@ -2328,7 +1333,7 @@ var AptosStealthService = class {
|
|
|
2328
1333
|
|
|
2329
1334
|
// src/move/sui.ts
|
|
2330
1335
|
import { BLAKE2b } from "@noble/hashes/blake2b";
|
|
2331
|
-
import { bytesToHex as
|
|
1336
|
+
import { bytesToHex as bytesToHex6, hexToBytes as hexToBytes5 } from "@noble/hashes/utils";
|
|
2332
1337
|
var SUI_ED25519_SCHEME = 0;
|
|
2333
1338
|
function ed25519PublicKeyToSuiAddress(publicKey) {
|
|
2334
1339
|
if (!isValidHex(publicKey)) {
|
|
@@ -2343,14 +1348,14 @@ function ed25519PublicKeyToSuiAddress(publicKey) {
|
|
|
2343
1348
|
"publicKey"
|
|
2344
1349
|
);
|
|
2345
1350
|
}
|
|
2346
|
-
const publicKeyBytes =
|
|
1351
|
+
const publicKeyBytes = hexToBytes5(publicKey.slice(2));
|
|
2347
1352
|
const addressInput = new Uint8Array(publicKeyBytes.length + 1);
|
|
2348
1353
|
addressInput[0] = SUI_ED25519_SCHEME;
|
|
2349
1354
|
addressInput.set(publicKeyBytes, 1);
|
|
2350
1355
|
const hasher = new BLAKE2b({ dkLen: 32 });
|
|
2351
1356
|
hasher.update(addressInput);
|
|
2352
1357
|
const addressHash = hasher.digest();
|
|
2353
|
-
return `0x${
|
|
1358
|
+
return `0x${bytesToHex6(addressHash)}`;
|
|
2354
1359
|
}
|
|
2355
1360
|
function isValidSuiAddress(address) {
|
|
2356
1361
|
if (typeof address !== "string" || address.length === 0) {
|
|
@@ -3323,6 +2328,80 @@ var SIP = class {
|
|
|
3323
2328
|
fulfilledAt: Math.floor(Date.now() / 1e3)
|
|
3324
2329
|
};
|
|
3325
2330
|
}
|
|
2331
|
+
// ─── Same-Chain Privacy ───────────────────────────────────────────────────
|
|
2332
|
+
/**
|
|
2333
|
+
* Execute a same-chain private transfer
|
|
2334
|
+
*
|
|
2335
|
+
* Bypasses cross-chain settlement for direct on-chain privacy transfers.
|
|
2336
|
+
* Currently supports Solana only.
|
|
2337
|
+
*
|
|
2338
|
+
* @param chain - Chain to execute on (must be 'solana')
|
|
2339
|
+
* @param params - Transfer parameters
|
|
2340
|
+
* @returns Transfer result with stealth address
|
|
2341
|
+
*
|
|
2342
|
+
* @example
|
|
2343
|
+
* ```typescript
|
|
2344
|
+
* const result = await sip.executeSameChain('solana', {
|
|
2345
|
+
* recipientMetaAddress: {
|
|
2346
|
+
* chain: 'solana',
|
|
2347
|
+
* spendingKey: '0x...',
|
|
2348
|
+
* viewingKey: '0x...',
|
|
2349
|
+
* },
|
|
2350
|
+
* amount: 5_000_000n, // 5 USDC
|
|
2351
|
+
* token: 'USDC',
|
|
2352
|
+
* connection,
|
|
2353
|
+
* sender: wallet.publicKey,
|
|
2354
|
+
* signTransaction: wallet.signTransaction,
|
|
2355
|
+
* })
|
|
2356
|
+
*
|
|
2357
|
+
* console.log('Sent to stealth:', result.stealthAddress)
|
|
2358
|
+
* ```
|
|
2359
|
+
*/
|
|
2360
|
+
async executeSameChain(chain, params) {
|
|
2361
|
+
if (chain !== "solana") {
|
|
2362
|
+
throw new ValidationError(
|
|
2363
|
+
`Same-chain privacy only supported for 'solana', got '${chain}'`,
|
|
2364
|
+
"chain"
|
|
2365
|
+
);
|
|
2366
|
+
}
|
|
2367
|
+
const { sendPrivateSPLTransfer: sendPrivateSPLTransfer2 } = await import("./solana-Q4NAVBTS.mjs");
|
|
2368
|
+
const { PublicKey: SolanaPublicKey } = await import("@solana/web3.js");
|
|
2369
|
+
const { getAssociatedTokenAddress } = await import("@solana/spl-token");
|
|
2370
|
+
const { SOLANA_TOKEN_MINTS: SOLANA_TOKEN_MINTS2 } = await import("./constants-VOI7BSLK.mjs");
|
|
2371
|
+
let mint;
|
|
2372
|
+
if (params.token in SOLANA_TOKEN_MINTS2) {
|
|
2373
|
+
mint = new SolanaPublicKey(SOLANA_TOKEN_MINTS2[params.token]);
|
|
2374
|
+
} else {
|
|
2375
|
+
mint = new SolanaPublicKey(params.token);
|
|
2376
|
+
}
|
|
2377
|
+
const senderTokenAccount = await getAssociatedTokenAddress(
|
|
2378
|
+
mint,
|
|
2379
|
+
params.sender
|
|
2380
|
+
);
|
|
2381
|
+
const result = await sendPrivateSPLTransfer2({
|
|
2382
|
+
connection: params.connection,
|
|
2383
|
+
sender: params.sender,
|
|
2384
|
+
senderTokenAccount,
|
|
2385
|
+
recipientMetaAddress: params.recipientMetaAddress,
|
|
2386
|
+
mint,
|
|
2387
|
+
amount: params.amount,
|
|
2388
|
+
signTransaction: params.signTransaction
|
|
2389
|
+
});
|
|
2390
|
+
return {
|
|
2391
|
+
txHash: result.txSignature,
|
|
2392
|
+
stealthAddress: result.stealthAddress,
|
|
2393
|
+
ephemeralPublicKey: result.ephemeralPublicKey,
|
|
2394
|
+
viewTag: result.viewTag,
|
|
2395
|
+
explorerUrl: result.explorerUrl,
|
|
2396
|
+
chain: "solana"
|
|
2397
|
+
};
|
|
2398
|
+
}
|
|
2399
|
+
/**
|
|
2400
|
+
* Check if same-chain privacy is supported for a chain
|
|
2401
|
+
*/
|
|
2402
|
+
isSameChainSupported(chain) {
|
|
2403
|
+
return chain === "solana";
|
|
2404
|
+
}
|
|
3326
2405
|
};
|
|
3327
2406
|
function createSIP(network = "testnet") {
|
|
3328
2407
|
return new SIP({ network });
|
|
@@ -3339,9 +2418,9 @@ function createProductionSIP(config) {
|
|
|
3339
2418
|
}
|
|
3340
2419
|
|
|
3341
2420
|
// src/cosmos/stealth.ts
|
|
3342
|
-
import { sha256 as
|
|
2421
|
+
import { sha256 as sha2565 } from "@noble/hashes/sha256";
|
|
3343
2422
|
import { ripemd160 } from "@noble/hashes/ripemd160";
|
|
3344
|
-
import { hexToBytes as
|
|
2423
|
+
import { hexToBytes as hexToBytes6, bytesToHex as bytesToHex7 } from "@noble/hashes/utils";
|
|
3345
2424
|
import { bech32 } from "@scure/base";
|
|
3346
2425
|
var CHAIN_PREFIXES = {
|
|
3347
2426
|
cosmos: "cosmos",
|
|
@@ -3423,14 +2502,14 @@ var CosmosStealthService = class {
|
|
|
3423
2502
|
);
|
|
3424
2503
|
}
|
|
3425
2504
|
const metaAddress = {
|
|
3426
|
-
spendingKey: `0x${
|
|
3427
|
-
viewingKey: `0x${
|
|
2505
|
+
spendingKey: `0x${bytesToHex7(spendingPubKey)}`,
|
|
2506
|
+
viewingKey: `0x${bytesToHex7(viewingPubKey)}`,
|
|
3428
2507
|
chain: "ethereum"
|
|
3429
2508
|
// Use ethereum for secp256k1 generation
|
|
3430
2509
|
};
|
|
3431
2510
|
const { stealthAddress, sharedSecret } = generateStealthAddress(metaAddress);
|
|
3432
2511
|
const cosmosAddress = this.stealthKeyToCosmosAddress(
|
|
3433
|
-
|
|
2512
|
+
hexToBytes6(stealthAddress.address.slice(2)),
|
|
3434
2513
|
CHAIN_PREFIXES[chain]
|
|
3435
2514
|
);
|
|
3436
2515
|
return {
|
|
@@ -3458,8 +2537,8 @@ var CosmosStealthService = class {
|
|
|
3458
2537
|
* ```
|
|
3459
2538
|
*/
|
|
3460
2539
|
generateStealthAddressFromMeta(recipientMetaAddress, chain) {
|
|
3461
|
-
const spendingPubKey =
|
|
3462
|
-
const viewingPubKey =
|
|
2540
|
+
const spendingPubKey = hexToBytes6(recipientMetaAddress.spendingKey.slice(2));
|
|
2541
|
+
const viewingPubKey = hexToBytes6(recipientMetaAddress.viewingKey.slice(2));
|
|
3463
2542
|
return this.generateStealthAddress(spendingPubKey, viewingPubKey, chain);
|
|
3464
2543
|
}
|
|
3465
2544
|
/**
|
|
@@ -3489,7 +2568,7 @@ var CosmosStealthService = class {
|
|
|
3489
2568
|
"publicKey"
|
|
3490
2569
|
);
|
|
3491
2570
|
}
|
|
3492
|
-
const sha256Hash =
|
|
2571
|
+
const sha256Hash = sha2565(publicKey);
|
|
3493
2572
|
const hash160 = ripemd160(sha256Hash);
|
|
3494
2573
|
const words = bech32.toWords(hash160);
|
|
3495
2574
|
return bech32.encode(prefix, words);
|
|
@@ -3637,13 +2716,13 @@ function isValidCosmosAddress(address, expectedChain) {
|
|
|
3637
2716
|
}
|
|
3638
2717
|
|
|
3639
2718
|
// src/cosmos/ibc-stealth.ts
|
|
3640
|
-
import { hexToBytes as
|
|
3641
|
-
import { secp256k1 as
|
|
3642
|
-
import { sha256 as
|
|
2719
|
+
import { hexToBytes as hexToBytes7, bytesToHex as bytesToHex8 } from "@noble/hashes/utils";
|
|
2720
|
+
import { secp256k1 as secp256k12 } from "@noble/curves/secp256k1";
|
|
2721
|
+
import { sha256 as sha2566 } from "@noble/hashes/sha256";
|
|
3643
2722
|
|
|
3644
2723
|
// src/proofs/mock.ts
|
|
3645
|
-
import { sha256 as
|
|
3646
|
-
import { bytesToHex as
|
|
2724
|
+
import { sha256 as sha2567 } from "@noble/hashes/sha256";
|
|
2725
|
+
import { bytesToHex as bytesToHex9, randomBytes as randomBytes5 } from "@noble/hashes/utils";
|
|
3647
2726
|
var MOCK_PROOF_PREFIX = "0x4d4f434b";
|
|
3648
2727
|
var WARNING_MESSAGE = `
|
|
3649
2728
|
\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2557
|
|
@@ -3808,17 +2887,17 @@ var MockProofProvider = class {
|
|
|
3808
2887
|
{ type: proofType, params },
|
|
3809
2888
|
(_, v) => typeof v === "bigint" ? v.toString() : v
|
|
3810
2889
|
);
|
|
3811
|
-
const hash2 =
|
|
3812
|
-
const random =
|
|
2890
|
+
const hash2 = sha2567(new TextEncoder().encode(input));
|
|
2891
|
+
const random = randomBytes5(16);
|
|
3813
2892
|
const combined = new Uint8Array(4 + hash2.length + random.length);
|
|
3814
2893
|
combined.set(new TextEncoder().encode("MOCK"), 0);
|
|
3815
2894
|
combined.set(hash2, 4);
|
|
3816
2895
|
combined.set(random, 4 + hash2.length);
|
|
3817
|
-
return `${MOCK_PROOF_PREFIX}${
|
|
2896
|
+
return `${MOCK_PROOF_PREFIX}${bytesToHex9(combined.slice(4))}`;
|
|
3818
2897
|
}
|
|
3819
2898
|
hashToHex(data) {
|
|
3820
|
-
const hash2 =
|
|
3821
|
-
return `0x${
|
|
2899
|
+
const hash2 = sha2567(new TextEncoder().encode(data));
|
|
2900
|
+
return `0x${bytesToHex9(hash2)}`;
|
|
3822
2901
|
}
|
|
3823
2902
|
};
|
|
3824
2903
|
|
|
@@ -4091,7 +3170,7 @@ function checkMobileWASMCompatibility() {
|
|
|
4091
3170
|
recommendations
|
|
4092
3171
|
};
|
|
4093
3172
|
}
|
|
4094
|
-
function
|
|
3173
|
+
function hexToBytes8(hex) {
|
|
4095
3174
|
const h = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
4096
3175
|
if (h.length === 0) return new Uint8Array(0);
|
|
4097
3176
|
if (h.length % 2 !== 0) {
|
|
@@ -4103,7 +3182,7 @@ function hexToBytes9(hex) {
|
|
|
4103
3182
|
}
|
|
4104
3183
|
return bytes;
|
|
4105
3184
|
}
|
|
4106
|
-
function
|
|
3185
|
+
function bytesToHex10(bytes) {
|
|
4107
3186
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
4108
3187
|
}
|
|
4109
3188
|
function isBrowser() {
|
|
@@ -4166,13 +3245,13 @@ var CHAIN_NUMERIC_IDS = {
|
|
|
4166
3245
|
};
|
|
4167
3246
|
|
|
4168
3247
|
// src/oracle/verification.ts
|
|
4169
|
-
import { ed25519
|
|
4170
|
-
import { sha256 as
|
|
4171
|
-
import { bytesToHex as
|
|
3248
|
+
import { ed25519 } from "@noble/curves/ed25519";
|
|
3249
|
+
import { sha256 as sha2569 } from "@noble/hashes/sha256";
|
|
3250
|
+
import { bytesToHex as bytesToHex12, hexToBytes as hexToBytes10 } from "@noble/hashes/utils";
|
|
4172
3251
|
|
|
4173
3252
|
// src/oracle/serialization.ts
|
|
4174
|
-
import { sha256 as
|
|
4175
|
-
import { bytesToHex as
|
|
3253
|
+
import { sha256 as sha2568 } from "@noble/hashes/sha256";
|
|
3254
|
+
import { bytesToHex as bytesToHex11, hexToBytes as hexToBytes9, utf8ToBytes as utf8ToBytes2 } from "@noble/hashes/utils";
|
|
4176
3255
|
function serializeAttestationMessage(message) {
|
|
4177
3256
|
const buffer = new Uint8Array(197);
|
|
4178
3257
|
const view = new DataView(buffer.buffer);
|
|
@@ -4215,19 +3294,19 @@ function deserializeAttestationMessage(bytes) {
|
|
|
4215
3294
|
const version = bytes[offset++];
|
|
4216
3295
|
const chainId = view.getUint32(offset, false);
|
|
4217
3296
|
offset += 4;
|
|
4218
|
-
const intentHash = `0x${
|
|
3297
|
+
const intentHash = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4219
3298
|
offset += 32;
|
|
4220
|
-
const recipient = `0x${
|
|
3299
|
+
const recipient = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4221
3300
|
offset += 32;
|
|
4222
3301
|
const amount = bytesToBigint(bytes.slice(offset, offset + 16));
|
|
4223
3302
|
offset += 16;
|
|
4224
|
-
const assetId = `0x${
|
|
3303
|
+
const assetId = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4225
3304
|
offset += 32;
|
|
4226
|
-
const txHash = `0x${
|
|
3305
|
+
const txHash = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4227
3306
|
offset += 32;
|
|
4228
3307
|
const blockNumber = view.getBigUint64(offset, false);
|
|
4229
3308
|
offset += 8;
|
|
4230
|
-
const blockHash = `0x${
|
|
3309
|
+
const blockHash = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4231
3310
|
offset += 32;
|
|
4232
3311
|
const timestamp = Number(view.getBigUint64(offset, false));
|
|
4233
3312
|
return {
|
|
@@ -4249,7 +3328,7 @@ function computeAttestationHash(message) {
|
|
|
4249
3328
|
const toHash = new Uint8Array(domain.length + messageBytes.length);
|
|
4250
3329
|
toHash.set(domain, 0);
|
|
4251
3330
|
toHash.set(messageBytes, domain.length);
|
|
4252
|
-
return
|
|
3331
|
+
return sha2568(toHash);
|
|
4253
3332
|
}
|
|
4254
3333
|
function getChainNumericId(chain) {
|
|
4255
3334
|
const id = CHAIN_NUMERIC_IDS[chain];
|
|
@@ -4260,7 +3339,7 @@ function getChainNumericId(chain) {
|
|
|
4260
3339
|
}
|
|
4261
3340
|
function normalizeToBytes(hex, length, field) {
|
|
4262
3341
|
const stripped = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
4263
|
-
const bytes =
|
|
3342
|
+
const bytes = hexToBytes9(stripped);
|
|
4264
3343
|
if (bytes.length === length) {
|
|
4265
3344
|
return bytes;
|
|
4266
3345
|
}
|
|
@@ -4293,9 +3372,9 @@ function bytesToBigint(bytes) {
|
|
|
4293
3372
|
|
|
4294
3373
|
// src/oracle/verification.ts
|
|
4295
3374
|
function deriveOracleId(publicKey) {
|
|
4296
|
-
const keyBytes = typeof publicKey === "string" ?
|
|
4297
|
-
const hash2 =
|
|
4298
|
-
return `0x${
|
|
3375
|
+
const keyBytes = typeof publicKey === "string" ? hexToBytes10(publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey) : publicKey;
|
|
3376
|
+
const hash2 = sha2569(keyBytes);
|
|
3377
|
+
return `0x${bytesToHex12(hash2)}`;
|
|
4299
3378
|
}
|
|
4300
3379
|
function verifyAttestation(attestation, registry) {
|
|
4301
3380
|
const { message, signatures } = attestation;
|
|
@@ -4325,13 +3404,13 @@ function verifyAttestation(attestation, registry) {
|
|
|
4325
3404
|
continue;
|
|
4326
3405
|
}
|
|
4327
3406
|
try {
|
|
4328
|
-
const publicKeyBytes =
|
|
3407
|
+
const publicKeyBytes = hexToBytes10(
|
|
4329
3408
|
oracle.publicKey.startsWith("0x") ? oracle.publicKey.slice(2) : oracle.publicKey
|
|
4330
3409
|
);
|
|
4331
|
-
const signatureBytes =
|
|
3410
|
+
const signatureBytes = hexToBytes10(
|
|
4332
3411
|
sig.signature.startsWith("0x") ? sig.signature.slice(2) : sig.signature
|
|
4333
3412
|
);
|
|
4334
|
-
const isValid =
|
|
3413
|
+
const isValid = ed25519.verify(signatureBytes, messageHash, publicKeyBytes);
|
|
4335
3414
|
if (isValid) {
|
|
4336
3415
|
validCount++;
|
|
4337
3416
|
validOracles.push(sig.oracleId);
|
|
@@ -4353,24 +3432,24 @@ function verifyAttestation(attestation, registry) {
|
|
|
4353
3432
|
}
|
|
4354
3433
|
function verifyOracleSignature(signature, messageHash, oracle) {
|
|
4355
3434
|
try {
|
|
4356
|
-
const publicKeyBytes =
|
|
3435
|
+
const publicKeyBytes = hexToBytes10(
|
|
4357
3436
|
oracle.publicKey.startsWith("0x") ? oracle.publicKey.slice(2) : oracle.publicKey
|
|
4358
3437
|
);
|
|
4359
|
-
const signatureBytes =
|
|
3438
|
+
const signatureBytes = hexToBytes10(
|
|
4360
3439
|
signature.signature.startsWith("0x") ? signature.signature.slice(2) : signature.signature
|
|
4361
3440
|
);
|
|
4362
|
-
return
|
|
3441
|
+
return ed25519.verify(signatureBytes, messageHash, publicKeyBytes);
|
|
4363
3442
|
} catch {
|
|
4364
3443
|
return false;
|
|
4365
3444
|
}
|
|
4366
3445
|
}
|
|
4367
3446
|
function signAttestationMessage(messageHash, privateKey) {
|
|
4368
|
-
const signature =
|
|
4369
|
-
const publicKey =
|
|
3447
|
+
const signature = ed25519.sign(messageHash, privateKey);
|
|
3448
|
+
const publicKey = ed25519.getPublicKey(privateKey);
|
|
4370
3449
|
const oracleId = deriveOracleId(publicKey);
|
|
4371
3450
|
return {
|
|
4372
3451
|
oracleId,
|
|
4373
|
-
signature: `0x${
|
|
3452
|
+
signature: `0x${bytesToHex12(signature)}`
|
|
4374
3453
|
};
|
|
4375
3454
|
}
|
|
4376
3455
|
function createOracleRegistry(config = {}) {
|
|
@@ -4438,7 +3517,7 @@ import { ReportStatus as ReportStatus2 } from "@sip-protocol/types";
|
|
|
4438
3517
|
import {
|
|
4439
3518
|
IntentStatus as IntentStatus3
|
|
4440
3519
|
} from "@sip-protocol/types";
|
|
4441
|
-
import { bytesToHex as
|
|
3520
|
+
import { bytesToHex as bytesToHex13, randomBytes as randomBytes6 } from "@noble/hashes/utils";
|
|
4442
3521
|
var MockSolver = class {
|
|
4443
3522
|
info;
|
|
4444
3523
|
capabilities;
|
|
@@ -4520,7 +3599,7 @@ var MockSolver = class {
|
|
|
4520
3599
|
const spreadAmount = baseOutput * BigInt(Math.floor(this.spreadPercent * 1e4)) / 10000n;
|
|
4521
3600
|
const outputAmount = baseOutput + spreadAmount;
|
|
4522
3601
|
const feeAmount = outputAmount * BigInt(Math.floor(this.feePercent * 1e4)) / 10000n;
|
|
4523
|
-
const quoteId = `quote-${
|
|
3602
|
+
const quoteId = `quote-${bytesToHex13(randomBytes6(8))}`;
|
|
4524
3603
|
const now = Math.floor(Date.now() / 1e3);
|
|
4525
3604
|
const quote = {
|
|
4526
3605
|
quoteId,
|
|
@@ -4531,7 +3610,7 @@ var MockSolver = class {
|
|
|
4531
3610
|
expiry: now + 60,
|
|
4532
3611
|
// Quote valid for 1 minute
|
|
4533
3612
|
fee: feeAmount,
|
|
4534
|
-
signature: `0x${
|
|
3613
|
+
signature: `0x${bytesToHex13(randomBytes6(64))}`,
|
|
4535
3614
|
// Mock signature
|
|
4536
3615
|
validUntil: now + 60,
|
|
4537
3616
|
estimatedGas: 200000n
|
|
@@ -4568,7 +3647,7 @@ var MockSolver = class {
|
|
|
4568
3647
|
error: status.error
|
|
4569
3648
|
};
|
|
4570
3649
|
}
|
|
4571
|
-
const txHash = `0x${
|
|
3650
|
+
const txHash = `0x${bytesToHex13(randomBytes6(32))}`;
|
|
4572
3651
|
status.status = "completed";
|
|
4573
3652
|
status.txHash = txHash;
|
|
4574
3653
|
return {
|
|
@@ -4578,10 +3657,10 @@ var MockSolver = class {
|
|
|
4578
3657
|
txHash: intent.privacyLevel === "transparent" ? txHash : void 0,
|
|
4579
3658
|
fulfillmentProof: {
|
|
4580
3659
|
type: "fulfillment",
|
|
4581
|
-
proof: `0x${
|
|
3660
|
+
proof: `0x${bytesToHex13(randomBytes6(128))}`,
|
|
4582
3661
|
publicInputs: [
|
|
4583
|
-
`0x${
|
|
4584
|
-
`0x${
|
|
3662
|
+
`0x${bytesToHex13(new TextEncoder().encode(intent.intentId))}`,
|
|
3663
|
+
`0x${bytesToHex13(new TextEncoder().encode(quote.quoteId))}`
|
|
4585
3664
|
]
|
|
4586
3665
|
},
|
|
4587
3666
|
fulfilledAt: Math.floor(Date.now() / 1e3)
|
|
@@ -5733,7 +4812,7 @@ function createZcashNativeBackend(config) {
|
|
|
5733
4812
|
|
|
5734
4813
|
// src/settlement/backends/direct-chain.ts
|
|
5735
4814
|
import { PrivacyLevel as PrivacyLevel5 } from "@sip-protocol/types";
|
|
5736
|
-
import { randomBytes as
|
|
4815
|
+
import { randomBytes as randomBytes7, bytesToHex as bytesToHex14 } from "@noble/hashes/utils";
|
|
5737
4816
|
var DEFAULT_GAS_FEES = {
|
|
5738
4817
|
ethereum: 21000n * 50n * 1000000000n,
|
|
5739
4818
|
// 21k gas * 50 gwei = 0.00105 ETH
|
|
@@ -7060,18 +6139,18 @@ import { ZcashErrorCode as ZcashErrorCode2 } from "@sip-protocol/types";
|
|
|
7060
6139
|
import { ZcashErrorCode as ZcashErrorCode3 } from "@sip-protocol/types";
|
|
7061
6140
|
|
|
7062
6141
|
// src/bitcoin/taproot.ts
|
|
7063
|
-
import { secp256k1 as
|
|
7064
|
-
import { sha256 as
|
|
7065
|
-
import { bytesToHex as
|
|
6142
|
+
import { secp256k1 as secp256k13, schnorr } from "@noble/curves/secp256k1";
|
|
6143
|
+
import { sha256 as sha25610 } from "@noble/hashes/sha256";
|
|
6144
|
+
import { bytesToHex as bytesToHex15, hexToBytes as hexToBytes11 } from "@noble/hashes/utils";
|
|
7066
6145
|
var BECH32_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
7067
6146
|
var BECH32_GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
7068
6147
|
function taggedHash(tag, data) {
|
|
7069
|
-
const tagHash =
|
|
6148
|
+
const tagHash = sha25610(new TextEncoder().encode(tag));
|
|
7070
6149
|
const taggedData = new Uint8Array(tagHash.length * 2 + data.length);
|
|
7071
6150
|
taggedData.set(tagHash, 0);
|
|
7072
6151
|
taggedData.set(tagHash, tagHash.length);
|
|
7073
6152
|
taggedData.set(data, tagHash.length * 2);
|
|
7074
|
-
return
|
|
6153
|
+
return sha25610(taggedData);
|
|
7075
6154
|
}
|
|
7076
6155
|
function schnorrSign(message, privateKey, auxRand) {
|
|
7077
6156
|
if (message.length !== 32) {
|
|
@@ -7105,7 +6184,7 @@ function getXOnlyPublicKey(privateKey) {
|
|
|
7105
6184
|
if (privateKey.length !== 32) {
|
|
7106
6185
|
throw new ValidationError("privateKey must be 32 bytes", "privateKey");
|
|
7107
6186
|
}
|
|
7108
|
-
const publicKey =
|
|
6187
|
+
const publicKey = secp256k13.getPublicKey(privateKey, false);
|
|
7109
6188
|
return publicKey.slice(1, 33);
|
|
7110
6189
|
}
|
|
7111
6190
|
function computeTweakedKey(internalKey, merkleRoot) {
|
|
@@ -7117,16 +6196,16 @@ function computeTweakedKey(internalKey, merkleRoot) {
|
|
|
7117
6196
|
}
|
|
7118
6197
|
const tweakData = merkleRoot ? new Uint8Array([...internalKey, ...merkleRoot]) : internalKey;
|
|
7119
6198
|
const tweak = taggedHash("TapTweak", tweakData);
|
|
7120
|
-
const tweakScalar = BigInt("0x" +
|
|
7121
|
-
const internalPoint =
|
|
7122
|
-
"02" +
|
|
6199
|
+
const tweakScalar = BigInt("0x" + bytesToHex15(tweak)) % secp256k13.CURVE.n;
|
|
6200
|
+
const internalPoint = secp256k13.ProjectivePoint.fromHex(
|
|
6201
|
+
"02" + bytesToHex15(internalKey)
|
|
7123
6202
|
);
|
|
7124
|
-
const tweakPoint =
|
|
6203
|
+
const tweakPoint = secp256k13.ProjectivePoint.BASE.multiply(tweakScalar);
|
|
7125
6204
|
const tweakedPoint = internalPoint.add(tweakPoint);
|
|
7126
6205
|
const tweakedKeyBytes = tweakedPoint.toRawBytes(false);
|
|
7127
6206
|
const xOnly = tweakedKeyBytes.slice(1, 33);
|
|
7128
6207
|
const yCoord = tweakedKeyBytes.slice(33, 65);
|
|
7129
|
-
const yBigInt = BigInt("0x" +
|
|
6208
|
+
const yBigInt = BigInt("0x" + bytesToHex15(yCoord));
|
|
7130
6209
|
const parity = Number(yBigInt & 1n);
|
|
7131
6210
|
return {
|
|
7132
6211
|
tweakedKey: xOnly,
|
|
@@ -7156,9 +6235,9 @@ function createTaprootOutput(internalKey, scripts) {
|
|
|
7156
6235
|
}
|
|
7157
6236
|
const { tweakedKey, parity } = computeTweakedKey(internalKey, merkleRoot);
|
|
7158
6237
|
return {
|
|
7159
|
-
tweakedKey: `0x${
|
|
7160
|
-
internalKey: `0x${
|
|
7161
|
-
merkleRoot: merkleRoot ? `0x${
|
|
6238
|
+
tweakedKey: `0x${bytesToHex15(tweakedKey)}`,
|
|
6239
|
+
internalKey: `0x${bytesToHex15(internalKey)}`,
|
|
6240
|
+
merkleRoot: merkleRoot ? `0x${bytesToHex15(merkleRoot)}` : void 0,
|
|
7162
6241
|
parity
|
|
7163
6242
|
};
|
|
7164
6243
|
}
|
|
@@ -7291,10 +6370,10 @@ function createKeySpendOnlyOutput(privateKey, network = "mainnet") {
|
|
|
7291
6370
|
if (!isValidPrivateKey(privateKey)) {
|
|
7292
6371
|
throw new ValidationError("privateKey must be a valid 32-byte hex string", "privateKey");
|
|
7293
6372
|
}
|
|
7294
|
-
const privKeyBytes =
|
|
6373
|
+
const privKeyBytes = hexToBytes11(privateKey.slice(2));
|
|
7295
6374
|
const internalKey = getXOnlyPublicKey(privKeyBytes);
|
|
7296
6375
|
const output = createTaprootOutput(internalKey);
|
|
7297
|
-
const tweakedKeyBytes =
|
|
6376
|
+
const tweakedKeyBytes = hexToBytes11(output.tweakedKey.slice(2));
|
|
7298
6377
|
const address = taprootAddress(tweakedKeyBytes, network);
|
|
7299
6378
|
return {
|
|
7300
6379
|
output,
|
|
@@ -7320,11 +6399,11 @@ function schnorrSignHex(message, privateKey, auxRand) {
|
|
|
7320
6399
|
if (auxRand && !isValidHex(auxRand)) {
|
|
7321
6400
|
throw new ValidationError("auxRand must be a hex string", "auxRand");
|
|
7322
6401
|
}
|
|
7323
|
-
const messageBytes =
|
|
7324
|
-
const privateKeyBytes =
|
|
7325
|
-
const auxRandBytes = auxRand ?
|
|
6402
|
+
const messageBytes = hexToBytes11(message.slice(2));
|
|
6403
|
+
const privateKeyBytes = hexToBytes11(privateKey.slice(2));
|
|
6404
|
+
const auxRandBytes = auxRand ? hexToBytes11(auxRand.slice(2)) : void 0;
|
|
7326
6405
|
const signature = schnorrSign(messageBytes, privateKeyBytes, auxRandBytes);
|
|
7327
|
-
return `0x${
|
|
6406
|
+
return `0x${bytesToHex15(signature)}`;
|
|
7328
6407
|
}
|
|
7329
6408
|
function schnorrVerifyHex(signature, message, publicKey) {
|
|
7330
6409
|
if (!isValidHex(signature)) {
|
|
@@ -7336,16 +6415,16 @@ function schnorrVerifyHex(signature, message, publicKey) {
|
|
|
7336
6415
|
if (!isValidHex(publicKey)) {
|
|
7337
6416
|
throw new ValidationError("publicKey must be a hex string", "publicKey");
|
|
7338
6417
|
}
|
|
7339
|
-
const signatureBytes =
|
|
7340
|
-
const messageBytes =
|
|
7341
|
-
const publicKeyBytes =
|
|
6418
|
+
const signatureBytes = hexToBytes11(signature.slice(2));
|
|
6419
|
+
const messageBytes = hexToBytes11(message.slice(2));
|
|
6420
|
+
const publicKeyBytes = hexToBytes11(publicKey.slice(2));
|
|
7342
6421
|
return schnorrVerify(signatureBytes, messageBytes, publicKeyBytes);
|
|
7343
6422
|
}
|
|
7344
6423
|
|
|
7345
6424
|
// src/bitcoin/silent-payments.ts
|
|
7346
|
-
import { secp256k1 as
|
|
7347
|
-
import { sha256 as
|
|
7348
|
-
import { bytesToHex as
|
|
6425
|
+
import { secp256k1 as secp256k14 } from "@noble/curves/secp256k1";
|
|
6426
|
+
import { sha256 as sha25611 } from "@noble/hashes/sha256";
|
|
6427
|
+
import { bytesToHex as bytesToHex16, hexToBytes as hexToBytes12 } from "@noble/hashes/utils";
|
|
7349
6428
|
|
|
7350
6429
|
// src/payment/payment.ts
|
|
7351
6430
|
import {
|
|
@@ -7353,8 +6432,8 @@ import {
|
|
|
7353
6432
|
PrivacyLevel as PrivacyLevel8,
|
|
7354
6433
|
PaymentStatus
|
|
7355
6434
|
} from "@sip-protocol/types";
|
|
7356
|
-
import { sha256 as
|
|
7357
|
-
import { bytesToHex as
|
|
6435
|
+
import { sha256 as sha25612 } from "@noble/hashes/sha256";
|
|
6436
|
+
import { bytesToHex as bytesToHex17, hexToBytes as hexToBytes13, randomBytes as randomBytes8 } from "@noble/hashes/utils";
|
|
7358
6437
|
import { xchacha20poly1305 as xchacha20poly13052 } from "@noble/ciphers/chacha.js";
|
|
7359
6438
|
import { hkdf as hkdf2 } from "@noble/hashes/hkdf";
|
|
7360
6439
|
|
|
@@ -7850,8 +6929,8 @@ async function createShieldedPayment(params, options) {
|
|
|
7850
6929
|
let viewingKeyHash;
|
|
7851
6930
|
if (viewingKey) {
|
|
7852
6931
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
7853
|
-
const keyBytes =
|
|
7854
|
-
viewingKeyHash = `0x${
|
|
6932
|
+
const keyBytes = hexToBytes13(keyHex);
|
|
6933
|
+
viewingKeyHash = `0x${bytesToHex17(sha25612(keyBytes))}`;
|
|
7855
6934
|
}
|
|
7856
6935
|
const privacyConfig = getPrivacyConfig(
|
|
7857
6936
|
privacy,
|
|
@@ -7891,7 +6970,7 @@ async function createShieldedPayment(params, options) {
|
|
|
7891
6970
|
if (privacy !== PrivacyLevel8.TRANSPARENT && proofProvider?.isReady) {
|
|
7892
6971
|
const hexToUint8 = (hex) => {
|
|
7893
6972
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
7894
|
-
return
|
|
6973
|
+
return hexToBytes13(cleanHex);
|
|
7895
6974
|
};
|
|
7896
6975
|
const fundingResult = await proofProvider.generateFundingProof({
|
|
7897
6976
|
balance: amount,
|
|
@@ -7918,17 +6997,17 @@ async function createShieldedPayment(params, options) {
|
|
|
7918
6997
|
}
|
|
7919
6998
|
function encryptMemo(memo, viewingKey) {
|
|
7920
6999
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
7921
|
-
const keyBytes =
|
|
7922
|
-
const encKey = hkdf2(
|
|
7000
|
+
const keyBytes = hexToBytes13(keyHex);
|
|
7001
|
+
const encKey = hkdf2(sha25612, keyBytes, new Uint8Array(0), new Uint8Array(0), 32);
|
|
7923
7002
|
try {
|
|
7924
|
-
const nonce =
|
|
7003
|
+
const nonce = randomBytes8(24);
|
|
7925
7004
|
const cipher = xchacha20poly13052(encKey, nonce);
|
|
7926
7005
|
const plaintext = new TextEncoder().encode(memo);
|
|
7927
7006
|
const ciphertext = cipher.encrypt(plaintext);
|
|
7928
7007
|
const result = new Uint8Array(nonce.length + ciphertext.length);
|
|
7929
7008
|
result.set(nonce);
|
|
7930
7009
|
result.set(ciphertext, nonce.length);
|
|
7931
|
-
return `0x${
|
|
7010
|
+
return `0x${bytesToHex17(result)}`;
|
|
7932
7011
|
} finally {
|
|
7933
7012
|
secureWipe(keyBytes);
|
|
7934
7013
|
secureWipe(encKey);
|
|
@@ -7936,11 +7015,11 @@ function encryptMemo(memo, viewingKey) {
|
|
|
7936
7015
|
}
|
|
7937
7016
|
function decryptMemo(encryptedMemo, viewingKey) {
|
|
7938
7017
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
7939
|
-
const keyBytes =
|
|
7940
|
-
const encKey = hkdf2(
|
|
7018
|
+
const keyBytes = hexToBytes13(keyHex);
|
|
7019
|
+
const encKey = hkdf2(sha25612, keyBytes, new Uint8Array(0), new Uint8Array(0), 32);
|
|
7941
7020
|
try {
|
|
7942
7021
|
const dataHex = encryptedMemo.startsWith("0x") ? encryptedMemo.slice(2) : encryptedMemo;
|
|
7943
|
-
const data =
|
|
7022
|
+
const data = hexToBytes13(dataHex);
|
|
7944
7023
|
const nonce = data.slice(0, 24);
|
|
7945
7024
|
const ciphertext = data.slice(24);
|
|
7946
7025
|
const cipher = xchacha20poly13052(encKey, nonce);
|
|
@@ -7991,9 +7070,9 @@ import {
|
|
|
7991
7070
|
ProposalStatus,
|
|
7992
7071
|
PrivacyLevel as PrivacyLevel9
|
|
7993
7072
|
} from "@sip-protocol/types";
|
|
7994
|
-
import { secp256k1 as
|
|
7995
|
-
import { sha256 as
|
|
7996
|
-
import { bytesToHex as
|
|
7073
|
+
import { secp256k1 as secp256k15 } from "@noble/curves/secp256k1";
|
|
7074
|
+
import { sha256 as sha25613 } from "@noble/hashes/sha256";
|
|
7075
|
+
import { bytesToHex as bytesToHex18, hexToBytes as hexToBytes14, randomBytes as randomBytes9 } from "@noble/hashes/utils";
|
|
7997
7076
|
var DEFAULT_PROPOSAL_TTL = 7 * 24 * 60 * 60;
|
|
7998
7077
|
var Treasury = class _Treasury {
|
|
7999
7078
|
config;
|
|
@@ -8484,12 +7563,12 @@ var Treasury = class _Treasury {
|
|
|
8484
7563
|
}
|
|
8485
7564
|
};
|
|
8486
7565
|
function generateTreasuryId() {
|
|
8487
|
-
const bytes =
|
|
8488
|
-
return `treasury_${
|
|
7566
|
+
const bytes = randomBytes9(16);
|
|
7567
|
+
return `treasury_${bytesToHex18(bytes)}`;
|
|
8489
7568
|
}
|
|
8490
7569
|
function generateProposalId() {
|
|
8491
|
-
const bytes =
|
|
8492
|
-
return `prop_${
|
|
7570
|
+
const bytes = randomBytes9(16);
|
|
7571
|
+
return `prop_${bytesToHex18(bytes)}`;
|
|
8493
7572
|
}
|
|
8494
7573
|
function computeProposalHash(proposal) {
|
|
8495
7574
|
const data = JSON.stringify({
|
|
@@ -8501,13 +7580,13 @@ function computeProposalHash(proposal) {
|
|
|
8501
7580
|
createdAt: proposal.createdAt,
|
|
8502
7581
|
expiresAt: proposal.expiresAt
|
|
8503
7582
|
}, (_, value) => typeof value === "bigint" ? value.toString() : value);
|
|
8504
|
-
return
|
|
7583
|
+
return sha25613(new TextEncoder().encode(data));
|
|
8505
7584
|
}
|
|
8506
7585
|
function signMessage(messageHash, privateKey) {
|
|
8507
7586
|
const keyHex = privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey;
|
|
8508
|
-
const keyBytes =
|
|
7587
|
+
const keyBytes = hexToBytes14(keyHex);
|
|
8509
7588
|
try {
|
|
8510
|
-
const signature =
|
|
7589
|
+
const signature = secp256k15.sign(messageHash, keyBytes);
|
|
8511
7590
|
return `0x${signature.toCompactHex()}`;
|
|
8512
7591
|
} finally {
|
|
8513
7592
|
secureWipe(keyBytes);
|
|
@@ -8517,9 +7596,9 @@ function verifySignature(messageHash, signature, publicKey) {
|
|
|
8517
7596
|
const sigHex = signature.startsWith("0x") ? signature.slice(2) : signature;
|
|
8518
7597
|
const pubKeyHex = publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey;
|
|
8519
7598
|
try {
|
|
8520
|
-
const sigBytes =
|
|
8521
|
-
const pubKeyBytes =
|
|
8522
|
-
return
|
|
7599
|
+
const sigBytes = hexToBytes14(sigHex);
|
|
7600
|
+
const pubKeyBytes = hexToBytes14(pubKeyHex);
|
|
7601
|
+
return secp256k15.verify(sigBytes, messageHash, pubKeyBytes);
|
|
8523
7602
|
} catch {
|
|
8524
7603
|
return false;
|
|
8525
7604
|
}
|
|
@@ -8679,7 +7758,7 @@ function validateBatchProposalParams(params, config) {
|
|
|
8679
7758
|
import {
|
|
8680
7759
|
ReportStatus
|
|
8681
7760
|
} from "@sip-protocol/types";
|
|
8682
|
-
import { bytesToHex as
|
|
7761
|
+
import { bytesToHex as bytesToHex19, randomBytes as randomBytes10 } from "@noble/hashes/utils";
|
|
8683
7762
|
var DEFAULTS2 = {
|
|
8684
7763
|
riskThreshold: 70,
|
|
8685
7764
|
highValueThreshold: 10000000000n,
|
|
@@ -9426,7 +8505,7 @@ var ComplianceManager = class _ComplianceManager {
|
|
|
9426
8505
|
}
|
|
9427
8506
|
};
|
|
9428
8507
|
function generateId(prefix) {
|
|
9429
|
-
return `${prefix}_${
|
|
8508
|
+
return `${prefix}_${bytesToHex19(randomBytes10(12))}`;
|
|
9430
8509
|
}
|
|
9431
8510
|
function validateRegisterAuditorParams(params) {
|
|
9432
8511
|
if (!params.organization?.trim()) {
|
|
@@ -9514,8 +8593,8 @@ function validateReportParams(params) {
|
|
|
9514
8593
|
}
|
|
9515
8594
|
|
|
9516
8595
|
// src/compliance/reports.ts
|
|
9517
|
-
import { sha256 as
|
|
9518
|
-
import { hexToBytes as
|
|
8596
|
+
import { sha256 as sha25614 } from "@noble/hashes/sha256";
|
|
8597
|
+
import { hexToBytes as hexToBytes15, bytesToHex as bytesToHex20 } from "@noble/hashes/utils";
|
|
9519
8598
|
|
|
9520
8599
|
// src/compliance/pdf.ts
|
|
9521
8600
|
function generatePdfReport(report, options = {}) {
|
|
@@ -9816,12 +8895,12 @@ var ComplianceReporter = class {
|
|
|
9816
8895
|
normalizeViewingKey(viewingKey) {
|
|
9817
8896
|
if (typeof viewingKey === "string") {
|
|
9818
8897
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
9819
|
-
const keyBytes =
|
|
9820
|
-
const hashBytes =
|
|
8898
|
+
const keyBytes = hexToBytes15(keyHex);
|
|
8899
|
+
const hashBytes = sha25614(keyBytes);
|
|
9821
8900
|
return {
|
|
9822
8901
|
key: `0x${keyHex}`,
|
|
9823
8902
|
path: "m/0",
|
|
9824
|
-
hash: `0x${
|
|
8903
|
+
hash: `0x${bytesToHex20(hashBytes)}`
|
|
9825
8904
|
};
|
|
9826
8905
|
}
|
|
9827
8906
|
return viewingKey;
|
|
@@ -10202,8 +9281,8 @@ var ComplianceReporter = class {
|
|
|
10202
9281
|
};
|
|
10203
9282
|
|
|
10204
9283
|
// src/compliance/conditional.ts
|
|
10205
|
-
import { sha256 as
|
|
10206
|
-
import { bytesToHex as
|
|
9284
|
+
import { sha256 as sha25615 } from "@noble/hashes/sha256";
|
|
9285
|
+
import { bytesToHex as bytesToHex21, hexToBytes as hexToBytes16, randomBytes as randomBytes11 } from "@noble/hashes/utils";
|
|
10207
9286
|
import { xchacha20poly1305 as xchacha20poly13053 } from "@noble/ciphers/chacha.js";
|
|
10208
9287
|
var ConditionalDisclosure = class {
|
|
10209
9288
|
/**
|
|
@@ -10269,20 +9348,20 @@ var ConditionalDisclosure = class {
|
|
|
10269
9348
|
params.commitment,
|
|
10270
9349
|
revealAfterSeconds
|
|
10271
9350
|
);
|
|
10272
|
-
const nonce =
|
|
10273
|
-
const viewingKeyBytes =
|
|
9351
|
+
const nonce = randomBytes11(24);
|
|
9352
|
+
const viewingKeyBytes = hexToBytes16(params.viewingKey.slice(2));
|
|
10274
9353
|
const cipher = xchacha20poly13053(encryptionKey, nonce);
|
|
10275
9354
|
const encryptedKey = cipher.encrypt(viewingKeyBytes);
|
|
10276
9355
|
const commitmentData = new Uint8Array([
|
|
10277
9356
|
...viewingKeyBytes,
|
|
10278
9357
|
...this._numberToBytes(revealAfterSeconds)
|
|
10279
9358
|
]);
|
|
10280
|
-
const commitmentHash =
|
|
9359
|
+
const commitmentHash = sha25615(commitmentData);
|
|
10281
9360
|
return {
|
|
10282
|
-
encryptedKey: "0x" +
|
|
10283
|
-
nonce: "0x" +
|
|
9361
|
+
encryptedKey: "0x" + bytesToHex21(encryptedKey),
|
|
9362
|
+
nonce: "0x" + bytesToHex21(nonce),
|
|
10284
9363
|
revealAfter: revealAfterSeconds,
|
|
10285
|
-
verificationCommitment: "0x" +
|
|
9364
|
+
verificationCommitment: "0x" + bytesToHex21(commitmentHash),
|
|
10286
9365
|
encryptionCommitment: params.commitment,
|
|
10287
9366
|
type
|
|
10288
9367
|
};
|
|
@@ -10359,11 +9438,11 @@ var ConditionalDisclosure = class {
|
|
|
10359
9438
|
timeLock.encryptionCommitment,
|
|
10360
9439
|
timeLock.revealAfter
|
|
10361
9440
|
);
|
|
10362
|
-
const nonce =
|
|
10363
|
-
const encryptedData =
|
|
9441
|
+
const nonce = hexToBytes16(timeLock.nonce.slice(2));
|
|
9442
|
+
const encryptedData = hexToBytes16(timeLock.encryptedKey.slice(2));
|
|
10364
9443
|
const cipher = xchacha20poly13053(encryptionKey, nonce);
|
|
10365
9444
|
const decryptedBytes = cipher.decrypt(encryptedData);
|
|
10366
|
-
const viewingKey = "0x" +
|
|
9445
|
+
const viewingKey = "0x" + bytesToHex21(decryptedBytes);
|
|
10367
9446
|
return {
|
|
10368
9447
|
unlocked: true,
|
|
10369
9448
|
viewingKey
|
|
@@ -10394,13 +9473,13 @@ var ConditionalDisclosure = class {
|
|
|
10394
9473
|
*/
|
|
10395
9474
|
verifyCommitment(timeLock, viewingKey) {
|
|
10396
9475
|
try {
|
|
10397
|
-
const viewingKeyBytes =
|
|
9476
|
+
const viewingKeyBytes = hexToBytes16(viewingKey.slice(2));
|
|
10398
9477
|
const commitmentData = new Uint8Array([
|
|
10399
9478
|
...viewingKeyBytes,
|
|
10400
9479
|
...this._numberToBytes(timeLock.revealAfter)
|
|
10401
9480
|
]);
|
|
10402
|
-
const expectedCommitment =
|
|
10403
|
-
const actualCommitment =
|
|
9481
|
+
const expectedCommitment = sha25615(commitmentData);
|
|
9482
|
+
const actualCommitment = hexToBytes16(timeLock.verificationCommitment.slice(2));
|
|
10404
9483
|
if (expectedCommitment.length !== actualCommitment.length) {
|
|
10405
9484
|
return false;
|
|
10406
9485
|
}
|
|
@@ -10419,10 +9498,10 @@ var ConditionalDisclosure = class {
|
|
|
10419
9498
|
* @private
|
|
10420
9499
|
*/
|
|
10421
9500
|
_deriveEncryptionKey(commitment, revealAfter) {
|
|
10422
|
-
const commitmentBytes =
|
|
9501
|
+
const commitmentBytes = hexToBytes16(commitment.slice(2));
|
|
10423
9502
|
const timeBytes = this._numberToBytes(revealAfter);
|
|
10424
9503
|
const combined = new Uint8Array([...commitmentBytes, ...timeBytes]);
|
|
10425
|
-
const key =
|
|
9504
|
+
const key = sha25615(combined);
|
|
10426
9505
|
if (key.length !== 32) {
|
|
10427
9506
|
throw new CryptoError(
|
|
10428
9507
|
"Derived key must be 32 bytes",
|
|
@@ -10449,14 +9528,14 @@ var ConditionalDisclosure = class {
|
|
|
10449
9528
|
};
|
|
10450
9529
|
|
|
10451
9530
|
// src/compliance/conditional-threshold.ts
|
|
10452
|
-
import { secp256k1 as
|
|
10453
|
-
import { sha256 as
|
|
10454
|
-
import { bytesToHex as
|
|
10455
|
-
var CURVE_ORDER2 =
|
|
9531
|
+
import { secp256k1 as secp256k16 } from "@noble/curves/secp256k1";
|
|
9532
|
+
import { sha256 as sha25616 } from "@noble/hashes/sha256";
|
|
9533
|
+
import { bytesToHex as bytesToHex22, hexToBytes as hexToBytes17 } from "@noble/hashes/utils";
|
|
9534
|
+
var CURVE_ORDER2 = secp256k16.CURVE.n;
|
|
10456
9535
|
|
|
10457
9536
|
// src/compliance/threshold.ts
|
|
10458
|
-
import { sha256 as
|
|
10459
|
-
import { bytesToHex as
|
|
9537
|
+
import { sha256 as sha25617 } from "@noble/hashes/sha256";
|
|
9538
|
+
import { bytesToHex as bytesToHex23, hexToBytes as hexToBytes18, randomBytes as randomBytes12 } from "@noble/hashes/utils";
|
|
10460
9539
|
var FIELD_PRIME = 2n ** 256n - 189n;
|
|
10461
9540
|
var ThresholdViewingKey = class {
|
|
10462
9541
|
/**
|
|
@@ -10639,7 +9718,7 @@ var ThresholdViewingKey = class {
|
|
|
10639
9718
|
* Convert viewing key to secret (bigint)
|
|
10640
9719
|
*/
|
|
10641
9720
|
static viewingKeyToSecret(viewingKey) {
|
|
10642
|
-
const bytes =
|
|
9721
|
+
const bytes = hexToBytes18(viewingKey.slice(2));
|
|
10643
9722
|
let secret = 0n;
|
|
10644
9723
|
for (let i = 0; i < bytes.length; i++) {
|
|
10645
9724
|
secret = secret << 8n | BigInt(bytes[i]);
|
|
@@ -10673,7 +9752,7 @@ var ThresholdViewingKey = class {
|
|
|
10673
9752
|
* Generate a random field element
|
|
10674
9753
|
*/
|
|
10675
9754
|
static randomFieldElement() {
|
|
10676
|
-
const bytes =
|
|
9755
|
+
const bytes = randomBytes12(32);
|
|
10677
9756
|
let value = 0n;
|
|
10678
9757
|
for (let i = 0; i < bytes.length; i++) {
|
|
10679
9758
|
value = value << 8n | BigInt(bytes[i]);
|
|
@@ -10698,8 +9777,8 @@ var ThresholdViewingKey = class {
|
|
|
10698
9777
|
*/
|
|
10699
9778
|
static createCommitment(secret, coefficients) {
|
|
10700
9779
|
const data = [secret, ...coefficients].map((c) => c.toString(16).padStart(64, "0")).join("");
|
|
10701
|
-
const hash2 =
|
|
10702
|
-
return
|
|
9780
|
+
const hash2 = sha25617(hexToBytes18(data));
|
|
9781
|
+
return bytesToHex23(hash2);
|
|
10703
9782
|
}
|
|
10704
9783
|
/**
|
|
10705
9784
|
* Encode share as string: "x:y:len:commitment"
|
|
@@ -10822,10 +9901,10 @@ var ThresholdViewingKey = class {
|
|
|
10822
9901
|
};
|
|
10823
9902
|
|
|
10824
9903
|
// src/compliance/derivation.ts
|
|
10825
|
-
import { sha256 as
|
|
10826
|
-
import { sha512 as
|
|
9904
|
+
import { sha256 as sha25618 } from "@noble/hashes/sha256";
|
|
9905
|
+
import { sha512 as sha5122 } from "@noble/hashes/sha512";
|
|
10827
9906
|
import { hmac as hmac2 } from "@noble/hashes/hmac";
|
|
10828
|
-
import { bytesToHex as
|
|
9907
|
+
import { bytesToHex as bytesToHex24, utf8ToBytes as utf8ToBytes4 } from "@noble/hashes/utils";
|
|
10829
9908
|
var AuditorType = /* @__PURE__ */ ((AuditorType2) => {
|
|
10830
9909
|
AuditorType2[AuditorType2["PRIMARY"] = 0] = "PRIMARY";
|
|
10831
9910
|
AuditorType2[AuditorType2["REGULATORY"] = 1] = "REGULATORY";
|
|
@@ -10922,7 +10001,7 @@ var AuditorKeyDerivation = class {
|
|
|
10922
10001
|
auditorType
|
|
10923
10002
|
// auditorType (non-hardened)
|
|
10924
10003
|
];
|
|
10925
|
-
const masterData = hmac2(
|
|
10004
|
+
const masterData = hmac2(sha5122, utf8ToBytes4("SIP-MASTER-SEED"), masterSeed);
|
|
10926
10005
|
let currentKey = new Uint8Array(masterData.slice(0, 32));
|
|
10927
10006
|
let chainCode = new Uint8Array(masterData.slice(32, 64));
|
|
10928
10007
|
try {
|
|
@@ -10935,9 +10014,9 @@ var AuditorKeyDerivation = class {
|
|
|
10935
10014
|
currentKey = new Uint8Array(derived.key);
|
|
10936
10015
|
chainCode = new Uint8Array(derived.chainCode);
|
|
10937
10016
|
}
|
|
10938
|
-
const keyHex = `0x${
|
|
10939
|
-
const hashBytes =
|
|
10940
|
-
const hash2 = `0x${
|
|
10017
|
+
const keyHex = `0x${bytesToHex24(currentKey)}`;
|
|
10018
|
+
const hashBytes = sha25618(currentKey);
|
|
10019
|
+
const hash2 = `0x${bytesToHex24(hashBytes)}`;
|
|
10941
10020
|
const viewingKey = {
|
|
10942
10021
|
key: keyHex,
|
|
10943
10022
|
path,
|
|
@@ -11004,7 +10083,7 @@ var AuditorKeyDerivation = class {
|
|
|
11004
10083
|
account | this.HARDENED
|
|
11005
10084
|
// account' (hardened)
|
|
11006
10085
|
];
|
|
11007
|
-
const masterData = hmac2(
|
|
10086
|
+
const masterData = hmac2(sha5122, utf8ToBytes4("SIP-MASTER-SEED"), masterSeed);
|
|
11008
10087
|
let commonKey = new Uint8Array(masterData.slice(0, 32));
|
|
11009
10088
|
let commonChainCode = new Uint8Array(masterData.slice(32, 64));
|
|
11010
10089
|
try {
|
|
@@ -11021,9 +10100,9 @@ var AuditorKeyDerivation = class {
|
|
|
11021
10100
|
for (const auditorType of uniqueTypes) {
|
|
11022
10101
|
const derived = this.deriveChildKey(commonKey, commonChainCode, auditorType);
|
|
11023
10102
|
try {
|
|
11024
|
-
const keyHex = `0x${
|
|
11025
|
-
const hashBytes =
|
|
11026
|
-
const hash2 = `0x${
|
|
10103
|
+
const keyHex = `0x${bytesToHex24(derived.key)}`;
|
|
10104
|
+
const hashBytes = sha25618(derived.key);
|
|
10105
|
+
const hash2 = `0x${bytesToHex24(hashBytes)}`;
|
|
11027
10106
|
const path = this.derivePath(auditorType, account);
|
|
11028
10107
|
const viewingKey = {
|
|
11029
10108
|
key: keyHex,
|
|
@@ -11088,7 +10167,7 @@ var AuditorKeyDerivation = class {
|
|
|
11088
10167
|
}
|
|
11089
10168
|
const indexView = new DataView(data.buffer, 33, 4);
|
|
11090
10169
|
indexView.setUint32(0, index, false);
|
|
11091
|
-
const hmacResult = hmac2(
|
|
10170
|
+
const hmacResult = hmac2(sha5122, chainCode, data);
|
|
11092
10171
|
const childKey = new Uint8Array(hmacResult.slice(0, 32));
|
|
11093
10172
|
const childChainCode = new Uint8Array(hmacResult.slice(32, 64));
|
|
11094
10173
|
return {
|
|
@@ -11144,7 +10223,7 @@ var AuditorKeyDerivation = class {
|
|
|
11144
10223
|
};
|
|
11145
10224
|
|
|
11146
10225
|
// src/auction/sealed-bid.ts
|
|
11147
|
-
import { randomBytes as
|
|
10226
|
+
import { randomBytes as randomBytes13, bytesToHex as bytesToHex25 } from "@noble/hashes/utils";
|
|
11148
10227
|
var SealedBidAuction = class {
|
|
11149
10228
|
/**
|
|
11150
10229
|
* Create a sealed bid for an auction
|
|
@@ -11221,7 +10300,7 @@ var SealedBidAuction = class {
|
|
|
11221
10300
|
);
|
|
11222
10301
|
}
|
|
11223
10302
|
}
|
|
11224
|
-
const salt = params.salt ??
|
|
10303
|
+
const salt = params.salt ?? randomBytes13(32);
|
|
11225
10304
|
const { commitment, blinding } = commit(params.amount, salt);
|
|
11226
10305
|
const sealedBid = {
|
|
11227
10306
|
auctionId: params.auctionId,
|
|
@@ -11365,7 +10444,7 @@ var SealedBidAuction = class {
|
|
|
11365
10444
|
* ```
|
|
11366
10445
|
*/
|
|
11367
10446
|
revealBid(bid, amount, salt) {
|
|
11368
|
-
const saltHex = `0x${
|
|
10447
|
+
const saltHex = `0x${bytesToHex25(salt)}`;
|
|
11369
10448
|
const isValid = this.verifyBid({
|
|
11370
10449
|
commitment: bid.commitment,
|
|
11371
10450
|
amount,
|
|
@@ -11850,9 +10929,9 @@ function createSealedBidAuction() {
|
|
|
11850
10929
|
}
|
|
11851
10930
|
|
|
11852
10931
|
// src/governance/private-vote.ts
|
|
11853
|
-
import { sha256 as
|
|
10932
|
+
import { sha256 as sha25619 } from "@noble/hashes/sha256";
|
|
11854
10933
|
import { hkdf as hkdf3 } from "@noble/hashes/hkdf";
|
|
11855
|
-
import { bytesToHex as
|
|
10934
|
+
import { bytesToHex as bytesToHex26, hexToBytes as hexToBytes20, randomBytes as randomBytes14, utf8ToBytes as utf8ToBytes5 } from "@noble/hashes/utils";
|
|
11856
10935
|
import { xchacha20poly1305 as xchacha20poly13054 } from "@noble/ciphers/chacha.js";
|
|
11857
10936
|
var VOTE_ENCRYPTION_DOMAIN = "SIP-PRIVATE-VOTE-ENCRYPTION-V1";
|
|
11858
10937
|
var NONCE_SIZE2 = 24;
|
|
@@ -11889,7 +10968,7 @@ var PrivateVoting = class {
|
|
|
11889
10968
|
const { proposalId, choice, weight, encryptionKey, voter = "anonymous" } = params;
|
|
11890
10969
|
const derivedKey = this.deriveEncryptionKey(encryptionKey, proposalId);
|
|
11891
10970
|
try {
|
|
11892
|
-
const nonce =
|
|
10971
|
+
const nonce = randomBytes14(NONCE_SIZE2);
|
|
11893
10972
|
const voteData = {
|
|
11894
10973
|
proposalId,
|
|
11895
10974
|
choice,
|
|
@@ -11900,11 +10979,11 @@ var PrivateVoting = class {
|
|
|
11900
10979
|
const plaintext = utf8ToBytes5(JSON.stringify(voteData));
|
|
11901
10980
|
const cipher = xchacha20poly13054(derivedKey, nonce);
|
|
11902
10981
|
const ciphertext = cipher.encrypt(plaintext);
|
|
11903
|
-
const keyHash =
|
|
10982
|
+
const keyHash = sha25619(hexToBytes20(encryptionKey.slice(2)));
|
|
11904
10983
|
return {
|
|
11905
|
-
ciphertext: `0x${
|
|
11906
|
-
nonce: `0x${
|
|
11907
|
-
encryptionKeyHash: `0x${
|
|
10984
|
+
ciphertext: `0x${bytesToHex26(ciphertext)}`,
|
|
10985
|
+
nonce: `0x${bytesToHex26(nonce)}`,
|
|
10986
|
+
encryptionKeyHash: `0x${bytesToHex26(keyHash)}`,
|
|
11908
10987
|
proposalId,
|
|
11909
10988
|
voter,
|
|
11910
10989
|
timestamp: voteData.timestamp
|
|
@@ -11950,8 +11029,8 @@ var PrivateVoting = class {
|
|
|
11950
11029
|
}
|
|
11951
11030
|
const derivedKey = this.deriveEncryptionKey(decryptionKey, vote.proposalId);
|
|
11952
11031
|
try {
|
|
11953
|
-
const keyHash =
|
|
11954
|
-
const expectedKeyHash = `0x${
|
|
11032
|
+
const keyHash = sha25619(hexToBytes20(decryptionKey.slice(2)));
|
|
11033
|
+
const expectedKeyHash = `0x${bytesToHex26(keyHash)}`;
|
|
11955
11034
|
if (vote.encryptionKeyHash !== expectedKeyHash) {
|
|
11956
11035
|
throw new CryptoError(
|
|
11957
11036
|
"Decryption key hash mismatch - this key cannot decrypt this vote",
|
|
@@ -11960,9 +11039,9 @@ var PrivateVoting = class {
|
|
|
11960
11039
|
);
|
|
11961
11040
|
}
|
|
11962
11041
|
const nonceHex = vote.nonce.startsWith("0x") ? vote.nonce.slice(2) : vote.nonce;
|
|
11963
|
-
const nonce =
|
|
11042
|
+
const nonce = hexToBytes20(nonceHex);
|
|
11964
11043
|
const ciphertextHex = vote.ciphertext.startsWith("0x") ? vote.ciphertext.slice(2) : vote.ciphertext;
|
|
11965
|
-
const ciphertext =
|
|
11044
|
+
const ciphertext = hexToBytes20(ciphertextHex);
|
|
11966
11045
|
const cipher = xchacha20poly13054(derivedKey, nonce);
|
|
11967
11046
|
let plaintext;
|
|
11968
11047
|
try {
|
|
@@ -12051,11 +11130,11 @@ var PrivateVoting = class {
|
|
|
12051
11130
|
*/
|
|
12052
11131
|
deriveEncryptionKey(key, proposalId) {
|
|
12053
11132
|
const keyHex = key.startsWith("0x") ? key.slice(2) : key;
|
|
12054
|
-
const keyBytes =
|
|
11133
|
+
const keyBytes = hexToBytes20(keyHex);
|
|
12055
11134
|
try {
|
|
12056
11135
|
const salt = utf8ToBytes5(VOTE_ENCRYPTION_DOMAIN);
|
|
12057
11136
|
const info = utf8ToBytes5(proposalId);
|
|
12058
|
-
return hkdf3(
|
|
11137
|
+
return hkdf3(sha25619, keyBytes, salt, info, 32);
|
|
12059
11138
|
} finally {
|
|
12060
11139
|
secureWipe(keyBytes);
|
|
12061
11140
|
}
|
|
@@ -12200,21 +11279,21 @@ var PrivateVoting = class {
|
|
|
12200
11279
|
const blindings = {};
|
|
12201
11280
|
for (const [choice, weights] of Object.entries(votesByChoice)) {
|
|
12202
11281
|
const totalWeight = weights.reduce((sum, w) => sum + w, 0n);
|
|
12203
|
-
const { commitment, blinding } = commit(totalWeight,
|
|
11282
|
+
const { commitment, blinding } = commit(totalWeight, hexToBytes20(generateBlinding().slice(2)));
|
|
12204
11283
|
tallies[choice] = commitment;
|
|
12205
11284
|
blindings[choice] = blinding;
|
|
12206
11285
|
}
|
|
12207
11286
|
const encryptedBlindings = {};
|
|
12208
11287
|
for (const [choice, blinding] of Object.entries(blindings)) {
|
|
12209
|
-
const nonce =
|
|
11288
|
+
const nonce = randomBytes14(NONCE_SIZE2);
|
|
12210
11289
|
const derivedKey = this.deriveEncryptionKey(decryptionKey, `${proposalId}-tally-${choice}`);
|
|
12211
11290
|
try {
|
|
12212
11291
|
const cipher = xchacha20poly13054(derivedKey, nonce);
|
|
12213
|
-
const blindingBytes =
|
|
11292
|
+
const blindingBytes = hexToBytes20(blinding.slice(2));
|
|
12214
11293
|
const ciphertext = cipher.encrypt(blindingBytes);
|
|
12215
11294
|
encryptedBlindings[choice] = {
|
|
12216
|
-
ciphertext: `0x${
|
|
12217
|
-
nonce: `0x${
|
|
11295
|
+
ciphertext: `0x${bytesToHex26(ciphertext)}`,
|
|
11296
|
+
nonce: `0x${bytesToHex26(nonce)}`
|
|
12218
11297
|
};
|
|
12219
11298
|
} finally {
|
|
12220
11299
|
secureWipe(derivedKey);
|
|
@@ -12307,9 +11386,9 @@ var PrivateVoting = class {
|
|
|
12307
11386
|
}
|
|
12308
11387
|
let reconstructedKey = null;
|
|
12309
11388
|
try {
|
|
12310
|
-
reconstructedKey =
|
|
11389
|
+
reconstructedKey = hexToBytes20(decryptionShares[0].share.slice(2));
|
|
12311
11390
|
for (let i = 1; i < decryptionShares.length; i++) {
|
|
12312
|
-
const shareBytes =
|
|
11391
|
+
const shareBytes = hexToBytes20(decryptionShares[i].share.slice(2));
|
|
12313
11392
|
if (shareBytes.length !== reconstructedKey.length) {
|
|
12314
11393
|
throw new ValidationError(
|
|
12315
11394
|
"all decryption shares must have the same length",
|
|
@@ -12322,7 +11401,7 @@ var PrivateVoting = class {
|
|
|
12322
11401
|
reconstructedKey[j] ^= shareBytes[j];
|
|
12323
11402
|
}
|
|
12324
11403
|
}
|
|
12325
|
-
const reconstructedKeyHex = `0x${
|
|
11404
|
+
const reconstructedKeyHex = `0x${bytesToHex26(reconstructedKey)}`;
|
|
12326
11405
|
const results = {};
|
|
12327
11406
|
for (const [choice, commitmentPoint] of Object.entries(tally.tallies)) {
|
|
12328
11407
|
const encBlinding = tally.encryptedBlindings[choice];
|
|
@@ -12339,11 +11418,11 @@ var PrivateVoting = class {
|
|
|
12339
11418
|
);
|
|
12340
11419
|
let blindingFactor;
|
|
12341
11420
|
try {
|
|
12342
|
-
const nonceBytes =
|
|
12343
|
-
const ciphertextBytes =
|
|
11421
|
+
const nonceBytes = hexToBytes20(encBlinding.nonce.slice(2));
|
|
11422
|
+
const ciphertextBytes = hexToBytes20(encBlinding.ciphertext.slice(2));
|
|
12344
11423
|
const cipher = xchacha20poly13054(derivedKey, nonceBytes);
|
|
12345
11424
|
const blindingBytes = cipher.decrypt(ciphertextBytes);
|
|
12346
|
-
blindingFactor = `0x${
|
|
11425
|
+
blindingFactor = `0x${bytesToHex26(blindingBytes)}`;
|
|
12347
11426
|
} catch (e) {
|
|
12348
11427
|
throw new CryptoError(
|
|
12349
11428
|
"failed to decrypt blinding factor",
|
|
@@ -12363,7 +11442,7 @@ var PrivateVoting = class {
|
|
|
12363
11442
|
try {
|
|
12364
11443
|
const { commitment: testCommit } = commit(
|
|
12365
11444
|
value,
|
|
12366
|
-
|
|
11445
|
+
hexToBytes20(blindingFactor.slice(2))
|
|
12367
11446
|
);
|
|
12368
11447
|
if (testCommit === commitmentPoint) {
|
|
12369
11448
|
results[choice] = value;
|
|
@@ -12563,9 +11642,9 @@ function createPrivateVoting() {
|
|
|
12563
11642
|
}
|
|
12564
11643
|
|
|
12565
11644
|
// src/nft/private-nft.ts
|
|
12566
|
-
import { sha256 as
|
|
12567
|
-
import { secp256k1 as
|
|
12568
|
-
import { bytesToHex as
|
|
11645
|
+
import { sha256 as sha25620 } from "@noble/hashes/sha256";
|
|
11646
|
+
import { secp256k1 as secp256k17 } from "@noble/curves/secp256k1";
|
|
11647
|
+
import { bytesToHex as bytesToHex27, hexToBytes as hexToBytes21 } from "@noble/hashes/utils";
|
|
12569
11648
|
var PrivateNFT = class {
|
|
12570
11649
|
/**
|
|
12571
11650
|
* Create a private ownership record for an NFT
|
|
@@ -12651,23 +11730,23 @@ var PrivateNFT = class {
|
|
|
12651
11730
|
const { ownership, challenge, stealthPrivateKey } = params;
|
|
12652
11731
|
try {
|
|
12653
11732
|
const message = this.createProofMessage(ownership, challenge);
|
|
12654
|
-
const messageHash =
|
|
12655
|
-
const privateKeyBytes =
|
|
12656
|
-
const signature =
|
|
11733
|
+
const messageHash = sha25620(new TextEncoder().encode(message));
|
|
11734
|
+
const privateKeyBytes = hexToBytes21(stealthPrivateKey.slice(2));
|
|
11735
|
+
const signature = secp256k17.sign(messageHash, privateKeyBytes);
|
|
12657
11736
|
const zkProof = {
|
|
12658
11737
|
type: "ownership",
|
|
12659
|
-
proof: `0x${
|
|
11738
|
+
proof: `0x${bytesToHex27(signature.toCompactRawBytes())}`,
|
|
12660
11739
|
publicInputs: [
|
|
12661
|
-
`0x${
|
|
11740
|
+
`0x${bytesToHex27(messageHash)}`
|
|
12662
11741
|
]
|
|
12663
11742
|
};
|
|
12664
|
-
const stealthHashBytes =
|
|
11743
|
+
const stealthHashBytes = sha25620(hexToBytes21(ownership.ownerStealth.address.slice(2)));
|
|
12665
11744
|
return {
|
|
12666
11745
|
nftContract: ownership.nftContract,
|
|
12667
11746
|
tokenId: ownership.tokenId,
|
|
12668
11747
|
challenge,
|
|
12669
11748
|
proof: zkProof,
|
|
12670
|
-
stealthHash: `0x${
|
|
11749
|
+
stealthHash: `0x${bytesToHex27(stealthHashBytes)}`,
|
|
12671
11750
|
timestamp: Date.now()
|
|
12672
11751
|
};
|
|
12673
11752
|
} catch (e) {
|
|
@@ -12709,9 +11788,9 @@ var PrivateNFT = class {
|
|
|
12709
11788
|
verifyOwnership(proof) {
|
|
12710
11789
|
try {
|
|
12711
11790
|
this.validateOwnershipProof(proof);
|
|
12712
|
-
const signatureBytes =
|
|
12713
|
-
const signature =
|
|
12714
|
-
const messageHash =
|
|
11791
|
+
const signatureBytes = hexToBytes21(proof.proof.proof.slice(2));
|
|
11792
|
+
const signature = secp256k17.Signature.fromCompact(signatureBytes);
|
|
11793
|
+
const messageHash = hexToBytes21(proof.proof.publicInputs[0].slice(2));
|
|
12715
11794
|
if (signatureBytes.length !== 64) {
|
|
12716
11795
|
return {
|
|
12717
11796
|
valid: false,
|
|
@@ -12808,12 +11887,12 @@ var PrivateNFT = class {
|
|
|
12808
11887
|
chain: nft.chain,
|
|
12809
11888
|
timestamp: Date.now()
|
|
12810
11889
|
};
|
|
12811
|
-
const previousOwnerHashBytes =
|
|
11890
|
+
const previousOwnerHashBytes = sha25620(hexToBytes21(nft.ownerStealth.address.slice(2)));
|
|
12812
11891
|
const transfer = {
|
|
12813
11892
|
nftContract: nft.nftContract,
|
|
12814
11893
|
tokenId: nft.tokenId,
|
|
12815
11894
|
newOwnerStealth,
|
|
12816
|
-
previousOwnerHash: `0x${
|
|
11895
|
+
previousOwnerHash: `0x${bytesToHex27(previousOwnerHashBytes)}`,
|
|
12817
11896
|
chain: nft.chain,
|
|
12818
11897
|
timestamp: Date.now()
|
|
12819
11898
|
};
|
|
@@ -12880,8 +11959,8 @@ var PrivateNFT = class {
|
|
|
12880
11959
|
);
|
|
12881
11960
|
}
|
|
12882
11961
|
const ownedNFTs = [];
|
|
12883
|
-
const scanKeyHex = `0x${
|
|
12884
|
-
const viewingKeyHex = `0x${
|
|
11962
|
+
const scanKeyHex = `0x${bytesToHex27(scanKey)}`;
|
|
11963
|
+
const viewingKeyHex = `0x${bytesToHex27(viewingKey)}`;
|
|
12885
11964
|
for (const transfer of transfers) {
|
|
12886
11965
|
try {
|
|
12887
11966
|
if (!transfer || typeof transfer !== "object") {
|
|
@@ -15747,7 +14826,7 @@ var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
|
15747
14826
|
* @see https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/
|
|
15748
14827
|
*/
|
|
15749
14828
|
buildRawEthereumTx(tx) {
|
|
15750
|
-
const
|
|
14829
|
+
const hexToBytes22 = (hex) => {
|
|
15751
14830
|
if (!hex || hex === "0x" || hex === "0x0" || hex === "0x00") {
|
|
15752
14831
|
return new Uint8Array(0);
|
|
15753
14832
|
}
|
|
@@ -15764,21 +14843,21 @@ var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
|
15764
14843
|
const isEIP1559 = tx.maxFeePerGas !== void 0 && tx.maxPriorityFeePerGas !== void 0;
|
|
15765
14844
|
if (isEIP1559) {
|
|
15766
14845
|
const txData = [
|
|
15767
|
-
|
|
14846
|
+
hexToBytes22(`0x${tx.chainId.toString(16)}`),
|
|
15768
14847
|
// chainId
|
|
15769
|
-
|
|
14848
|
+
hexToBytes22(tx.nonce),
|
|
15770
14849
|
// nonce
|
|
15771
|
-
|
|
14850
|
+
hexToBytes22(tx.maxPriorityFeePerGas),
|
|
15772
14851
|
// maxPriorityFeePerGas
|
|
15773
|
-
|
|
14852
|
+
hexToBytes22(tx.maxFeePerGas),
|
|
15774
14853
|
// maxFeePerGas
|
|
15775
|
-
|
|
14854
|
+
hexToBytes22(tx.gasLimit),
|
|
15776
14855
|
// gasLimit
|
|
15777
|
-
|
|
14856
|
+
hexToBytes22(tx.to),
|
|
15778
14857
|
// to
|
|
15779
|
-
|
|
14858
|
+
hexToBytes22(tx.value),
|
|
15780
14859
|
// value
|
|
15781
|
-
|
|
14860
|
+
hexToBytes22(tx.data),
|
|
15782
14861
|
// data
|
|
15783
14862
|
[]
|
|
15784
14863
|
// accessList (empty)
|
|
@@ -15797,19 +14876,19 @@ var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
|
15797
14876
|
);
|
|
15798
14877
|
}
|
|
15799
14878
|
const txData = [
|
|
15800
|
-
|
|
14879
|
+
hexToBytes22(tx.nonce),
|
|
15801
14880
|
// nonce
|
|
15802
|
-
|
|
14881
|
+
hexToBytes22(tx.gasPrice),
|
|
15803
14882
|
// gasPrice
|
|
15804
|
-
|
|
14883
|
+
hexToBytes22(tx.gasLimit),
|
|
15805
14884
|
// gasLimit
|
|
15806
|
-
|
|
14885
|
+
hexToBytes22(tx.to),
|
|
15807
14886
|
// to
|
|
15808
|
-
|
|
14887
|
+
hexToBytes22(tx.value),
|
|
15809
14888
|
// value
|
|
15810
|
-
|
|
14889
|
+
hexToBytes22(tx.data),
|
|
15811
14890
|
// data
|
|
15812
|
-
|
|
14891
|
+
hexToBytes22(`0x${tx.chainId.toString(16)}`),
|
|
15813
14892
|
// v (chainId for EIP-155)
|
|
15814
14893
|
new Uint8Array(0),
|
|
15815
14894
|
// r (empty for unsigned)
|
|
@@ -16325,7 +15404,7 @@ function createTrezorAdapter(config) {
|
|
|
16325
15404
|
|
|
16326
15405
|
// src/wallet/hardware/mock.ts
|
|
16327
15406
|
import { WalletErrorCode as WalletErrorCode17 } from "@sip-protocol/types";
|
|
16328
|
-
import { bytesToHex as
|
|
15407
|
+
import { bytesToHex as bytesToHex28, randomBytes as randomBytes15 } from "@noble/hashes/utils";
|
|
16329
15408
|
var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
16330
15409
|
chain;
|
|
16331
15410
|
name = "mock-ledger";
|
|
@@ -16570,15 +15649,15 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
16570
15649
|
}
|
|
16571
15650
|
}
|
|
16572
15651
|
generateMockAddress(index) {
|
|
16573
|
-
const bytes =
|
|
15652
|
+
const bytes = randomBytes15(20);
|
|
16574
15653
|
bytes[0] = index;
|
|
16575
|
-
return `0x${
|
|
15654
|
+
return `0x${bytesToHex28(bytes)}`;
|
|
16576
15655
|
}
|
|
16577
15656
|
generateMockPublicKey(index) {
|
|
16578
|
-
const bytes =
|
|
15657
|
+
const bytes = randomBytes15(33);
|
|
16579
15658
|
bytes[0] = 2;
|
|
16580
15659
|
bytes[1] = index;
|
|
16581
|
-
return `0x${
|
|
15660
|
+
return `0x${bytesToHex28(bytes)}`;
|
|
16582
15661
|
}
|
|
16583
15662
|
generateMockSignature(data) {
|
|
16584
15663
|
const sig = new Uint8Array(65);
|
|
@@ -16587,7 +15666,7 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
16587
15666
|
sig[32 + i] = (data[i % data.length] ?? 0) ^ i * 11;
|
|
16588
15667
|
}
|
|
16589
15668
|
sig[64] = 27;
|
|
16590
|
-
return `0x${
|
|
15669
|
+
return `0x${bytesToHex28(sig)}`;
|
|
16591
15670
|
}
|
|
16592
15671
|
delay(ms) {
|
|
16593
15672
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -16776,15 +15855,15 @@ var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
|
16776
15855
|
}
|
|
16777
15856
|
}
|
|
16778
15857
|
generateMockAddress(index) {
|
|
16779
|
-
const bytes =
|
|
15858
|
+
const bytes = randomBytes15(20);
|
|
16780
15859
|
bytes[0] = index + 100;
|
|
16781
|
-
return `0x${
|
|
15860
|
+
return `0x${bytesToHex28(bytes)}`;
|
|
16782
15861
|
}
|
|
16783
15862
|
generateMockPublicKey(index) {
|
|
16784
|
-
const bytes =
|
|
15863
|
+
const bytes = randomBytes15(33);
|
|
16785
15864
|
bytes[0] = 3;
|
|
16786
15865
|
bytes[1] = index + 100;
|
|
16787
|
-
return `0x${
|
|
15866
|
+
return `0x${bytesToHex28(bytes)}`;
|
|
16788
15867
|
}
|
|
16789
15868
|
generateMockSignature(data) {
|
|
16790
15869
|
const sig = new Uint8Array(65);
|
|
@@ -16793,7 +15872,7 @@ var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
|
16793
15872
|
sig[32 + i] = (data[i % data.length] ?? 0) ^ i * 17;
|
|
16794
15873
|
}
|
|
16795
15874
|
sig[64] = 28;
|
|
16796
|
-
return `0x${
|
|
15875
|
+
return `0x${bytesToHex28(sig)}`;
|
|
16797
15876
|
}
|
|
16798
15877
|
delay(ms) {
|
|
16799
15878
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -16809,49 +15888,55 @@ function createMockTrezorAdapter(config) {
|
|
|
16809
15888
|
// src/wallet/index.ts
|
|
16810
15889
|
import { WalletErrorCode as WalletErrorCode18 } from "@sip-protocol/types";
|
|
16811
15890
|
|
|
15891
|
+
// src/executors/same-chain.ts
|
|
15892
|
+
var SolanaSameChainExecutor = class {
|
|
15893
|
+
chain = "solana";
|
|
15894
|
+
config;
|
|
15895
|
+
constructor(config) {
|
|
15896
|
+
this.config = config;
|
|
15897
|
+
}
|
|
15898
|
+
async execute(params) {
|
|
15899
|
+
const { recipientMetaAddress, amount, token } = params;
|
|
15900
|
+
const { connection, sender, getTokenAccount, signTransaction, getTokenMint: getTokenMint2 } = this.config;
|
|
15901
|
+
const mint = getTokenMint2(token);
|
|
15902
|
+
const senderTokenAccount = await getTokenAccount(mint);
|
|
15903
|
+
const result = await sendPrivateSPLTransfer({
|
|
15904
|
+
connection,
|
|
15905
|
+
sender,
|
|
15906
|
+
senderTokenAccount,
|
|
15907
|
+
recipientMetaAddress,
|
|
15908
|
+
mint,
|
|
15909
|
+
amount,
|
|
15910
|
+
signTransaction
|
|
15911
|
+
});
|
|
15912
|
+
return {
|
|
15913
|
+
txHash: result.txSignature,
|
|
15914
|
+
stealthAddress: result.stealthAddress,
|
|
15915
|
+
ephemeralPublicKey: result.ephemeralPublicKey,
|
|
15916
|
+
explorerUrl: result.explorerUrl,
|
|
15917
|
+
chain: "solana"
|
|
15918
|
+
};
|
|
15919
|
+
}
|
|
15920
|
+
async estimateFee(params) {
|
|
15921
|
+
return estimatePrivateTransferFee(this.config.connection, true);
|
|
15922
|
+
}
|
|
15923
|
+
};
|
|
15924
|
+
function createSameChainExecutor(chain, config) {
|
|
15925
|
+
switch (chain) {
|
|
15926
|
+
case "solana":
|
|
15927
|
+
return new SolanaSameChainExecutor(config);
|
|
15928
|
+
default:
|
|
15929
|
+
throw new Error(`Same-chain executor not available for chain: ${chain}`);
|
|
15930
|
+
}
|
|
15931
|
+
}
|
|
15932
|
+
function isSameChainSupported(chain) {
|
|
15933
|
+
return chain === "solana";
|
|
15934
|
+
}
|
|
15935
|
+
function getSupportedSameChainChains() {
|
|
15936
|
+
return ["solana"];
|
|
15937
|
+
}
|
|
15938
|
+
|
|
16812
15939
|
export {
|
|
16813
|
-
isValidChainId,
|
|
16814
|
-
isValidPrivacyLevel,
|
|
16815
|
-
isValidHex,
|
|
16816
|
-
isValidHexLength,
|
|
16817
|
-
isValidAmount,
|
|
16818
|
-
isNonNegativeAmount,
|
|
16819
|
-
isValidSlippage,
|
|
16820
|
-
isValidStealthMetaAddress,
|
|
16821
|
-
isValidCompressedPublicKey,
|
|
16822
|
-
isValidEd25519PublicKey,
|
|
16823
|
-
isValidPrivateKey,
|
|
16824
|
-
validateAsset,
|
|
16825
|
-
validateIntentInput,
|
|
16826
|
-
validateIntentOutput,
|
|
16827
|
-
validateCreateIntentParams,
|
|
16828
|
-
validateViewingKey,
|
|
16829
|
-
isValidScalar,
|
|
16830
|
-
validateScalar,
|
|
16831
|
-
secureWipe,
|
|
16832
|
-
withSecureBuffer,
|
|
16833
|
-
withSecureBufferSync,
|
|
16834
|
-
secureWipeAll,
|
|
16835
|
-
generateStealthMetaAddress,
|
|
16836
|
-
generateStealthAddress,
|
|
16837
|
-
deriveStealthPrivateKey,
|
|
16838
|
-
checkStealthAddress,
|
|
16839
|
-
encodeStealthMetaAddress,
|
|
16840
|
-
decodeStealthMetaAddress,
|
|
16841
|
-
publicKeyToEthAddress,
|
|
16842
|
-
isEd25519Chain,
|
|
16843
|
-
getCurveForChain,
|
|
16844
|
-
generateEd25519StealthMetaAddress,
|
|
16845
|
-
generateEd25519StealthAddress,
|
|
16846
|
-
deriveEd25519StealthPrivateKey,
|
|
16847
|
-
checkEd25519StealthAddress,
|
|
16848
|
-
ed25519PublicKeyToSolanaAddress,
|
|
16849
|
-
isValidSolanaAddress,
|
|
16850
|
-
solanaAddressToEd25519PublicKey,
|
|
16851
|
-
ed25519PublicKeyToNearAddress,
|
|
16852
|
-
nearAddressToEd25519PublicKey,
|
|
16853
|
-
isValidNearImplicitAddress,
|
|
16854
|
-
isValidNearAccountId,
|
|
16855
15940
|
commit,
|
|
16856
15941
|
verifyOpening,
|
|
16857
15942
|
commitZero,
|
|
@@ -16919,8 +16004,8 @@ export {
|
|
|
16919
16004
|
supportsWASMSimd,
|
|
16920
16005
|
supportsWASMBulkMemory,
|
|
16921
16006
|
checkMobileWASMCompatibility,
|
|
16922
|
-
|
|
16923
|
-
|
|
16007
|
+
hexToBytes8 as hexToBytes,
|
|
16008
|
+
bytesToHex10 as bytesToHex,
|
|
16924
16009
|
isBrowser,
|
|
16925
16010
|
supportsWebWorkers,
|
|
16926
16011
|
supportsSharedArrayBuffer,
|
|
@@ -17060,6 +16145,10 @@ export {
|
|
|
17060
16145
|
createMockLedgerAdapter,
|
|
17061
16146
|
createMockTrezorAdapter,
|
|
17062
16147
|
WalletErrorCode18 as WalletErrorCode,
|
|
16148
|
+
SolanaSameChainExecutor,
|
|
16149
|
+
createSameChainExecutor,
|
|
16150
|
+
isSameChainSupported,
|
|
16151
|
+
getSupportedSameChainChains,
|
|
17063
16152
|
PrivacyLevel11 as PrivacyLevel,
|
|
17064
16153
|
IntentStatus4 as IntentStatus,
|
|
17065
16154
|
SIP_VERSION3 as SIP_VERSION,
|