@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-DLDWZFYC.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
|
});
|
|
@@ -1997,8 +995,8 @@ var OneClickClient = class {
|
|
|
1997
995
|
params.set("depositMemo", depositMemo);
|
|
1998
996
|
}
|
|
1999
997
|
const rawStatus = await this.get(`/v0/status?${params.toString()}`);
|
|
2000
|
-
const settlementTxHash = rawStatus.settlementTxHash ?? rawStatus.destinationChainTxHashes?.[0]?.hash;
|
|
2001
|
-
const depositTxHash = rawStatus.depositTxHash ?? rawStatus.originChainTxHashes?.[0]?.hash;
|
|
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;
|
|
2002
1000
|
return {
|
|
2003
1001
|
...rawStatus,
|
|
2004
1002
|
settlementTxHash,
|
|
@@ -2201,7 +1199,7 @@ import {
|
|
|
2201
1199
|
|
|
2202
1200
|
// src/move/aptos.ts
|
|
2203
1201
|
import { sha3_256 } from "@noble/hashes/sha3";
|
|
2204
|
-
import { bytesToHex as
|
|
1202
|
+
import { bytesToHex as bytesToHex5, hexToBytes as hexToBytes4 } from "@noble/hashes/utils";
|
|
2205
1203
|
var APTOS_SINGLE_ED25519_SCHEME = 0;
|
|
2206
1204
|
function ed25519PublicKeyToAptosAddress(publicKey) {
|
|
2207
1205
|
if (!isValidHex(publicKey)) {
|
|
@@ -2216,12 +1214,12 @@ function ed25519PublicKeyToAptosAddress(publicKey) {
|
|
|
2216
1214
|
"publicKey"
|
|
2217
1215
|
);
|
|
2218
1216
|
}
|
|
2219
|
-
const publicKeyBytes =
|
|
1217
|
+
const publicKeyBytes = hexToBytes4(publicKey.slice(2));
|
|
2220
1218
|
const authKeyInput = new Uint8Array(publicKeyBytes.length + 1);
|
|
2221
1219
|
authKeyInput.set(publicKeyBytes, 0);
|
|
2222
1220
|
authKeyInput[publicKeyBytes.length] = APTOS_SINGLE_ED25519_SCHEME;
|
|
2223
1221
|
const addressHash = sha3_256(authKeyInput);
|
|
2224
|
-
return `0x${
|
|
1222
|
+
return `0x${bytesToHex5(addressHash)}`;
|
|
2225
1223
|
}
|
|
2226
1224
|
function isValidAptosAddress(address) {
|
|
2227
1225
|
if (typeof address !== "string" || address.length === 0) {
|
|
@@ -2335,7 +1333,7 @@ var AptosStealthService = class {
|
|
|
2335
1333
|
|
|
2336
1334
|
// src/move/sui.ts
|
|
2337
1335
|
import { BLAKE2b } from "@noble/hashes/blake2b";
|
|
2338
|
-
import { bytesToHex as
|
|
1336
|
+
import { bytesToHex as bytesToHex6, hexToBytes as hexToBytes5 } from "@noble/hashes/utils";
|
|
2339
1337
|
var SUI_ED25519_SCHEME = 0;
|
|
2340
1338
|
function ed25519PublicKeyToSuiAddress(publicKey) {
|
|
2341
1339
|
if (!isValidHex(publicKey)) {
|
|
@@ -2350,14 +1348,14 @@ function ed25519PublicKeyToSuiAddress(publicKey) {
|
|
|
2350
1348
|
"publicKey"
|
|
2351
1349
|
);
|
|
2352
1350
|
}
|
|
2353
|
-
const publicKeyBytes =
|
|
1351
|
+
const publicKeyBytes = hexToBytes5(publicKey.slice(2));
|
|
2354
1352
|
const addressInput = new Uint8Array(publicKeyBytes.length + 1);
|
|
2355
1353
|
addressInput[0] = SUI_ED25519_SCHEME;
|
|
2356
1354
|
addressInput.set(publicKeyBytes, 1);
|
|
2357
1355
|
const hasher = new BLAKE2b({ dkLen: 32 });
|
|
2358
1356
|
hasher.update(addressInput);
|
|
2359
1357
|
const addressHash = hasher.digest();
|
|
2360
|
-
return `0x${
|
|
1358
|
+
return `0x${bytesToHex6(addressHash)}`;
|
|
2361
1359
|
}
|
|
2362
1360
|
function isValidSuiAddress(address) {
|
|
2363
1361
|
if (typeof address !== "string" || address.length === 0) {
|
|
@@ -3330,6 +2328,80 @@ var SIP = class {
|
|
|
3330
2328
|
fulfilledAt: Math.floor(Date.now() / 1e3)
|
|
3331
2329
|
};
|
|
3332
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-5EMCTPTS.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
|
+
}
|
|
3333
2405
|
};
|
|
3334
2406
|
function createSIP(network = "testnet") {
|
|
3335
2407
|
return new SIP({ network });
|
|
@@ -3346,9 +2418,9 @@ function createProductionSIP(config) {
|
|
|
3346
2418
|
}
|
|
3347
2419
|
|
|
3348
2420
|
// src/cosmos/stealth.ts
|
|
3349
|
-
import { sha256 as
|
|
2421
|
+
import { sha256 as sha2565 } from "@noble/hashes/sha256";
|
|
3350
2422
|
import { ripemd160 } from "@noble/hashes/ripemd160";
|
|
3351
|
-
import { hexToBytes as
|
|
2423
|
+
import { hexToBytes as hexToBytes6, bytesToHex as bytesToHex7 } from "@noble/hashes/utils";
|
|
3352
2424
|
import { bech32 } from "@scure/base";
|
|
3353
2425
|
var CHAIN_PREFIXES = {
|
|
3354
2426
|
cosmos: "cosmos",
|
|
@@ -3430,14 +2502,14 @@ var CosmosStealthService = class {
|
|
|
3430
2502
|
);
|
|
3431
2503
|
}
|
|
3432
2504
|
const metaAddress = {
|
|
3433
|
-
spendingKey: `0x${
|
|
3434
|
-
viewingKey: `0x${
|
|
2505
|
+
spendingKey: `0x${bytesToHex7(spendingPubKey)}`,
|
|
2506
|
+
viewingKey: `0x${bytesToHex7(viewingPubKey)}`,
|
|
3435
2507
|
chain: "ethereum"
|
|
3436
2508
|
// Use ethereum for secp256k1 generation
|
|
3437
2509
|
};
|
|
3438
2510
|
const { stealthAddress, sharedSecret } = generateStealthAddress(metaAddress);
|
|
3439
2511
|
const cosmosAddress = this.stealthKeyToCosmosAddress(
|
|
3440
|
-
|
|
2512
|
+
hexToBytes6(stealthAddress.address.slice(2)),
|
|
3441
2513
|
CHAIN_PREFIXES[chain]
|
|
3442
2514
|
);
|
|
3443
2515
|
return {
|
|
@@ -3465,8 +2537,8 @@ var CosmosStealthService = class {
|
|
|
3465
2537
|
* ```
|
|
3466
2538
|
*/
|
|
3467
2539
|
generateStealthAddressFromMeta(recipientMetaAddress, chain) {
|
|
3468
|
-
const spendingPubKey =
|
|
3469
|
-
const viewingPubKey =
|
|
2540
|
+
const spendingPubKey = hexToBytes6(recipientMetaAddress.spendingKey.slice(2));
|
|
2541
|
+
const viewingPubKey = hexToBytes6(recipientMetaAddress.viewingKey.slice(2));
|
|
3470
2542
|
return this.generateStealthAddress(spendingPubKey, viewingPubKey, chain);
|
|
3471
2543
|
}
|
|
3472
2544
|
/**
|
|
@@ -3496,7 +2568,7 @@ var CosmosStealthService = class {
|
|
|
3496
2568
|
"publicKey"
|
|
3497
2569
|
);
|
|
3498
2570
|
}
|
|
3499
|
-
const sha256Hash =
|
|
2571
|
+
const sha256Hash = sha2565(publicKey);
|
|
3500
2572
|
const hash160 = ripemd160(sha256Hash);
|
|
3501
2573
|
const words = bech32.toWords(hash160);
|
|
3502
2574
|
return bech32.encode(prefix, words);
|
|
@@ -3644,13 +2716,13 @@ function isValidCosmosAddress(address, expectedChain) {
|
|
|
3644
2716
|
}
|
|
3645
2717
|
|
|
3646
2718
|
// src/cosmos/ibc-stealth.ts
|
|
3647
|
-
import { hexToBytes as
|
|
3648
|
-
import { secp256k1 as
|
|
3649
|
-
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";
|
|
3650
2722
|
|
|
3651
2723
|
// src/proofs/mock.ts
|
|
3652
|
-
import { sha256 as
|
|
3653
|
-
import { bytesToHex as
|
|
2724
|
+
import { sha256 as sha2567 } from "@noble/hashes/sha256";
|
|
2725
|
+
import { bytesToHex as bytesToHex9, randomBytes as randomBytes5 } from "@noble/hashes/utils";
|
|
3654
2726
|
var MOCK_PROOF_PREFIX = "0x4d4f434b";
|
|
3655
2727
|
var WARNING_MESSAGE = `
|
|
3656
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
|
|
@@ -3815,17 +2887,17 @@ var MockProofProvider = class {
|
|
|
3815
2887
|
{ type: proofType, params },
|
|
3816
2888
|
(_, v) => typeof v === "bigint" ? v.toString() : v
|
|
3817
2889
|
);
|
|
3818
|
-
const hash2 =
|
|
3819
|
-
const random =
|
|
2890
|
+
const hash2 = sha2567(new TextEncoder().encode(input));
|
|
2891
|
+
const random = randomBytes5(16);
|
|
3820
2892
|
const combined = new Uint8Array(4 + hash2.length + random.length);
|
|
3821
2893
|
combined.set(new TextEncoder().encode("MOCK"), 0);
|
|
3822
2894
|
combined.set(hash2, 4);
|
|
3823
2895
|
combined.set(random, 4 + hash2.length);
|
|
3824
|
-
return `${MOCK_PROOF_PREFIX}${
|
|
2896
|
+
return `${MOCK_PROOF_PREFIX}${bytesToHex9(combined.slice(4))}`;
|
|
3825
2897
|
}
|
|
3826
2898
|
hashToHex(data) {
|
|
3827
|
-
const hash2 =
|
|
3828
|
-
return `0x${
|
|
2899
|
+
const hash2 = sha2567(new TextEncoder().encode(data));
|
|
2900
|
+
return `0x${bytesToHex9(hash2)}`;
|
|
3829
2901
|
}
|
|
3830
2902
|
};
|
|
3831
2903
|
|
|
@@ -4098,7 +3170,7 @@ function checkMobileWASMCompatibility() {
|
|
|
4098
3170
|
recommendations
|
|
4099
3171
|
};
|
|
4100
3172
|
}
|
|
4101
|
-
function
|
|
3173
|
+
function hexToBytes8(hex) {
|
|
4102
3174
|
const h = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
4103
3175
|
if (h.length === 0) return new Uint8Array(0);
|
|
4104
3176
|
if (h.length % 2 !== 0) {
|
|
@@ -4110,7 +3182,7 @@ function hexToBytes9(hex) {
|
|
|
4110
3182
|
}
|
|
4111
3183
|
return bytes;
|
|
4112
3184
|
}
|
|
4113
|
-
function
|
|
3185
|
+
function bytesToHex10(bytes) {
|
|
4114
3186
|
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
4115
3187
|
}
|
|
4116
3188
|
function isBrowser() {
|
|
@@ -4173,13 +3245,13 @@ var CHAIN_NUMERIC_IDS = {
|
|
|
4173
3245
|
};
|
|
4174
3246
|
|
|
4175
3247
|
// src/oracle/verification.ts
|
|
4176
|
-
import { ed25519
|
|
4177
|
-
import { sha256 as
|
|
4178
|
-
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";
|
|
4179
3251
|
|
|
4180
3252
|
// src/oracle/serialization.ts
|
|
4181
|
-
import { sha256 as
|
|
4182
|
-
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";
|
|
4183
3255
|
function serializeAttestationMessage(message) {
|
|
4184
3256
|
const buffer = new Uint8Array(197);
|
|
4185
3257
|
const view = new DataView(buffer.buffer);
|
|
@@ -4222,19 +3294,19 @@ function deserializeAttestationMessage(bytes) {
|
|
|
4222
3294
|
const version = bytes[offset++];
|
|
4223
3295
|
const chainId = view.getUint32(offset, false);
|
|
4224
3296
|
offset += 4;
|
|
4225
|
-
const intentHash = `0x${
|
|
3297
|
+
const intentHash = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4226
3298
|
offset += 32;
|
|
4227
|
-
const recipient = `0x${
|
|
3299
|
+
const recipient = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4228
3300
|
offset += 32;
|
|
4229
3301
|
const amount = bytesToBigint(bytes.slice(offset, offset + 16));
|
|
4230
3302
|
offset += 16;
|
|
4231
|
-
const assetId = `0x${
|
|
3303
|
+
const assetId = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4232
3304
|
offset += 32;
|
|
4233
|
-
const txHash = `0x${
|
|
3305
|
+
const txHash = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4234
3306
|
offset += 32;
|
|
4235
3307
|
const blockNumber = view.getBigUint64(offset, false);
|
|
4236
3308
|
offset += 8;
|
|
4237
|
-
const blockHash = `0x${
|
|
3309
|
+
const blockHash = `0x${bytesToHex11(bytes.slice(offset, offset + 32))}`;
|
|
4238
3310
|
offset += 32;
|
|
4239
3311
|
const timestamp = Number(view.getBigUint64(offset, false));
|
|
4240
3312
|
return {
|
|
@@ -4256,7 +3328,7 @@ function computeAttestationHash(message) {
|
|
|
4256
3328
|
const toHash = new Uint8Array(domain.length + messageBytes.length);
|
|
4257
3329
|
toHash.set(domain, 0);
|
|
4258
3330
|
toHash.set(messageBytes, domain.length);
|
|
4259
|
-
return
|
|
3331
|
+
return sha2568(toHash);
|
|
4260
3332
|
}
|
|
4261
3333
|
function getChainNumericId(chain) {
|
|
4262
3334
|
const id = CHAIN_NUMERIC_IDS[chain];
|
|
@@ -4267,7 +3339,7 @@ function getChainNumericId(chain) {
|
|
|
4267
3339
|
}
|
|
4268
3340
|
function normalizeToBytes(hex, length, field) {
|
|
4269
3341
|
const stripped = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
4270
|
-
const bytes =
|
|
3342
|
+
const bytes = hexToBytes9(stripped);
|
|
4271
3343
|
if (bytes.length === length) {
|
|
4272
3344
|
return bytes;
|
|
4273
3345
|
}
|
|
@@ -4300,9 +3372,9 @@ function bytesToBigint(bytes) {
|
|
|
4300
3372
|
|
|
4301
3373
|
// src/oracle/verification.ts
|
|
4302
3374
|
function deriveOracleId(publicKey) {
|
|
4303
|
-
const keyBytes = typeof publicKey === "string" ?
|
|
4304
|
-
const hash2 =
|
|
4305
|
-
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)}`;
|
|
4306
3378
|
}
|
|
4307
3379
|
function verifyAttestation(attestation, registry) {
|
|
4308
3380
|
const { message, signatures } = attestation;
|
|
@@ -4332,13 +3404,13 @@ function verifyAttestation(attestation, registry) {
|
|
|
4332
3404
|
continue;
|
|
4333
3405
|
}
|
|
4334
3406
|
try {
|
|
4335
|
-
const publicKeyBytes =
|
|
3407
|
+
const publicKeyBytes = hexToBytes10(
|
|
4336
3408
|
oracle.publicKey.startsWith("0x") ? oracle.publicKey.slice(2) : oracle.publicKey
|
|
4337
3409
|
);
|
|
4338
|
-
const signatureBytes =
|
|
3410
|
+
const signatureBytes = hexToBytes10(
|
|
4339
3411
|
sig.signature.startsWith("0x") ? sig.signature.slice(2) : sig.signature
|
|
4340
3412
|
);
|
|
4341
|
-
const isValid =
|
|
3413
|
+
const isValid = ed25519.verify(signatureBytes, messageHash, publicKeyBytes);
|
|
4342
3414
|
if (isValid) {
|
|
4343
3415
|
validCount++;
|
|
4344
3416
|
validOracles.push(sig.oracleId);
|
|
@@ -4360,24 +3432,24 @@ function verifyAttestation(attestation, registry) {
|
|
|
4360
3432
|
}
|
|
4361
3433
|
function verifyOracleSignature(signature, messageHash, oracle) {
|
|
4362
3434
|
try {
|
|
4363
|
-
const publicKeyBytes =
|
|
3435
|
+
const publicKeyBytes = hexToBytes10(
|
|
4364
3436
|
oracle.publicKey.startsWith("0x") ? oracle.publicKey.slice(2) : oracle.publicKey
|
|
4365
3437
|
);
|
|
4366
|
-
const signatureBytes =
|
|
3438
|
+
const signatureBytes = hexToBytes10(
|
|
4367
3439
|
signature.signature.startsWith("0x") ? signature.signature.slice(2) : signature.signature
|
|
4368
3440
|
);
|
|
4369
|
-
return
|
|
3441
|
+
return ed25519.verify(signatureBytes, messageHash, publicKeyBytes);
|
|
4370
3442
|
} catch {
|
|
4371
3443
|
return false;
|
|
4372
3444
|
}
|
|
4373
3445
|
}
|
|
4374
3446
|
function signAttestationMessage(messageHash, privateKey) {
|
|
4375
|
-
const signature =
|
|
4376
|
-
const publicKey =
|
|
3447
|
+
const signature = ed25519.sign(messageHash, privateKey);
|
|
3448
|
+
const publicKey = ed25519.getPublicKey(privateKey);
|
|
4377
3449
|
const oracleId = deriveOracleId(publicKey);
|
|
4378
3450
|
return {
|
|
4379
3451
|
oracleId,
|
|
4380
|
-
signature: `0x${
|
|
3452
|
+
signature: `0x${bytesToHex12(signature)}`
|
|
4381
3453
|
};
|
|
4382
3454
|
}
|
|
4383
3455
|
function createOracleRegistry(config = {}) {
|
|
@@ -4445,7 +3517,7 @@ import { ReportStatus as ReportStatus2 } from "@sip-protocol/types";
|
|
|
4445
3517
|
import {
|
|
4446
3518
|
IntentStatus as IntentStatus3
|
|
4447
3519
|
} from "@sip-protocol/types";
|
|
4448
|
-
import { bytesToHex as
|
|
3520
|
+
import { bytesToHex as bytesToHex13, randomBytes as randomBytes6 } from "@noble/hashes/utils";
|
|
4449
3521
|
var MockSolver = class {
|
|
4450
3522
|
info;
|
|
4451
3523
|
capabilities;
|
|
@@ -4527,7 +3599,7 @@ var MockSolver = class {
|
|
|
4527
3599
|
const spreadAmount = baseOutput * BigInt(Math.floor(this.spreadPercent * 1e4)) / 10000n;
|
|
4528
3600
|
const outputAmount = baseOutput + spreadAmount;
|
|
4529
3601
|
const feeAmount = outputAmount * BigInt(Math.floor(this.feePercent * 1e4)) / 10000n;
|
|
4530
|
-
const quoteId = `quote-${
|
|
3602
|
+
const quoteId = `quote-${bytesToHex13(randomBytes6(8))}`;
|
|
4531
3603
|
const now = Math.floor(Date.now() / 1e3);
|
|
4532
3604
|
const quote = {
|
|
4533
3605
|
quoteId,
|
|
@@ -4538,7 +3610,7 @@ var MockSolver = class {
|
|
|
4538
3610
|
expiry: now + 60,
|
|
4539
3611
|
// Quote valid for 1 minute
|
|
4540
3612
|
fee: feeAmount,
|
|
4541
|
-
signature: `0x${
|
|
3613
|
+
signature: `0x${bytesToHex13(randomBytes6(64))}`,
|
|
4542
3614
|
// Mock signature
|
|
4543
3615
|
validUntil: now + 60,
|
|
4544
3616
|
estimatedGas: 200000n
|
|
@@ -4575,7 +3647,7 @@ var MockSolver = class {
|
|
|
4575
3647
|
error: status.error
|
|
4576
3648
|
};
|
|
4577
3649
|
}
|
|
4578
|
-
const txHash = `0x${
|
|
3650
|
+
const txHash = `0x${bytesToHex13(randomBytes6(32))}`;
|
|
4579
3651
|
status.status = "completed";
|
|
4580
3652
|
status.txHash = txHash;
|
|
4581
3653
|
return {
|
|
@@ -4585,10 +3657,10 @@ var MockSolver = class {
|
|
|
4585
3657
|
txHash: intent.privacyLevel === "transparent" ? txHash : void 0,
|
|
4586
3658
|
fulfillmentProof: {
|
|
4587
3659
|
type: "fulfillment",
|
|
4588
|
-
proof: `0x${
|
|
3660
|
+
proof: `0x${bytesToHex13(randomBytes6(128))}`,
|
|
4589
3661
|
publicInputs: [
|
|
4590
|
-
`0x${
|
|
4591
|
-
`0x${
|
|
3662
|
+
`0x${bytesToHex13(new TextEncoder().encode(intent.intentId))}`,
|
|
3663
|
+
`0x${bytesToHex13(new TextEncoder().encode(quote.quoteId))}`
|
|
4592
3664
|
]
|
|
4593
3665
|
},
|
|
4594
3666
|
fulfilledAt: Math.floor(Date.now() / 1e3)
|
|
@@ -5740,7 +4812,7 @@ function createZcashNativeBackend(config) {
|
|
|
5740
4812
|
|
|
5741
4813
|
// src/settlement/backends/direct-chain.ts
|
|
5742
4814
|
import { PrivacyLevel as PrivacyLevel5 } from "@sip-protocol/types";
|
|
5743
|
-
import { randomBytes as
|
|
4815
|
+
import { randomBytes as randomBytes7, bytesToHex as bytesToHex14 } from "@noble/hashes/utils";
|
|
5744
4816
|
var DEFAULT_GAS_FEES = {
|
|
5745
4817
|
ethereum: 21000n * 50n * 1000000000n,
|
|
5746
4818
|
// 21k gas * 50 gwei = 0.00105 ETH
|
|
@@ -7067,18 +6139,18 @@ import { ZcashErrorCode as ZcashErrorCode2 } from "@sip-protocol/types";
|
|
|
7067
6139
|
import { ZcashErrorCode as ZcashErrorCode3 } from "@sip-protocol/types";
|
|
7068
6140
|
|
|
7069
6141
|
// src/bitcoin/taproot.ts
|
|
7070
|
-
import { secp256k1 as
|
|
7071
|
-
import { sha256 as
|
|
7072
|
-
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";
|
|
7073
6145
|
var BECH32_CHARSET = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
|
|
7074
6146
|
var BECH32_GENERATOR = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
7075
6147
|
function taggedHash(tag, data) {
|
|
7076
|
-
const tagHash =
|
|
6148
|
+
const tagHash = sha25610(new TextEncoder().encode(tag));
|
|
7077
6149
|
const taggedData = new Uint8Array(tagHash.length * 2 + data.length);
|
|
7078
6150
|
taggedData.set(tagHash, 0);
|
|
7079
6151
|
taggedData.set(tagHash, tagHash.length);
|
|
7080
6152
|
taggedData.set(data, tagHash.length * 2);
|
|
7081
|
-
return
|
|
6153
|
+
return sha25610(taggedData);
|
|
7082
6154
|
}
|
|
7083
6155
|
function schnorrSign(message, privateKey, auxRand) {
|
|
7084
6156
|
if (message.length !== 32) {
|
|
@@ -7112,7 +6184,7 @@ function getXOnlyPublicKey(privateKey) {
|
|
|
7112
6184
|
if (privateKey.length !== 32) {
|
|
7113
6185
|
throw new ValidationError("privateKey must be 32 bytes", "privateKey");
|
|
7114
6186
|
}
|
|
7115
|
-
const publicKey =
|
|
6187
|
+
const publicKey = secp256k13.getPublicKey(privateKey, false);
|
|
7116
6188
|
return publicKey.slice(1, 33);
|
|
7117
6189
|
}
|
|
7118
6190
|
function computeTweakedKey(internalKey, merkleRoot) {
|
|
@@ -7124,16 +6196,16 @@ function computeTweakedKey(internalKey, merkleRoot) {
|
|
|
7124
6196
|
}
|
|
7125
6197
|
const tweakData = merkleRoot ? new Uint8Array([...internalKey, ...merkleRoot]) : internalKey;
|
|
7126
6198
|
const tweak = taggedHash("TapTweak", tweakData);
|
|
7127
|
-
const tweakScalar = BigInt("0x" +
|
|
7128
|
-
const internalPoint =
|
|
7129
|
-
"02" +
|
|
6199
|
+
const tweakScalar = BigInt("0x" + bytesToHex15(tweak)) % secp256k13.CURVE.n;
|
|
6200
|
+
const internalPoint = secp256k13.ProjectivePoint.fromHex(
|
|
6201
|
+
"02" + bytesToHex15(internalKey)
|
|
7130
6202
|
);
|
|
7131
|
-
const tweakPoint =
|
|
6203
|
+
const tweakPoint = secp256k13.ProjectivePoint.BASE.multiply(tweakScalar);
|
|
7132
6204
|
const tweakedPoint = internalPoint.add(tweakPoint);
|
|
7133
6205
|
const tweakedKeyBytes = tweakedPoint.toRawBytes(false);
|
|
7134
6206
|
const xOnly = tweakedKeyBytes.slice(1, 33);
|
|
7135
6207
|
const yCoord = tweakedKeyBytes.slice(33, 65);
|
|
7136
|
-
const yBigInt = BigInt("0x" +
|
|
6208
|
+
const yBigInt = BigInt("0x" + bytesToHex15(yCoord));
|
|
7137
6209
|
const parity = Number(yBigInt & 1n);
|
|
7138
6210
|
return {
|
|
7139
6211
|
tweakedKey: xOnly,
|
|
@@ -7163,9 +6235,9 @@ function createTaprootOutput(internalKey, scripts) {
|
|
|
7163
6235
|
}
|
|
7164
6236
|
const { tweakedKey, parity } = computeTweakedKey(internalKey, merkleRoot);
|
|
7165
6237
|
return {
|
|
7166
|
-
tweakedKey: `0x${
|
|
7167
|
-
internalKey: `0x${
|
|
7168
|
-
merkleRoot: merkleRoot ? `0x${
|
|
6238
|
+
tweakedKey: `0x${bytesToHex15(tweakedKey)}`,
|
|
6239
|
+
internalKey: `0x${bytesToHex15(internalKey)}`,
|
|
6240
|
+
merkleRoot: merkleRoot ? `0x${bytesToHex15(merkleRoot)}` : void 0,
|
|
7169
6241
|
parity
|
|
7170
6242
|
};
|
|
7171
6243
|
}
|
|
@@ -7298,10 +6370,10 @@ function createKeySpendOnlyOutput(privateKey, network = "mainnet") {
|
|
|
7298
6370
|
if (!isValidPrivateKey(privateKey)) {
|
|
7299
6371
|
throw new ValidationError("privateKey must be a valid 32-byte hex string", "privateKey");
|
|
7300
6372
|
}
|
|
7301
|
-
const privKeyBytes =
|
|
6373
|
+
const privKeyBytes = hexToBytes11(privateKey.slice(2));
|
|
7302
6374
|
const internalKey = getXOnlyPublicKey(privKeyBytes);
|
|
7303
6375
|
const output = createTaprootOutput(internalKey);
|
|
7304
|
-
const tweakedKeyBytes =
|
|
6376
|
+
const tweakedKeyBytes = hexToBytes11(output.tweakedKey.slice(2));
|
|
7305
6377
|
const address = taprootAddress(tweakedKeyBytes, network);
|
|
7306
6378
|
return {
|
|
7307
6379
|
output,
|
|
@@ -7327,11 +6399,11 @@ function schnorrSignHex(message, privateKey, auxRand) {
|
|
|
7327
6399
|
if (auxRand && !isValidHex(auxRand)) {
|
|
7328
6400
|
throw new ValidationError("auxRand must be a hex string", "auxRand");
|
|
7329
6401
|
}
|
|
7330
|
-
const messageBytes =
|
|
7331
|
-
const privateKeyBytes =
|
|
7332
|
-
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;
|
|
7333
6405
|
const signature = schnorrSign(messageBytes, privateKeyBytes, auxRandBytes);
|
|
7334
|
-
return `0x${
|
|
6406
|
+
return `0x${bytesToHex15(signature)}`;
|
|
7335
6407
|
}
|
|
7336
6408
|
function schnorrVerifyHex(signature, message, publicKey) {
|
|
7337
6409
|
if (!isValidHex(signature)) {
|
|
@@ -7343,16 +6415,16 @@ function schnorrVerifyHex(signature, message, publicKey) {
|
|
|
7343
6415
|
if (!isValidHex(publicKey)) {
|
|
7344
6416
|
throw new ValidationError("publicKey must be a hex string", "publicKey");
|
|
7345
6417
|
}
|
|
7346
|
-
const signatureBytes =
|
|
7347
|
-
const messageBytes =
|
|
7348
|
-
const publicKeyBytes =
|
|
6418
|
+
const signatureBytes = hexToBytes11(signature.slice(2));
|
|
6419
|
+
const messageBytes = hexToBytes11(message.slice(2));
|
|
6420
|
+
const publicKeyBytes = hexToBytes11(publicKey.slice(2));
|
|
7349
6421
|
return schnorrVerify(signatureBytes, messageBytes, publicKeyBytes);
|
|
7350
6422
|
}
|
|
7351
6423
|
|
|
7352
6424
|
// src/bitcoin/silent-payments.ts
|
|
7353
|
-
import { secp256k1 as
|
|
7354
|
-
import { sha256 as
|
|
7355
|
-
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";
|
|
7356
6428
|
|
|
7357
6429
|
// src/payment/payment.ts
|
|
7358
6430
|
import {
|
|
@@ -7360,8 +6432,8 @@ import {
|
|
|
7360
6432
|
PrivacyLevel as PrivacyLevel8,
|
|
7361
6433
|
PaymentStatus
|
|
7362
6434
|
} from "@sip-protocol/types";
|
|
7363
|
-
import { sha256 as
|
|
7364
|
-
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";
|
|
7365
6437
|
import { xchacha20poly1305 as xchacha20poly13052 } from "@noble/ciphers/chacha.js";
|
|
7366
6438
|
import { hkdf as hkdf2 } from "@noble/hashes/hkdf";
|
|
7367
6439
|
|
|
@@ -7857,8 +6929,8 @@ async function createShieldedPayment(params, options) {
|
|
|
7857
6929
|
let viewingKeyHash;
|
|
7858
6930
|
if (viewingKey) {
|
|
7859
6931
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
7860
|
-
const keyBytes =
|
|
7861
|
-
viewingKeyHash = `0x${
|
|
6932
|
+
const keyBytes = hexToBytes13(keyHex);
|
|
6933
|
+
viewingKeyHash = `0x${bytesToHex17(sha25612(keyBytes))}`;
|
|
7862
6934
|
}
|
|
7863
6935
|
const privacyConfig = getPrivacyConfig(
|
|
7864
6936
|
privacy,
|
|
@@ -7898,7 +6970,7 @@ async function createShieldedPayment(params, options) {
|
|
|
7898
6970
|
if (privacy !== PrivacyLevel8.TRANSPARENT && proofProvider?.isReady) {
|
|
7899
6971
|
const hexToUint8 = (hex) => {
|
|
7900
6972
|
const cleanHex = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
7901
|
-
return
|
|
6973
|
+
return hexToBytes13(cleanHex);
|
|
7902
6974
|
};
|
|
7903
6975
|
const fundingResult = await proofProvider.generateFundingProof({
|
|
7904
6976
|
balance: amount,
|
|
@@ -7925,17 +6997,17 @@ async function createShieldedPayment(params, options) {
|
|
|
7925
6997
|
}
|
|
7926
6998
|
function encryptMemo(memo, viewingKey) {
|
|
7927
6999
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
7928
|
-
const keyBytes =
|
|
7929
|
-
const encKey = hkdf2(
|
|
7000
|
+
const keyBytes = hexToBytes13(keyHex);
|
|
7001
|
+
const encKey = hkdf2(sha25612, keyBytes, new Uint8Array(0), new Uint8Array(0), 32);
|
|
7930
7002
|
try {
|
|
7931
|
-
const nonce =
|
|
7003
|
+
const nonce = randomBytes8(24);
|
|
7932
7004
|
const cipher = xchacha20poly13052(encKey, nonce);
|
|
7933
7005
|
const plaintext = new TextEncoder().encode(memo);
|
|
7934
7006
|
const ciphertext = cipher.encrypt(plaintext);
|
|
7935
7007
|
const result = new Uint8Array(nonce.length + ciphertext.length);
|
|
7936
7008
|
result.set(nonce);
|
|
7937
7009
|
result.set(ciphertext, nonce.length);
|
|
7938
|
-
return `0x${
|
|
7010
|
+
return `0x${bytesToHex17(result)}`;
|
|
7939
7011
|
} finally {
|
|
7940
7012
|
secureWipe(keyBytes);
|
|
7941
7013
|
secureWipe(encKey);
|
|
@@ -7943,11 +7015,11 @@ function encryptMemo(memo, viewingKey) {
|
|
|
7943
7015
|
}
|
|
7944
7016
|
function decryptMemo(encryptedMemo, viewingKey) {
|
|
7945
7017
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
7946
|
-
const keyBytes =
|
|
7947
|
-
const encKey = hkdf2(
|
|
7018
|
+
const keyBytes = hexToBytes13(keyHex);
|
|
7019
|
+
const encKey = hkdf2(sha25612, keyBytes, new Uint8Array(0), new Uint8Array(0), 32);
|
|
7948
7020
|
try {
|
|
7949
7021
|
const dataHex = encryptedMemo.startsWith("0x") ? encryptedMemo.slice(2) : encryptedMemo;
|
|
7950
|
-
const data =
|
|
7022
|
+
const data = hexToBytes13(dataHex);
|
|
7951
7023
|
const nonce = data.slice(0, 24);
|
|
7952
7024
|
const ciphertext = data.slice(24);
|
|
7953
7025
|
const cipher = xchacha20poly13052(encKey, nonce);
|
|
@@ -7998,9 +7070,9 @@ import {
|
|
|
7998
7070
|
ProposalStatus,
|
|
7999
7071
|
PrivacyLevel as PrivacyLevel9
|
|
8000
7072
|
} from "@sip-protocol/types";
|
|
8001
|
-
import { secp256k1 as
|
|
8002
|
-
import { sha256 as
|
|
8003
|
-
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";
|
|
8004
7076
|
var DEFAULT_PROPOSAL_TTL = 7 * 24 * 60 * 60;
|
|
8005
7077
|
var Treasury = class _Treasury {
|
|
8006
7078
|
config;
|
|
@@ -8491,12 +7563,12 @@ var Treasury = class _Treasury {
|
|
|
8491
7563
|
}
|
|
8492
7564
|
};
|
|
8493
7565
|
function generateTreasuryId() {
|
|
8494
|
-
const bytes =
|
|
8495
|
-
return `treasury_${
|
|
7566
|
+
const bytes = randomBytes9(16);
|
|
7567
|
+
return `treasury_${bytesToHex18(bytes)}`;
|
|
8496
7568
|
}
|
|
8497
7569
|
function generateProposalId() {
|
|
8498
|
-
const bytes =
|
|
8499
|
-
return `prop_${
|
|
7570
|
+
const bytes = randomBytes9(16);
|
|
7571
|
+
return `prop_${bytesToHex18(bytes)}`;
|
|
8500
7572
|
}
|
|
8501
7573
|
function computeProposalHash(proposal) {
|
|
8502
7574
|
const data = JSON.stringify({
|
|
@@ -8508,13 +7580,13 @@ function computeProposalHash(proposal) {
|
|
|
8508
7580
|
createdAt: proposal.createdAt,
|
|
8509
7581
|
expiresAt: proposal.expiresAt
|
|
8510
7582
|
}, (_, value) => typeof value === "bigint" ? value.toString() : value);
|
|
8511
|
-
return
|
|
7583
|
+
return sha25613(new TextEncoder().encode(data));
|
|
8512
7584
|
}
|
|
8513
7585
|
function signMessage(messageHash, privateKey) {
|
|
8514
7586
|
const keyHex = privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey;
|
|
8515
|
-
const keyBytes =
|
|
7587
|
+
const keyBytes = hexToBytes14(keyHex);
|
|
8516
7588
|
try {
|
|
8517
|
-
const signature =
|
|
7589
|
+
const signature = secp256k15.sign(messageHash, keyBytes);
|
|
8518
7590
|
return `0x${signature.toCompactHex()}`;
|
|
8519
7591
|
} finally {
|
|
8520
7592
|
secureWipe(keyBytes);
|
|
@@ -8524,9 +7596,9 @@ function verifySignature(messageHash, signature, publicKey) {
|
|
|
8524
7596
|
const sigHex = signature.startsWith("0x") ? signature.slice(2) : signature;
|
|
8525
7597
|
const pubKeyHex = publicKey.startsWith("0x") ? publicKey.slice(2) : publicKey;
|
|
8526
7598
|
try {
|
|
8527
|
-
const sigBytes =
|
|
8528
|
-
const pubKeyBytes =
|
|
8529
|
-
return
|
|
7599
|
+
const sigBytes = hexToBytes14(sigHex);
|
|
7600
|
+
const pubKeyBytes = hexToBytes14(pubKeyHex);
|
|
7601
|
+
return secp256k15.verify(sigBytes, messageHash, pubKeyBytes);
|
|
8530
7602
|
} catch {
|
|
8531
7603
|
return false;
|
|
8532
7604
|
}
|
|
@@ -8686,7 +7758,7 @@ function validateBatchProposalParams(params, config) {
|
|
|
8686
7758
|
import {
|
|
8687
7759
|
ReportStatus
|
|
8688
7760
|
} from "@sip-protocol/types";
|
|
8689
|
-
import { bytesToHex as
|
|
7761
|
+
import { bytesToHex as bytesToHex19, randomBytes as randomBytes10 } from "@noble/hashes/utils";
|
|
8690
7762
|
var DEFAULTS2 = {
|
|
8691
7763
|
riskThreshold: 70,
|
|
8692
7764
|
highValueThreshold: 10000000000n,
|
|
@@ -9433,7 +8505,7 @@ var ComplianceManager = class _ComplianceManager {
|
|
|
9433
8505
|
}
|
|
9434
8506
|
};
|
|
9435
8507
|
function generateId(prefix) {
|
|
9436
|
-
return `${prefix}_${
|
|
8508
|
+
return `${prefix}_${bytesToHex19(randomBytes10(12))}`;
|
|
9437
8509
|
}
|
|
9438
8510
|
function validateRegisterAuditorParams(params) {
|
|
9439
8511
|
if (!params.organization?.trim()) {
|
|
@@ -9521,8 +8593,8 @@ function validateReportParams(params) {
|
|
|
9521
8593
|
}
|
|
9522
8594
|
|
|
9523
8595
|
// src/compliance/reports.ts
|
|
9524
|
-
import { sha256 as
|
|
9525
|
-
import { hexToBytes as
|
|
8596
|
+
import { sha256 as sha25614 } from "@noble/hashes/sha256";
|
|
8597
|
+
import { hexToBytes as hexToBytes15, bytesToHex as bytesToHex20 } from "@noble/hashes/utils";
|
|
9526
8598
|
|
|
9527
8599
|
// src/compliance/pdf.ts
|
|
9528
8600
|
function generatePdfReport(report, options = {}) {
|
|
@@ -9823,12 +8895,12 @@ var ComplianceReporter = class {
|
|
|
9823
8895
|
normalizeViewingKey(viewingKey) {
|
|
9824
8896
|
if (typeof viewingKey === "string") {
|
|
9825
8897
|
const keyHex = viewingKey.startsWith("0x") ? viewingKey.slice(2) : viewingKey;
|
|
9826
|
-
const keyBytes =
|
|
9827
|
-
const hashBytes =
|
|
8898
|
+
const keyBytes = hexToBytes15(keyHex);
|
|
8899
|
+
const hashBytes = sha25614(keyBytes);
|
|
9828
8900
|
return {
|
|
9829
8901
|
key: `0x${keyHex}`,
|
|
9830
8902
|
path: "m/0",
|
|
9831
|
-
hash: `0x${
|
|
8903
|
+
hash: `0x${bytesToHex20(hashBytes)}`
|
|
9832
8904
|
};
|
|
9833
8905
|
}
|
|
9834
8906
|
return viewingKey;
|
|
@@ -10209,8 +9281,8 @@ var ComplianceReporter = class {
|
|
|
10209
9281
|
};
|
|
10210
9282
|
|
|
10211
9283
|
// src/compliance/conditional.ts
|
|
10212
|
-
import { sha256 as
|
|
10213
|
-
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";
|
|
10214
9286
|
import { xchacha20poly1305 as xchacha20poly13053 } from "@noble/ciphers/chacha.js";
|
|
10215
9287
|
var ConditionalDisclosure = class {
|
|
10216
9288
|
/**
|
|
@@ -10276,20 +9348,20 @@ var ConditionalDisclosure = class {
|
|
|
10276
9348
|
params.commitment,
|
|
10277
9349
|
revealAfterSeconds
|
|
10278
9350
|
);
|
|
10279
|
-
const nonce =
|
|
10280
|
-
const viewingKeyBytes =
|
|
9351
|
+
const nonce = randomBytes11(24);
|
|
9352
|
+
const viewingKeyBytes = hexToBytes16(params.viewingKey.slice(2));
|
|
10281
9353
|
const cipher = xchacha20poly13053(encryptionKey, nonce);
|
|
10282
9354
|
const encryptedKey = cipher.encrypt(viewingKeyBytes);
|
|
10283
9355
|
const commitmentData = new Uint8Array([
|
|
10284
9356
|
...viewingKeyBytes,
|
|
10285
9357
|
...this._numberToBytes(revealAfterSeconds)
|
|
10286
9358
|
]);
|
|
10287
|
-
const commitmentHash =
|
|
9359
|
+
const commitmentHash = sha25615(commitmentData);
|
|
10288
9360
|
return {
|
|
10289
|
-
encryptedKey: "0x" +
|
|
10290
|
-
nonce: "0x" +
|
|
9361
|
+
encryptedKey: "0x" + bytesToHex21(encryptedKey),
|
|
9362
|
+
nonce: "0x" + bytesToHex21(nonce),
|
|
10291
9363
|
revealAfter: revealAfterSeconds,
|
|
10292
|
-
verificationCommitment: "0x" +
|
|
9364
|
+
verificationCommitment: "0x" + bytesToHex21(commitmentHash),
|
|
10293
9365
|
encryptionCommitment: params.commitment,
|
|
10294
9366
|
type
|
|
10295
9367
|
};
|
|
@@ -10366,11 +9438,11 @@ var ConditionalDisclosure = class {
|
|
|
10366
9438
|
timeLock.encryptionCommitment,
|
|
10367
9439
|
timeLock.revealAfter
|
|
10368
9440
|
);
|
|
10369
|
-
const nonce =
|
|
10370
|
-
const encryptedData =
|
|
9441
|
+
const nonce = hexToBytes16(timeLock.nonce.slice(2));
|
|
9442
|
+
const encryptedData = hexToBytes16(timeLock.encryptedKey.slice(2));
|
|
10371
9443
|
const cipher = xchacha20poly13053(encryptionKey, nonce);
|
|
10372
9444
|
const decryptedBytes = cipher.decrypt(encryptedData);
|
|
10373
|
-
const viewingKey = "0x" +
|
|
9445
|
+
const viewingKey = "0x" + bytesToHex21(decryptedBytes);
|
|
10374
9446
|
return {
|
|
10375
9447
|
unlocked: true,
|
|
10376
9448
|
viewingKey
|
|
@@ -10401,13 +9473,13 @@ var ConditionalDisclosure = class {
|
|
|
10401
9473
|
*/
|
|
10402
9474
|
verifyCommitment(timeLock, viewingKey) {
|
|
10403
9475
|
try {
|
|
10404
|
-
const viewingKeyBytes =
|
|
9476
|
+
const viewingKeyBytes = hexToBytes16(viewingKey.slice(2));
|
|
10405
9477
|
const commitmentData = new Uint8Array([
|
|
10406
9478
|
...viewingKeyBytes,
|
|
10407
9479
|
...this._numberToBytes(timeLock.revealAfter)
|
|
10408
9480
|
]);
|
|
10409
|
-
const expectedCommitment =
|
|
10410
|
-
const actualCommitment =
|
|
9481
|
+
const expectedCommitment = sha25615(commitmentData);
|
|
9482
|
+
const actualCommitment = hexToBytes16(timeLock.verificationCommitment.slice(2));
|
|
10411
9483
|
if (expectedCommitment.length !== actualCommitment.length) {
|
|
10412
9484
|
return false;
|
|
10413
9485
|
}
|
|
@@ -10426,10 +9498,10 @@ var ConditionalDisclosure = class {
|
|
|
10426
9498
|
* @private
|
|
10427
9499
|
*/
|
|
10428
9500
|
_deriveEncryptionKey(commitment, revealAfter) {
|
|
10429
|
-
const commitmentBytes =
|
|
9501
|
+
const commitmentBytes = hexToBytes16(commitment.slice(2));
|
|
10430
9502
|
const timeBytes = this._numberToBytes(revealAfter);
|
|
10431
9503
|
const combined = new Uint8Array([...commitmentBytes, ...timeBytes]);
|
|
10432
|
-
const key =
|
|
9504
|
+
const key = sha25615(combined);
|
|
10433
9505
|
if (key.length !== 32) {
|
|
10434
9506
|
throw new CryptoError(
|
|
10435
9507
|
"Derived key must be 32 bytes",
|
|
@@ -10456,14 +9528,14 @@ var ConditionalDisclosure = class {
|
|
|
10456
9528
|
};
|
|
10457
9529
|
|
|
10458
9530
|
// src/compliance/conditional-threshold.ts
|
|
10459
|
-
import { secp256k1 as
|
|
10460
|
-
import { sha256 as
|
|
10461
|
-
import { bytesToHex as
|
|
10462
|
-
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;
|
|
10463
9535
|
|
|
10464
9536
|
// src/compliance/threshold.ts
|
|
10465
|
-
import { sha256 as
|
|
10466
|
-
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";
|
|
10467
9539
|
var FIELD_PRIME = 2n ** 256n - 189n;
|
|
10468
9540
|
var ThresholdViewingKey = class {
|
|
10469
9541
|
/**
|
|
@@ -10646,7 +9718,7 @@ var ThresholdViewingKey = class {
|
|
|
10646
9718
|
* Convert viewing key to secret (bigint)
|
|
10647
9719
|
*/
|
|
10648
9720
|
static viewingKeyToSecret(viewingKey) {
|
|
10649
|
-
const bytes =
|
|
9721
|
+
const bytes = hexToBytes18(viewingKey.slice(2));
|
|
10650
9722
|
let secret = 0n;
|
|
10651
9723
|
for (let i = 0; i < bytes.length; i++) {
|
|
10652
9724
|
secret = secret << 8n | BigInt(bytes[i]);
|
|
@@ -10680,7 +9752,7 @@ var ThresholdViewingKey = class {
|
|
|
10680
9752
|
* Generate a random field element
|
|
10681
9753
|
*/
|
|
10682
9754
|
static randomFieldElement() {
|
|
10683
|
-
const bytes =
|
|
9755
|
+
const bytes = randomBytes12(32);
|
|
10684
9756
|
let value = 0n;
|
|
10685
9757
|
for (let i = 0; i < bytes.length; i++) {
|
|
10686
9758
|
value = value << 8n | BigInt(bytes[i]);
|
|
@@ -10705,8 +9777,8 @@ var ThresholdViewingKey = class {
|
|
|
10705
9777
|
*/
|
|
10706
9778
|
static createCommitment(secret, coefficients) {
|
|
10707
9779
|
const data = [secret, ...coefficients].map((c) => c.toString(16).padStart(64, "0")).join("");
|
|
10708
|
-
const hash2 =
|
|
10709
|
-
return
|
|
9780
|
+
const hash2 = sha25617(hexToBytes18(data));
|
|
9781
|
+
return bytesToHex23(hash2);
|
|
10710
9782
|
}
|
|
10711
9783
|
/**
|
|
10712
9784
|
* Encode share as string: "x:y:len:commitment"
|
|
@@ -10829,10 +9901,10 @@ var ThresholdViewingKey = class {
|
|
|
10829
9901
|
};
|
|
10830
9902
|
|
|
10831
9903
|
// src/compliance/derivation.ts
|
|
10832
|
-
import { sha256 as
|
|
10833
|
-
import { sha512 as
|
|
9904
|
+
import { sha256 as sha25618 } from "@noble/hashes/sha256";
|
|
9905
|
+
import { sha512 as sha5122 } from "@noble/hashes/sha512";
|
|
10834
9906
|
import { hmac as hmac2 } from "@noble/hashes/hmac";
|
|
10835
|
-
import { bytesToHex as
|
|
9907
|
+
import { bytesToHex as bytesToHex24, utf8ToBytes as utf8ToBytes4 } from "@noble/hashes/utils";
|
|
10836
9908
|
var AuditorType = /* @__PURE__ */ ((AuditorType2) => {
|
|
10837
9909
|
AuditorType2[AuditorType2["PRIMARY"] = 0] = "PRIMARY";
|
|
10838
9910
|
AuditorType2[AuditorType2["REGULATORY"] = 1] = "REGULATORY";
|
|
@@ -10929,7 +10001,7 @@ var AuditorKeyDerivation = class {
|
|
|
10929
10001
|
auditorType
|
|
10930
10002
|
// auditorType (non-hardened)
|
|
10931
10003
|
];
|
|
10932
|
-
const masterData = hmac2(
|
|
10004
|
+
const masterData = hmac2(sha5122, utf8ToBytes4("SIP-MASTER-SEED"), masterSeed);
|
|
10933
10005
|
let currentKey = new Uint8Array(masterData.slice(0, 32));
|
|
10934
10006
|
let chainCode = new Uint8Array(masterData.slice(32, 64));
|
|
10935
10007
|
try {
|
|
@@ -10942,9 +10014,9 @@ var AuditorKeyDerivation = class {
|
|
|
10942
10014
|
currentKey = new Uint8Array(derived.key);
|
|
10943
10015
|
chainCode = new Uint8Array(derived.chainCode);
|
|
10944
10016
|
}
|
|
10945
|
-
const keyHex = `0x${
|
|
10946
|
-
const hashBytes =
|
|
10947
|
-
const hash2 = `0x${
|
|
10017
|
+
const keyHex = `0x${bytesToHex24(currentKey)}`;
|
|
10018
|
+
const hashBytes = sha25618(currentKey);
|
|
10019
|
+
const hash2 = `0x${bytesToHex24(hashBytes)}`;
|
|
10948
10020
|
const viewingKey = {
|
|
10949
10021
|
key: keyHex,
|
|
10950
10022
|
path,
|
|
@@ -11011,7 +10083,7 @@ var AuditorKeyDerivation = class {
|
|
|
11011
10083
|
account | this.HARDENED
|
|
11012
10084
|
// account' (hardened)
|
|
11013
10085
|
];
|
|
11014
|
-
const masterData = hmac2(
|
|
10086
|
+
const masterData = hmac2(sha5122, utf8ToBytes4("SIP-MASTER-SEED"), masterSeed);
|
|
11015
10087
|
let commonKey = new Uint8Array(masterData.slice(0, 32));
|
|
11016
10088
|
let commonChainCode = new Uint8Array(masterData.slice(32, 64));
|
|
11017
10089
|
try {
|
|
@@ -11028,9 +10100,9 @@ var AuditorKeyDerivation = class {
|
|
|
11028
10100
|
for (const auditorType of uniqueTypes) {
|
|
11029
10101
|
const derived = this.deriveChildKey(commonKey, commonChainCode, auditorType);
|
|
11030
10102
|
try {
|
|
11031
|
-
const keyHex = `0x${
|
|
11032
|
-
const hashBytes =
|
|
11033
|
-
const hash2 = `0x${
|
|
10103
|
+
const keyHex = `0x${bytesToHex24(derived.key)}`;
|
|
10104
|
+
const hashBytes = sha25618(derived.key);
|
|
10105
|
+
const hash2 = `0x${bytesToHex24(hashBytes)}`;
|
|
11034
10106
|
const path = this.derivePath(auditorType, account);
|
|
11035
10107
|
const viewingKey = {
|
|
11036
10108
|
key: keyHex,
|
|
@@ -11095,7 +10167,7 @@ var AuditorKeyDerivation = class {
|
|
|
11095
10167
|
}
|
|
11096
10168
|
const indexView = new DataView(data.buffer, 33, 4);
|
|
11097
10169
|
indexView.setUint32(0, index, false);
|
|
11098
|
-
const hmacResult = hmac2(
|
|
10170
|
+
const hmacResult = hmac2(sha5122, chainCode, data);
|
|
11099
10171
|
const childKey = new Uint8Array(hmacResult.slice(0, 32));
|
|
11100
10172
|
const childChainCode = new Uint8Array(hmacResult.slice(32, 64));
|
|
11101
10173
|
return {
|
|
@@ -11151,7 +10223,7 @@ var AuditorKeyDerivation = class {
|
|
|
11151
10223
|
};
|
|
11152
10224
|
|
|
11153
10225
|
// src/auction/sealed-bid.ts
|
|
11154
|
-
import { randomBytes as
|
|
10226
|
+
import { randomBytes as randomBytes13, bytesToHex as bytesToHex25 } from "@noble/hashes/utils";
|
|
11155
10227
|
var SealedBidAuction = class {
|
|
11156
10228
|
/**
|
|
11157
10229
|
* Create a sealed bid for an auction
|
|
@@ -11228,7 +10300,7 @@ var SealedBidAuction = class {
|
|
|
11228
10300
|
);
|
|
11229
10301
|
}
|
|
11230
10302
|
}
|
|
11231
|
-
const salt = params.salt ??
|
|
10303
|
+
const salt = params.salt ?? randomBytes13(32);
|
|
11232
10304
|
const { commitment, blinding } = commit(params.amount, salt);
|
|
11233
10305
|
const sealedBid = {
|
|
11234
10306
|
auctionId: params.auctionId,
|
|
@@ -11372,7 +10444,7 @@ var SealedBidAuction = class {
|
|
|
11372
10444
|
* ```
|
|
11373
10445
|
*/
|
|
11374
10446
|
revealBid(bid, amount, salt) {
|
|
11375
|
-
const saltHex = `0x${
|
|
10447
|
+
const saltHex = `0x${bytesToHex25(salt)}`;
|
|
11376
10448
|
const isValid = this.verifyBid({
|
|
11377
10449
|
commitment: bid.commitment,
|
|
11378
10450
|
amount,
|
|
@@ -11857,9 +10929,9 @@ function createSealedBidAuction() {
|
|
|
11857
10929
|
}
|
|
11858
10930
|
|
|
11859
10931
|
// src/governance/private-vote.ts
|
|
11860
|
-
import { sha256 as
|
|
10932
|
+
import { sha256 as sha25619 } from "@noble/hashes/sha256";
|
|
11861
10933
|
import { hkdf as hkdf3 } from "@noble/hashes/hkdf";
|
|
11862
|
-
import { bytesToHex as
|
|
10934
|
+
import { bytesToHex as bytesToHex26, hexToBytes as hexToBytes20, randomBytes as randomBytes14, utf8ToBytes as utf8ToBytes5 } from "@noble/hashes/utils";
|
|
11863
10935
|
import { xchacha20poly1305 as xchacha20poly13054 } from "@noble/ciphers/chacha.js";
|
|
11864
10936
|
var VOTE_ENCRYPTION_DOMAIN = "SIP-PRIVATE-VOTE-ENCRYPTION-V1";
|
|
11865
10937
|
var NONCE_SIZE2 = 24;
|
|
@@ -11896,7 +10968,7 @@ var PrivateVoting = class {
|
|
|
11896
10968
|
const { proposalId, choice, weight, encryptionKey, voter = "anonymous" } = params;
|
|
11897
10969
|
const derivedKey = this.deriveEncryptionKey(encryptionKey, proposalId);
|
|
11898
10970
|
try {
|
|
11899
|
-
const nonce =
|
|
10971
|
+
const nonce = randomBytes14(NONCE_SIZE2);
|
|
11900
10972
|
const voteData = {
|
|
11901
10973
|
proposalId,
|
|
11902
10974
|
choice,
|
|
@@ -11907,11 +10979,11 @@ var PrivateVoting = class {
|
|
|
11907
10979
|
const plaintext = utf8ToBytes5(JSON.stringify(voteData));
|
|
11908
10980
|
const cipher = xchacha20poly13054(derivedKey, nonce);
|
|
11909
10981
|
const ciphertext = cipher.encrypt(plaintext);
|
|
11910
|
-
const keyHash =
|
|
10982
|
+
const keyHash = sha25619(hexToBytes20(encryptionKey.slice(2)));
|
|
11911
10983
|
return {
|
|
11912
|
-
ciphertext: `0x${
|
|
11913
|
-
nonce: `0x${
|
|
11914
|
-
encryptionKeyHash: `0x${
|
|
10984
|
+
ciphertext: `0x${bytesToHex26(ciphertext)}`,
|
|
10985
|
+
nonce: `0x${bytesToHex26(nonce)}`,
|
|
10986
|
+
encryptionKeyHash: `0x${bytesToHex26(keyHash)}`,
|
|
11915
10987
|
proposalId,
|
|
11916
10988
|
voter,
|
|
11917
10989
|
timestamp: voteData.timestamp
|
|
@@ -11957,8 +11029,8 @@ var PrivateVoting = class {
|
|
|
11957
11029
|
}
|
|
11958
11030
|
const derivedKey = this.deriveEncryptionKey(decryptionKey, vote.proposalId);
|
|
11959
11031
|
try {
|
|
11960
|
-
const keyHash =
|
|
11961
|
-
const expectedKeyHash = `0x${
|
|
11032
|
+
const keyHash = sha25619(hexToBytes20(decryptionKey.slice(2)));
|
|
11033
|
+
const expectedKeyHash = `0x${bytesToHex26(keyHash)}`;
|
|
11962
11034
|
if (vote.encryptionKeyHash !== expectedKeyHash) {
|
|
11963
11035
|
throw new CryptoError(
|
|
11964
11036
|
"Decryption key hash mismatch - this key cannot decrypt this vote",
|
|
@@ -11967,9 +11039,9 @@ var PrivateVoting = class {
|
|
|
11967
11039
|
);
|
|
11968
11040
|
}
|
|
11969
11041
|
const nonceHex = vote.nonce.startsWith("0x") ? vote.nonce.slice(2) : vote.nonce;
|
|
11970
|
-
const nonce =
|
|
11042
|
+
const nonce = hexToBytes20(nonceHex);
|
|
11971
11043
|
const ciphertextHex = vote.ciphertext.startsWith("0x") ? vote.ciphertext.slice(2) : vote.ciphertext;
|
|
11972
|
-
const ciphertext =
|
|
11044
|
+
const ciphertext = hexToBytes20(ciphertextHex);
|
|
11973
11045
|
const cipher = xchacha20poly13054(derivedKey, nonce);
|
|
11974
11046
|
let plaintext;
|
|
11975
11047
|
try {
|
|
@@ -12058,11 +11130,11 @@ var PrivateVoting = class {
|
|
|
12058
11130
|
*/
|
|
12059
11131
|
deriveEncryptionKey(key, proposalId) {
|
|
12060
11132
|
const keyHex = key.startsWith("0x") ? key.slice(2) : key;
|
|
12061
|
-
const keyBytes =
|
|
11133
|
+
const keyBytes = hexToBytes20(keyHex);
|
|
12062
11134
|
try {
|
|
12063
11135
|
const salt = utf8ToBytes5(VOTE_ENCRYPTION_DOMAIN);
|
|
12064
11136
|
const info = utf8ToBytes5(proposalId);
|
|
12065
|
-
return hkdf3(
|
|
11137
|
+
return hkdf3(sha25619, keyBytes, salt, info, 32);
|
|
12066
11138
|
} finally {
|
|
12067
11139
|
secureWipe(keyBytes);
|
|
12068
11140
|
}
|
|
@@ -12207,21 +11279,21 @@ var PrivateVoting = class {
|
|
|
12207
11279
|
const blindings = {};
|
|
12208
11280
|
for (const [choice, weights] of Object.entries(votesByChoice)) {
|
|
12209
11281
|
const totalWeight = weights.reduce((sum, w) => sum + w, 0n);
|
|
12210
|
-
const { commitment, blinding } = commit(totalWeight,
|
|
11282
|
+
const { commitment, blinding } = commit(totalWeight, hexToBytes20(generateBlinding().slice(2)));
|
|
12211
11283
|
tallies[choice] = commitment;
|
|
12212
11284
|
blindings[choice] = blinding;
|
|
12213
11285
|
}
|
|
12214
11286
|
const encryptedBlindings = {};
|
|
12215
11287
|
for (const [choice, blinding] of Object.entries(blindings)) {
|
|
12216
|
-
const nonce =
|
|
11288
|
+
const nonce = randomBytes14(NONCE_SIZE2);
|
|
12217
11289
|
const derivedKey = this.deriveEncryptionKey(decryptionKey, `${proposalId}-tally-${choice}`);
|
|
12218
11290
|
try {
|
|
12219
11291
|
const cipher = xchacha20poly13054(derivedKey, nonce);
|
|
12220
|
-
const blindingBytes =
|
|
11292
|
+
const blindingBytes = hexToBytes20(blinding.slice(2));
|
|
12221
11293
|
const ciphertext = cipher.encrypt(blindingBytes);
|
|
12222
11294
|
encryptedBlindings[choice] = {
|
|
12223
|
-
ciphertext: `0x${
|
|
12224
|
-
nonce: `0x${
|
|
11295
|
+
ciphertext: `0x${bytesToHex26(ciphertext)}`,
|
|
11296
|
+
nonce: `0x${bytesToHex26(nonce)}`
|
|
12225
11297
|
};
|
|
12226
11298
|
} finally {
|
|
12227
11299
|
secureWipe(derivedKey);
|
|
@@ -12314,9 +11386,9 @@ var PrivateVoting = class {
|
|
|
12314
11386
|
}
|
|
12315
11387
|
let reconstructedKey = null;
|
|
12316
11388
|
try {
|
|
12317
|
-
reconstructedKey =
|
|
11389
|
+
reconstructedKey = hexToBytes20(decryptionShares[0].share.slice(2));
|
|
12318
11390
|
for (let i = 1; i < decryptionShares.length; i++) {
|
|
12319
|
-
const shareBytes =
|
|
11391
|
+
const shareBytes = hexToBytes20(decryptionShares[i].share.slice(2));
|
|
12320
11392
|
if (shareBytes.length !== reconstructedKey.length) {
|
|
12321
11393
|
throw new ValidationError(
|
|
12322
11394
|
"all decryption shares must have the same length",
|
|
@@ -12329,7 +11401,7 @@ var PrivateVoting = class {
|
|
|
12329
11401
|
reconstructedKey[j] ^= shareBytes[j];
|
|
12330
11402
|
}
|
|
12331
11403
|
}
|
|
12332
|
-
const reconstructedKeyHex = `0x${
|
|
11404
|
+
const reconstructedKeyHex = `0x${bytesToHex26(reconstructedKey)}`;
|
|
12333
11405
|
const results = {};
|
|
12334
11406
|
for (const [choice, commitmentPoint] of Object.entries(tally.tallies)) {
|
|
12335
11407
|
const encBlinding = tally.encryptedBlindings[choice];
|
|
@@ -12346,11 +11418,11 @@ var PrivateVoting = class {
|
|
|
12346
11418
|
);
|
|
12347
11419
|
let blindingFactor;
|
|
12348
11420
|
try {
|
|
12349
|
-
const nonceBytes =
|
|
12350
|
-
const ciphertextBytes =
|
|
11421
|
+
const nonceBytes = hexToBytes20(encBlinding.nonce.slice(2));
|
|
11422
|
+
const ciphertextBytes = hexToBytes20(encBlinding.ciphertext.slice(2));
|
|
12351
11423
|
const cipher = xchacha20poly13054(derivedKey, nonceBytes);
|
|
12352
11424
|
const blindingBytes = cipher.decrypt(ciphertextBytes);
|
|
12353
|
-
blindingFactor = `0x${
|
|
11425
|
+
blindingFactor = `0x${bytesToHex26(blindingBytes)}`;
|
|
12354
11426
|
} catch (e) {
|
|
12355
11427
|
throw new CryptoError(
|
|
12356
11428
|
"failed to decrypt blinding factor",
|
|
@@ -12370,7 +11442,7 @@ var PrivateVoting = class {
|
|
|
12370
11442
|
try {
|
|
12371
11443
|
const { commitment: testCommit } = commit(
|
|
12372
11444
|
value,
|
|
12373
|
-
|
|
11445
|
+
hexToBytes20(blindingFactor.slice(2))
|
|
12374
11446
|
);
|
|
12375
11447
|
if (testCommit === commitmentPoint) {
|
|
12376
11448
|
results[choice] = value;
|
|
@@ -12570,9 +11642,9 @@ function createPrivateVoting() {
|
|
|
12570
11642
|
}
|
|
12571
11643
|
|
|
12572
11644
|
// src/nft/private-nft.ts
|
|
12573
|
-
import { sha256 as
|
|
12574
|
-
import { secp256k1 as
|
|
12575
|
-
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";
|
|
12576
11648
|
var PrivateNFT = class {
|
|
12577
11649
|
/**
|
|
12578
11650
|
* Create a private ownership record for an NFT
|
|
@@ -12658,23 +11730,23 @@ var PrivateNFT = class {
|
|
|
12658
11730
|
const { ownership, challenge, stealthPrivateKey } = params;
|
|
12659
11731
|
try {
|
|
12660
11732
|
const message = this.createProofMessage(ownership, challenge);
|
|
12661
|
-
const messageHash =
|
|
12662
|
-
const privateKeyBytes =
|
|
12663
|
-
const signature =
|
|
11733
|
+
const messageHash = sha25620(new TextEncoder().encode(message));
|
|
11734
|
+
const privateKeyBytes = hexToBytes21(stealthPrivateKey.slice(2));
|
|
11735
|
+
const signature = secp256k17.sign(messageHash, privateKeyBytes);
|
|
12664
11736
|
const zkProof = {
|
|
12665
11737
|
type: "ownership",
|
|
12666
|
-
proof: `0x${
|
|
11738
|
+
proof: `0x${bytesToHex27(signature.toCompactRawBytes())}`,
|
|
12667
11739
|
publicInputs: [
|
|
12668
|
-
`0x${
|
|
11740
|
+
`0x${bytesToHex27(messageHash)}`
|
|
12669
11741
|
]
|
|
12670
11742
|
};
|
|
12671
|
-
const stealthHashBytes =
|
|
11743
|
+
const stealthHashBytes = sha25620(hexToBytes21(ownership.ownerStealth.address.slice(2)));
|
|
12672
11744
|
return {
|
|
12673
11745
|
nftContract: ownership.nftContract,
|
|
12674
11746
|
tokenId: ownership.tokenId,
|
|
12675
11747
|
challenge,
|
|
12676
11748
|
proof: zkProof,
|
|
12677
|
-
stealthHash: `0x${
|
|
11749
|
+
stealthHash: `0x${bytesToHex27(stealthHashBytes)}`,
|
|
12678
11750
|
timestamp: Date.now()
|
|
12679
11751
|
};
|
|
12680
11752
|
} catch (e) {
|
|
@@ -12716,9 +11788,9 @@ var PrivateNFT = class {
|
|
|
12716
11788
|
verifyOwnership(proof) {
|
|
12717
11789
|
try {
|
|
12718
11790
|
this.validateOwnershipProof(proof);
|
|
12719
|
-
const signatureBytes =
|
|
12720
|
-
const signature =
|
|
12721
|
-
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));
|
|
12722
11794
|
if (signatureBytes.length !== 64) {
|
|
12723
11795
|
return {
|
|
12724
11796
|
valid: false,
|
|
@@ -12815,12 +11887,12 @@ var PrivateNFT = class {
|
|
|
12815
11887
|
chain: nft.chain,
|
|
12816
11888
|
timestamp: Date.now()
|
|
12817
11889
|
};
|
|
12818
|
-
const previousOwnerHashBytes =
|
|
11890
|
+
const previousOwnerHashBytes = sha25620(hexToBytes21(nft.ownerStealth.address.slice(2)));
|
|
12819
11891
|
const transfer = {
|
|
12820
11892
|
nftContract: nft.nftContract,
|
|
12821
11893
|
tokenId: nft.tokenId,
|
|
12822
11894
|
newOwnerStealth,
|
|
12823
|
-
previousOwnerHash: `0x${
|
|
11895
|
+
previousOwnerHash: `0x${bytesToHex27(previousOwnerHashBytes)}`,
|
|
12824
11896
|
chain: nft.chain,
|
|
12825
11897
|
timestamp: Date.now()
|
|
12826
11898
|
};
|
|
@@ -12887,8 +11959,8 @@ var PrivateNFT = class {
|
|
|
12887
11959
|
);
|
|
12888
11960
|
}
|
|
12889
11961
|
const ownedNFTs = [];
|
|
12890
|
-
const scanKeyHex = `0x${
|
|
12891
|
-
const viewingKeyHex = `0x${
|
|
11962
|
+
const scanKeyHex = `0x${bytesToHex27(scanKey)}`;
|
|
11963
|
+
const viewingKeyHex = `0x${bytesToHex27(viewingKey)}`;
|
|
12892
11964
|
for (const transfer of transfers) {
|
|
12893
11965
|
try {
|
|
12894
11966
|
if (!transfer || typeof transfer !== "object") {
|
|
@@ -15754,7 +14826,7 @@ var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
|
15754
14826
|
* @see https://ethereum.org/en/developers/docs/data-structures-and-encoding/rlp/
|
|
15755
14827
|
*/
|
|
15756
14828
|
buildRawEthereumTx(tx) {
|
|
15757
|
-
const
|
|
14829
|
+
const hexToBytes22 = (hex) => {
|
|
15758
14830
|
if (!hex || hex === "0x" || hex === "0x0" || hex === "0x00") {
|
|
15759
14831
|
return new Uint8Array(0);
|
|
15760
14832
|
}
|
|
@@ -15771,21 +14843,21 @@ var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
|
15771
14843
|
const isEIP1559 = tx.maxFeePerGas !== void 0 && tx.maxPriorityFeePerGas !== void 0;
|
|
15772
14844
|
if (isEIP1559) {
|
|
15773
14845
|
const txData = [
|
|
15774
|
-
|
|
14846
|
+
hexToBytes22(`0x${tx.chainId.toString(16)}`),
|
|
15775
14847
|
// chainId
|
|
15776
|
-
|
|
14848
|
+
hexToBytes22(tx.nonce),
|
|
15777
14849
|
// nonce
|
|
15778
|
-
|
|
14850
|
+
hexToBytes22(tx.maxPriorityFeePerGas),
|
|
15779
14851
|
// maxPriorityFeePerGas
|
|
15780
|
-
|
|
14852
|
+
hexToBytes22(tx.maxFeePerGas),
|
|
15781
14853
|
// maxFeePerGas
|
|
15782
|
-
|
|
14854
|
+
hexToBytes22(tx.gasLimit),
|
|
15783
14855
|
// gasLimit
|
|
15784
|
-
|
|
14856
|
+
hexToBytes22(tx.to),
|
|
15785
14857
|
// to
|
|
15786
|
-
|
|
14858
|
+
hexToBytes22(tx.value),
|
|
15787
14859
|
// value
|
|
15788
|
-
|
|
14860
|
+
hexToBytes22(tx.data),
|
|
15789
14861
|
// data
|
|
15790
14862
|
[]
|
|
15791
14863
|
// accessList (empty)
|
|
@@ -15804,19 +14876,19 @@ var LedgerWalletAdapter = class extends BaseWalletAdapter {
|
|
|
15804
14876
|
);
|
|
15805
14877
|
}
|
|
15806
14878
|
const txData = [
|
|
15807
|
-
|
|
14879
|
+
hexToBytes22(tx.nonce),
|
|
15808
14880
|
// nonce
|
|
15809
|
-
|
|
14881
|
+
hexToBytes22(tx.gasPrice),
|
|
15810
14882
|
// gasPrice
|
|
15811
|
-
|
|
14883
|
+
hexToBytes22(tx.gasLimit),
|
|
15812
14884
|
// gasLimit
|
|
15813
|
-
|
|
14885
|
+
hexToBytes22(tx.to),
|
|
15814
14886
|
// to
|
|
15815
|
-
|
|
14887
|
+
hexToBytes22(tx.value),
|
|
15816
14888
|
// value
|
|
15817
|
-
|
|
14889
|
+
hexToBytes22(tx.data),
|
|
15818
14890
|
// data
|
|
15819
|
-
|
|
14891
|
+
hexToBytes22(`0x${tx.chainId.toString(16)}`),
|
|
15820
14892
|
// v (chainId for EIP-155)
|
|
15821
14893
|
new Uint8Array(0),
|
|
15822
14894
|
// r (empty for unsigned)
|
|
@@ -16332,7 +15404,7 @@ function createTrezorAdapter(config) {
|
|
|
16332
15404
|
|
|
16333
15405
|
// src/wallet/hardware/mock.ts
|
|
16334
15406
|
import { WalletErrorCode as WalletErrorCode17 } from "@sip-protocol/types";
|
|
16335
|
-
import { bytesToHex as
|
|
15407
|
+
import { bytesToHex as bytesToHex28, randomBytes as randomBytes15 } from "@noble/hashes/utils";
|
|
16336
15408
|
var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
16337
15409
|
chain;
|
|
16338
15410
|
name = "mock-ledger";
|
|
@@ -16577,15 +15649,15 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
16577
15649
|
}
|
|
16578
15650
|
}
|
|
16579
15651
|
generateMockAddress(index) {
|
|
16580
|
-
const bytes =
|
|
15652
|
+
const bytes = randomBytes15(20);
|
|
16581
15653
|
bytes[0] = index;
|
|
16582
|
-
return `0x${
|
|
15654
|
+
return `0x${bytesToHex28(bytes)}`;
|
|
16583
15655
|
}
|
|
16584
15656
|
generateMockPublicKey(index) {
|
|
16585
|
-
const bytes =
|
|
15657
|
+
const bytes = randomBytes15(33);
|
|
16586
15658
|
bytes[0] = 2;
|
|
16587
15659
|
bytes[1] = index;
|
|
16588
|
-
return `0x${
|
|
15660
|
+
return `0x${bytesToHex28(bytes)}`;
|
|
16589
15661
|
}
|
|
16590
15662
|
generateMockSignature(data) {
|
|
16591
15663
|
const sig = new Uint8Array(65);
|
|
@@ -16594,7 +15666,7 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
16594
15666
|
sig[32 + i] = (data[i % data.length] ?? 0) ^ i * 11;
|
|
16595
15667
|
}
|
|
16596
15668
|
sig[64] = 27;
|
|
16597
|
-
return `0x${
|
|
15669
|
+
return `0x${bytesToHex28(sig)}`;
|
|
16598
15670
|
}
|
|
16599
15671
|
delay(ms) {
|
|
16600
15672
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -16783,15 +15855,15 @@ var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
|
16783
15855
|
}
|
|
16784
15856
|
}
|
|
16785
15857
|
generateMockAddress(index) {
|
|
16786
|
-
const bytes =
|
|
15858
|
+
const bytes = randomBytes15(20);
|
|
16787
15859
|
bytes[0] = index + 100;
|
|
16788
|
-
return `0x${
|
|
15860
|
+
return `0x${bytesToHex28(bytes)}`;
|
|
16789
15861
|
}
|
|
16790
15862
|
generateMockPublicKey(index) {
|
|
16791
|
-
const bytes =
|
|
15863
|
+
const bytes = randomBytes15(33);
|
|
16792
15864
|
bytes[0] = 3;
|
|
16793
15865
|
bytes[1] = index + 100;
|
|
16794
|
-
return `0x${
|
|
15866
|
+
return `0x${bytesToHex28(bytes)}`;
|
|
16795
15867
|
}
|
|
16796
15868
|
generateMockSignature(data) {
|
|
16797
15869
|
const sig = new Uint8Array(65);
|
|
@@ -16800,7 +15872,7 @@ var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
|
16800
15872
|
sig[32 + i] = (data[i % data.length] ?? 0) ^ i * 17;
|
|
16801
15873
|
}
|
|
16802
15874
|
sig[64] = 28;
|
|
16803
|
-
return `0x${
|
|
15875
|
+
return `0x${bytesToHex28(sig)}`;
|
|
16804
15876
|
}
|
|
16805
15877
|
delay(ms) {
|
|
16806
15878
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
@@ -16816,49 +15888,55 @@ function createMockTrezorAdapter(config) {
|
|
|
16816
15888
|
// src/wallet/index.ts
|
|
16817
15889
|
import { WalletErrorCode as WalletErrorCode18 } from "@sip-protocol/types";
|
|
16818
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
|
+
|
|
16819
15939
|
export {
|
|
16820
|
-
isValidChainId,
|
|
16821
|
-
isValidPrivacyLevel,
|
|
16822
|
-
isValidHex,
|
|
16823
|
-
isValidHexLength,
|
|
16824
|
-
isValidAmount,
|
|
16825
|
-
isNonNegativeAmount,
|
|
16826
|
-
isValidSlippage,
|
|
16827
|
-
isValidStealthMetaAddress,
|
|
16828
|
-
isValidCompressedPublicKey,
|
|
16829
|
-
isValidEd25519PublicKey,
|
|
16830
|
-
isValidPrivateKey,
|
|
16831
|
-
validateAsset,
|
|
16832
|
-
validateIntentInput,
|
|
16833
|
-
validateIntentOutput,
|
|
16834
|
-
validateCreateIntentParams,
|
|
16835
|
-
validateViewingKey,
|
|
16836
|
-
isValidScalar,
|
|
16837
|
-
validateScalar,
|
|
16838
|
-
secureWipe,
|
|
16839
|
-
withSecureBuffer,
|
|
16840
|
-
withSecureBufferSync,
|
|
16841
|
-
secureWipeAll,
|
|
16842
|
-
generateStealthMetaAddress,
|
|
16843
|
-
generateStealthAddress,
|
|
16844
|
-
deriveStealthPrivateKey,
|
|
16845
|
-
checkStealthAddress,
|
|
16846
|
-
encodeStealthMetaAddress,
|
|
16847
|
-
decodeStealthMetaAddress,
|
|
16848
|
-
publicKeyToEthAddress,
|
|
16849
|
-
isEd25519Chain,
|
|
16850
|
-
getCurveForChain,
|
|
16851
|
-
generateEd25519StealthMetaAddress,
|
|
16852
|
-
generateEd25519StealthAddress,
|
|
16853
|
-
deriveEd25519StealthPrivateKey,
|
|
16854
|
-
checkEd25519StealthAddress,
|
|
16855
|
-
ed25519PublicKeyToSolanaAddress,
|
|
16856
|
-
isValidSolanaAddress,
|
|
16857
|
-
solanaAddressToEd25519PublicKey,
|
|
16858
|
-
ed25519PublicKeyToNearAddress,
|
|
16859
|
-
nearAddressToEd25519PublicKey,
|
|
16860
|
-
isValidNearImplicitAddress,
|
|
16861
|
-
isValidNearAccountId,
|
|
16862
15940
|
commit,
|
|
16863
15941
|
verifyOpening,
|
|
16864
15942
|
commitZero,
|
|
@@ -16926,8 +16004,8 @@ export {
|
|
|
16926
16004
|
supportsWASMSimd,
|
|
16927
16005
|
supportsWASMBulkMemory,
|
|
16928
16006
|
checkMobileWASMCompatibility,
|
|
16929
|
-
|
|
16930
|
-
|
|
16007
|
+
hexToBytes8 as hexToBytes,
|
|
16008
|
+
bytesToHex10 as bytesToHex,
|
|
16931
16009
|
isBrowser,
|
|
16932
16010
|
supportsWebWorkers,
|
|
16933
16011
|
supportsSharedArrayBuffer,
|
|
@@ -17067,6 +16145,10 @@ export {
|
|
|
17067
16145
|
createMockLedgerAdapter,
|
|
17068
16146
|
createMockTrezorAdapter,
|
|
17069
16147
|
WalletErrorCode18 as WalletErrorCode,
|
|
16148
|
+
SolanaSameChainExecutor,
|
|
16149
|
+
createSameChainExecutor,
|
|
16150
|
+
isSameChainSupported,
|
|
16151
|
+
getSupportedSameChainChains,
|
|
17070
16152
|
PrivacyLevel11 as PrivacyLevel,
|
|
17071
16153
|
IntentStatus4 as IntentStatus,
|
|
17072
16154
|
SIP_VERSION3 as SIP_VERSION,
|