@sip-protocol/sdk 0.2.0 → 0.2.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 +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +944 -944
- package/dist/browser.mjs +607 -2
- package/dist/chunk-4VJHI66K.mjs +12120 -0
- package/dist/index.d.mts +39 -39
- package/dist/index.d.ts +39 -39
- package/dist/index.js +3 -608
- package/dist/index.mjs +1 -3
- package/package.json +1 -4
- package/src/browser.ts +4 -2
- package/src/index.ts +3 -2
- package/src/proofs/index.ts +10 -6
package/dist/browser.js
CHANGED
|
@@ -5097,609 +5097,6 @@ function getBrowserInfo() {
|
|
|
5097
5097
|
};
|
|
5098
5098
|
}
|
|
5099
5099
|
|
|
5100
|
-
// src/proofs/browser.ts
|
|
5101
|
-
var import_noir_js2 = require("@noir-lang/noir_js");
|
|
5102
|
-
var import_bb2 = require("@aztec/bb.js");
|
|
5103
|
-
var import_secp256k14 = require("@noble/curves/secp256k1");
|
|
5104
|
-
var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
5105
|
-
framework = "noir";
|
|
5106
|
-
_isReady = false;
|
|
5107
|
-
config;
|
|
5108
|
-
// Circuit instances
|
|
5109
|
-
fundingNoir = null;
|
|
5110
|
-
fundingBackend = null;
|
|
5111
|
-
validityNoir = null;
|
|
5112
|
-
validityBackend = null;
|
|
5113
|
-
fulfillmentNoir = null;
|
|
5114
|
-
fulfillmentBackend = null;
|
|
5115
|
-
// Worker instance (optional)
|
|
5116
|
-
worker = null;
|
|
5117
|
-
workerPending = /* @__PURE__ */ new Map();
|
|
5118
|
-
constructor(config = {}) {
|
|
5119
|
-
this.config = {
|
|
5120
|
-
useWorker: config.useWorker ?? true,
|
|
5121
|
-
verbose: config.verbose ?? false,
|
|
5122
|
-
oraclePublicKey: config.oraclePublicKey ?? void 0,
|
|
5123
|
-
timeout: config.timeout ?? 6e4
|
|
5124
|
-
};
|
|
5125
|
-
if (!isBrowser()) {
|
|
5126
|
-
console.warn(
|
|
5127
|
-
"[BrowserNoirProvider] Not running in browser environment. Consider using NoirProofProvider for Node.js."
|
|
5128
|
-
);
|
|
5129
|
-
}
|
|
5130
|
-
}
|
|
5131
|
-
get isReady() {
|
|
5132
|
-
return this._isReady;
|
|
5133
|
-
}
|
|
5134
|
-
/**
|
|
5135
|
-
* Get browser environment info
|
|
5136
|
-
*/
|
|
5137
|
-
static getBrowserInfo() {
|
|
5138
|
-
return getBrowserInfo();
|
|
5139
|
-
}
|
|
5140
|
-
/**
|
|
5141
|
-
* Check if browser supports all required features
|
|
5142
|
-
*/
|
|
5143
|
-
static checkBrowserSupport() {
|
|
5144
|
-
const missing = [];
|
|
5145
|
-
if (!isBrowser()) {
|
|
5146
|
-
missing.push("browser environment");
|
|
5147
|
-
}
|
|
5148
|
-
if (typeof WebAssembly === "undefined") {
|
|
5149
|
-
missing.push("WebAssembly");
|
|
5150
|
-
}
|
|
5151
|
-
if (!supportsSharedArrayBuffer()) {
|
|
5152
|
-
missing.push("SharedArrayBuffer (requires COOP/COEP headers)");
|
|
5153
|
-
}
|
|
5154
|
-
return {
|
|
5155
|
-
supported: missing.length === 0,
|
|
5156
|
-
missing
|
|
5157
|
-
};
|
|
5158
|
-
}
|
|
5159
|
-
/**
|
|
5160
|
-
* Derive secp256k1 public key coordinates from a private key
|
|
5161
|
-
*/
|
|
5162
|
-
static derivePublicKey(privateKey) {
|
|
5163
|
-
const uncompressedPubKey = import_secp256k14.secp256k1.getPublicKey(privateKey, false);
|
|
5164
|
-
const x = Array.from(uncompressedPubKey.slice(1, 33));
|
|
5165
|
-
const y = Array.from(uncompressedPubKey.slice(33, 65));
|
|
5166
|
-
return { x, y };
|
|
5167
|
-
}
|
|
5168
|
-
/**
|
|
5169
|
-
* Initialize the browser provider
|
|
5170
|
-
*
|
|
5171
|
-
* Loads WASM and circuit artifacts. This should be called before any
|
|
5172
|
-
* proof generation. Consider showing a loading indicator during init.
|
|
5173
|
-
*
|
|
5174
|
-
* @param onProgress - Optional progress callback
|
|
5175
|
-
*/
|
|
5176
|
-
async initialize(onProgress) {
|
|
5177
|
-
if (this._isReady) {
|
|
5178
|
-
return;
|
|
5179
|
-
}
|
|
5180
|
-
const { supported, missing } = _BrowserNoirProvider.checkBrowserSupport();
|
|
5181
|
-
if (!supported) {
|
|
5182
|
-
throw new ProofError(
|
|
5183
|
-
`Browser missing required features: ${missing.join(", ")}`,
|
|
5184
|
-
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
5185
|
-
);
|
|
5186
|
-
}
|
|
5187
|
-
try {
|
|
5188
|
-
onProgress?.({
|
|
5189
|
-
stage: "initializing",
|
|
5190
|
-
percent: 0,
|
|
5191
|
-
message: "Loading WASM runtime..."
|
|
5192
|
-
});
|
|
5193
|
-
if (this.config.verbose) {
|
|
5194
|
-
console.log("[BrowserNoirProvider] Initializing...");
|
|
5195
|
-
console.log("[BrowserNoirProvider] Browser info:", getBrowserInfo());
|
|
5196
|
-
}
|
|
5197
|
-
const fundingCircuit = funding_proof_default;
|
|
5198
|
-
const validityCircuit = validity_proof_default;
|
|
5199
|
-
const fulfillmentCircuit = fulfillment_proof_default;
|
|
5200
|
-
onProgress?.({
|
|
5201
|
-
stage: "initializing",
|
|
5202
|
-
percent: 20,
|
|
5203
|
-
message: "Creating proof backends..."
|
|
5204
|
-
});
|
|
5205
|
-
this.fundingBackend = new import_bb2.UltraHonkBackend(fundingCircuit.bytecode);
|
|
5206
|
-
this.validityBackend = new import_bb2.UltraHonkBackend(validityCircuit.bytecode);
|
|
5207
|
-
this.fulfillmentBackend = new import_bb2.UltraHonkBackend(fulfillmentCircuit.bytecode);
|
|
5208
|
-
onProgress?.({
|
|
5209
|
-
stage: "initializing",
|
|
5210
|
-
percent: 60,
|
|
5211
|
-
message: "Initializing Noir circuits..."
|
|
5212
|
-
});
|
|
5213
|
-
this.fundingNoir = new import_noir_js2.Noir(fundingCircuit);
|
|
5214
|
-
this.validityNoir = new import_noir_js2.Noir(validityCircuit);
|
|
5215
|
-
this.fulfillmentNoir = new import_noir_js2.Noir(fulfillmentCircuit);
|
|
5216
|
-
onProgress?.({
|
|
5217
|
-
stage: "initializing",
|
|
5218
|
-
percent: 90,
|
|
5219
|
-
message: "Setting up worker..."
|
|
5220
|
-
});
|
|
5221
|
-
if (this.config.useWorker && supportsWebWorkers()) {
|
|
5222
|
-
await this.initializeWorker();
|
|
5223
|
-
}
|
|
5224
|
-
this._isReady = true;
|
|
5225
|
-
onProgress?.({
|
|
5226
|
-
stage: "complete",
|
|
5227
|
-
percent: 100,
|
|
5228
|
-
message: "Ready for proof generation"
|
|
5229
|
-
});
|
|
5230
|
-
if (this.config.verbose) {
|
|
5231
|
-
console.log("[BrowserNoirProvider] Initialization complete");
|
|
5232
|
-
}
|
|
5233
|
-
} catch (error) {
|
|
5234
|
-
throw new ProofError(
|
|
5235
|
-
`Failed to initialize BrowserNoirProvider: ${error instanceof Error ? error.message : String(error)}`,
|
|
5236
|
-
"SIP_4003" /* PROOF_NOT_IMPLEMENTED */,
|
|
5237
|
-
{ context: { error } }
|
|
5238
|
-
);
|
|
5239
|
-
}
|
|
5240
|
-
}
|
|
5241
|
-
/**
|
|
5242
|
-
* Initialize Web Worker for off-main-thread proof generation
|
|
5243
|
-
*/
|
|
5244
|
-
async initializeWorker() {
|
|
5245
|
-
if (this.config.verbose) {
|
|
5246
|
-
console.log("[BrowserNoirProvider] Worker support: using async main-thread");
|
|
5247
|
-
}
|
|
5248
|
-
}
|
|
5249
|
-
/**
|
|
5250
|
-
* Generate a Funding Proof
|
|
5251
|
-
*
|
|
5252
|
-
* Proves: balance >= minimumRequired without revealing balance
|
|
5253
|
-
*
|
|
5254
|
-
* @param params - Funding proof parameters
|
|
5255
|
-
* @param onProgress - Optional progress callback
|
|
5256
|
-
*/
|
|
5257
|
-
async generateFundingProof(params, onProgress) {
|
|
5258
|
-
this.ensureReady();
|
|
5259
|
-
if (!this.fundingNoir || !this.fundingBackend) {
|
|
5260
|
-
throw new ProofGenerationError("funding", "Funding circuit not initialized");
|
|
5261
|
-
}
|
|
5262
|
-
try {
|
|
5263
|
-
onProgress?.({
|
|
5264
|
-
stage: "witness",
|
|
5265
|
-
percent: 10,
|
|
5266
|
-
message: "Preparing witness inputs..."
|
|
5267
|
-
});
|
|
5268
|
-
const { commitmentHash, blindingField } = await this.computeCommitmentHash(
|
|
5269
|
-
params.balance,
|
|
5270
|
-
params.blindingFactor,
|
|
5271
|
-
params.assetId
|
|
5272
|
-
);
|
|
5273
|
-
const witnessInputs = {
|
|
5274
|
-
commitment_hash: commitmentHash,
|
|
5275
|
-
minimum_required: params.minimumRequired.toString(),
|
|
5276
|
-
asset_id: this.assetIdToField(params.assetId),
|
|
5277
|
-
balance: params.balance.toString(),
|
|
5278
|
-
blinding: blindingField
|
|
5279
|
-
};
|
|
5280
|
-
onProgress?.({
|
|
5281
|
-
stage: "witness",
|
|
5282
|
-
percent: 30,
|
|
5283
|
-
message: "Generating witness..."
|
|
5284
|
-
});
|
|
5285
|
-
const { witness } = await this.fundingNoir.execute(witnessInputs);
|
|
5286
|
-
onProgress?.({
|
|
5287
|
-
stage: "proving",
|
|
5288
|
-
percent: 50,
|
|
5289
|
-
message: "Generating proof (this may take a moment)..."
|
|
5290
|
-
});
|
|
5291
|
-
const proofData = await this.fundingBackend.generateProof(witness);
|
|
5292
|
-
onProgress?.({
|
|
5293
|
-
stage: "complete",
|
|
5294
|
-
percent: 100,
|
|
5295
|
-
message: "Proof generated successfully"
|
|
5296
|
-
});
|
|
5297
|
-
const publicInputs = [
|
|
5298
|
-
`0x${commitmentHash}`,
|
|
5299
|
-
`0x${params.minimumRequired.toString(16).padStart(16, "0")}`,
|
|
5300
|
-
`0x${this.assetIdToField(params.assetId)}`
|
|
5301
|
-
];
|
|
5302
|
-
const proof = {
|
|
5303
|
-
type: "funding",
|
|
5304
|
-
proof: `0x${bytesToHex7(proofData.proof)}`,
|
|
5305
|
-
publicInputs
|
|
5306
|
-
};
|
|
5307
|
-
return { proof, publicInputs };
|
|
5308
|
-
} catch (error) {
|
|
5309
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
5310
|
-
throw new ProofGenerationError(
|
|
5311
|
-
"funding",
|
|
5312
|
-
`Failed to generate funding proof: ${message}`,
|
|
5313
|
-
error instanceof Error ? error : void 0
|
|
5314
|
-
);
|
|
5315
|
-
}
|
|
5316
|
-
}
|
|
5317
|
-
/**
|
|
5318
|
-
* Generate a Validity Proof
|
|
5319
|
-
*
|
|
5320
|
-
* Proves: Intent is authorized by sender without revealing identity
|
|
5321
|
-
*/
|
|
5322
|
-
async generateValidityProof(params, onProgress) {
|
|
5323
|
-
this.ensureReady();
|
|
5324
|
-
if (!this.validityNoir || !this.validityBackend) {
|
|
5325
|
-
throw new ProofGenerationError("validity", "Validity circuit not initialized");
|
|
5326
|
-
}
|
|
5327
|
-
try {
|
|
5328
|
-
onProgress?.({
|
|
5329
|
-
stage: "witness",
|
|
5330
|
-
percent: 10,
|
|
5331
|
-
message: "Preparing validity witness..."
|
|
5332
|
-
});
|
|
5333
|
-
const intentHashField = this.hexToField(params.intentHash);
|
|
5334
|
-
const senderAddressField = this.hexToField(params.senderAddress);
|
|
5335
|
-
const senderBlindingField = this.bytesToField(params.senderBlinding);
|
|
5336
|
-
const senderSecretField = this.bytesToField(params.senderSecret);
|
|
5337
|
-
const nonceField = this.bytesToField(params.nonce);
|
|
5338
|
-
const { commitmentX, commitmentY } = await this.computeSenderCommitment(
|
|
5339
|
-
senderAddressField,
|
|
5340
|
-
senderBlindingField
|
|
5341
|
-
);
|
|
5342
|
-
const nullifier = await this.computeNullifier(senderSecretField, intentHashField, nonceField);
|
|
5343
|
-
const signature = Array.from(params.authorizationSignature);
|
|
5344
|
-
const messageHash = this.fieldToBytes32(intentHashField);
|
|
5345
|
-
let pubKeyX;
|
|
5346
|
-
let pubKeyY;
|
|
5347
|
-
if (params.senderPublicKey) {
|
|
5348
|
-
pubKeyX = Array.from(params.senderPublicKey.x);
|
|
5349
|
-
pubKeyY = Array.from(params.senderPublicKey.y);
|
|
5350
|
-
} else {
|
|
5351
|
-
const coords = this.getPublicKeyCoordinates(params.senderSecret);
|
|
5352
|
-
pubKeyX = coords.x;
|
|
5353
|
-
pubKeyY = coords.y;
|
|
5354
|
-
}
|
|
5355
|
-
const witnessInputs = {
|
|
5356
|
-
intent_hash: intentHashField,
|
|
5357
|
-
sender_commitment_x: commitmentX,
|
|
5358
|
-
sender_commitment_y: commitmentY,
|
|
5359
|
-
nullifier,
|
|
5360
|
-
timestamp: params.timestamp.toString(),
|
|
5361
|
-
expiry: params.expiry.toString(),
|
|
5362
|
-
sender_address: senderAddressField,
|
|
5363
|
-
sender_blinding: senderBlindingField,
|
|
5364
|
-
sender_secret: senderSecretField,
|
|
5365
|
-
pub_key_x: pubKeyX,
|
|
5366
|
-
pub_key_y: pubKeyY,
|
|
5367
|
-
signature,
|
|
5368
|
-
message_hash: messageHash,
|
|
5369
|
-
nonce: nonceField
|
|
5370
|
-
};
|
|
5371
|
-
onProgress?.({
|
|
5372
|
-
stage: "witness",
|
|
5373
|
-
percent: 30,
|
|
5374
|
-
message: "Generating witness..."
|
|
5375
|
-
});
|
|
5376
|
-
const { witness } = await this.validityNoir.execute(witnessInputs);
|
|
5377
|
-
onProgress?.({
|
|
5378
|
-
stage: "proving",
|
|
5379
|
-
percent: 50,
|
|
5380
|
-
message: "Generating validity proof..."
|
|
5381
|
-
});
|
|
5382
|
-
const proofData = await this.validityBackend.generateProof(witness);
|
|
5383
|
-
onProgress?.({
|
|
5384
|
-
stage: "complete",
|
|
5385
|
-
percent: 100,
|
|
5386
|
-
message: "Validity proof generated"
|
|
5387
|
-
});
|
|
5388
|
-
const publicInputs = [
|
|
5389
|
-
`0x${intentHashField}`,
|
|
5390
|
-
`0x${commitmentX}`,
|
|
5391
|
-
`0x${commitmentY}`,
|
|
5392
|
-
`0x${nullifier}`,
|
|
5393
|
-
`0x${params.timestamp.toString(16).padStart(16, "0")}`,
|
|
5394
|
-
`0x${params.expiry.toString(16).padStart(16, "0")}`
|
|
5395
|
-
];
|
|
5396
|
-
const proof = {
|
|
5397
|
-
type: "validity",
|
|
5398
|
-
proof: `0x${bytesToHex7(proofData.proof)}`,
|
|
5399
|
-
publicInputs
|
|
5400
|
-
};
|
|
5401
|
-
return { proof, publicInputs };
|
|
5402
|
-
} catch (error) {
|
|
5403
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
5404
|
-
throw new ProofGenerationError(
|
|
5405
|
-
"validity",
|
|
5406
|
-
`Failed to generate validity proof: ${message}`,
|
|
5407
|
-
error instanceof Error ? error : void 0
|
|
5408
|
-
);
|
|
5409
|
-
}
|
|
5410
|
-
}
|
|
5411
|
-
/**
|
|
5412
|
-
* Generate a Fulfillment Proof
|
|
5413
|
-
*
|
|
5414
|
-
* Proves: Solver correctly executed the intent
|
|
5415
|
-
*/
|
|
5416
|
-
async generateFulfillmentProof(params, onProgress) {
|
|
5417
|
-
this.ensureReady();
|
|
5418
|
-
if (!this.fulfillmentNoir || !this.fulfillmentBackend) {
|
|
5419
|
-
throw new ProofGenerationError("fulfillment", "Fulfillment circuit not initialized");
|
|
5420
|
-
}
|
|
5421
|
-
try {
|
|
5422
|
-
onProgress?.({
|
|
5423
|
-
stage: "witness",
|
|
5424
|
-
percent: 10,
|
|
5425
|
-
message: "Preparing fulfillment witness..."
|
|
5426
|
-
});
|
|
5427
|
-
const intentHashField = this.hexToField(params.intentHash);
|
|
5428
|
-
const recipientStealthField = this.hexToField(params.recipientStealth);
|
|
5429
|
-
const { commitmentX, commitmentY } = await this.computeOutputCommitment(
|
|
5430
|
-
params.outputAmount,
|
|
5431
|
-
params.outputBlinding
|
|
5432
|
-
);
|
|
5433
|
-
const solverSecretField = this.bytesToField(params.solverSecret);
|
|
5434
|
-
const solverId = await this.computeSolverId(solverSecretField);
|
|
5435
|
-
const outputBlindingField = this.bytesToField(params.outputBlinding);
|
|
5436
|
-
const attestation = params.oracleAttestation;
|
|
5437
|
-
const attestationRecipientField = this.hexToField(attestation.recipient);
|
|
5438
|
-
const attestationTxHashField = this.hexToField(attestation.txHash);
|
|
5439
|
-
const oracleSignature = Array.from(attestation.signature);
|
|
5440
|
-
const oracleMessageHash = await this.computeOracleMessageHash(
|
|
5441
|
-
attestation.recipient,
|
|
5442
|
-
attestation.amount,
|
|
5443
|
-
attestation.txHash,
|
|
5444
|
-
attestation.blockNumber
|
|
5445
|
-
);
|
|
5446
|
-
const oraclePubKeyX = this.config.oraclePublicKey?.x ?? new Array(32).fill(0);
|
|
5447
|
-
const oraclePubKeyY = this.config.oraclePublicKey?.y ?? new Array(32).fill(0);
|
|
5448
|
-
const witnessInputs = {
|
|
5449
|
-
intent_hash: intentHashField,
|
|
5450
|
-
output_commitment_x: commitmentX,
|
|
5451
|
-
output_commitment_y: commitmentY,
|
|
5452
|
-
recipient_stealth: recipientStealthField,
|
|
5453
|
-
min_output_amount: params.minOutputAmount.toString(),
|
|
5454
|
-
solver_id: solverId,
|
|
5455
|
-
fulfillment_time: params.fulfillmentTime.toString(),
|
|
5456
|
-
expiry: params.expiry.toString(),
|
|
5457
|
-
output_amount: params.outputAmount.toString(),
|
|
5458
|
-
output_blinding: outputBlindingField,
|
|
5459
|
-
solver_secret: solverSecretField,
|
|
5460
|
-
attestation_recipient: attestationRecipientField,
|
|
5461
|
-
attestation_amount: attestation.amount.toString(),
|
|
5462
|
-
attestation_tx_hash: attestationTxHashField,
|
|
5463
|
-
attestation_block: attestation.blockNumber.toString(),
|
|
5464
|
-
oracle_signature: oracleSignature,
|
|
5465
|
-
oracle_message_hash: oracleMessageHash,
|
|
5466
|
-
oracle_pub_key_x: oraclePubKeyX,
|
|
5467
|
-
oracle_pub_key_y: oraclePubKeyY
|
|
5468
|
-
};
|
|
5469
|
-
onProgress?.({
|
|
5470
|
-
stage: "witness",
|
|
5471
|
-
percent: 30,
|
|
5472
|
-
message: "Generating witness..."
|
|
5473
|
-
});
|
|
5474
|
-
const { witness } = await this.fulfillmentNoir.execute(witnessInputs);
|
|
5475
|
-
onProgress?.({
|
|
5476
|
-
stage: "proving",
|
|
5477
|
-
percent: 50,
|
|
5478
|
-
message: "Generating fulfillment proof..."
|
|
5479
|
-
});
|
|
5480
|
-
const proofData = await this.fulfillmentBackend.generateProof(witness);
|
|
5481
|
-
onProgress?.({
|
|
5482
|
-
stage: "complete",
|
|
5483
|
-
percent: 100,
|
|
5484
|
-
message: "Fulfillment proof generated"
|
|
5485
|
-
});
|
|
5486
|
-
const publicInputs = [
|
|
5487
|
-
`0x${intentHashField}`,
|
|
5488
|
-
`0x${commitmentX}`,
|
|
5489
|
-
`0x${commitmentY}`,
|
|
5490
|
-
`0x${recipientStealthField}`,
|
|
5491
|
-
`0x${params.minOutputAmount.toString(16).padStart(16, "0")}`,
|
|
5492
|
-
`0x${solverId}`,
|
|
5493
|
-
`0x${params.fulfillmentTime.toString(16).padStart(16, "0")}`,
|
|
5494
|
-
`0x${params.expiry.toString(16).padStart(16, "0")}`
|
|
5495
|
-
];
|
|
5496
|
-
const proof = {
|
|
5497
|
-
type: "fulfillment",
|
|
5498
|
-
proof: `0x${bytesToHex7(proofData.proof)}`,
|
|
5499
|
-
publicInputs
|
|
5500
|
-
};
|
|
5501
|
-
return { proof, publicInputs };
|
|
5502
|
-
} catch (error) {
|
|
5503
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
5504
|
-
throw new ProofGenerationError(
|
|
5505
|
-
"fulfillment",
|
|
5506
|
-
`Failed to generate fulfillment proof: ${message}`,
|
|
5507
|
-
error instanceof Error ? error : void 0
|
|
5508
|
-
);
|
|
5509
|
-
}
|
|
5510
|
-
}
|
|
5511
|
-
/**
|
|
5512
|
-
* Verify a proof
|
|
5513
|
-
*/
|
|
5514
|
-
async verifyProof(proof) {
|
|
5515
|
-
this.ensureReady();
|
|
5516
|
-
let backend = null;
|
|
5517
|
-
switch (proof.type) {
|
|
5518
|
-
case "funding":
|
|
5519
|
-
backend = this.fundingBackend;
|
|
5520
|
-
break;
|
|
5521
|
-
case "validity":
|
|
5522
|
-
backend = this.validityBackend;
|
|
5523
|
-
break;
|
|
5524
|
-
case "fulfillment":
|
|
5525
|
-
backend = this.fulfillmentBackend;
|
|
5526
|
-
break;
|
|
5527
|
-
default:
|
|
5528
|
-
throw new ProofError(`Unknown proof type: ${proof.type}`, "SIP_4003" /* PROOF_NOT_IMPLEMENTED */);
|
|
5529
|
-
}
|
|
5530
|
-
if (!backend) {
|
|
5531
|
-
throw new ProofError(
|
|
5532
|
-
`${proof.type} backend not initialized`,
|
|
5533
|
-
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
5534
|
-
);
|
|
5535
|
-
}
|
|
5536
|
-
try {
|
|
5537
|
-
const proofHex = proof.proof.startsWith("0x") ? proof.proof.slice(2) : proof.proof;
|
|
5538
|
-
const proofBytes = hexToBytes5(proofHex);
|
|
5539
|
-
const isValid = await backend.verifyProof({
|
|
5540
|
-
proof: proofBytes,
|
|
5541
|
-
publicInputs: proof.publicInputs.map(
|
|
5542
|
-
(input) => input.startsWith("0x") ? input.slice(2) : input
|
|
5543
|
-
)
|
|
5544
|
-
});
|
|
5545
|
-
return isValid;
|
|
5546
|
-
} catch (error) {
|
|
5547
|
-
if (this.config.verbose) {
|
|
5548
|
-
console.error("[BrowserNoirProvider] Verification error:", error);
|
|
5549
|
-
}
|
|
5550
|
-
return false;
|
|
5551
|
-
}
|
|
5552
|
-
}
|
|
5553
|
-
/**
|
|
5554
|
-
* Destroy the provider and free resources
|
|
5555
|
-
*/
|
|
5556
|
-
async destroy() {
|
|
5557
|
-
if (this.fundingBackend) {
|
|
5558
|
-
await this.fundingBackend.destroy();
|
|
5559
|
-
this.fundingBackend = null;
|
|
5560
|
-
}
|
|
5561
|
-
if (this.validityBackend) {
|
|
5562
|
-
await this.validityBackend.destroy();
|
|
5563
|
-
this.validityBackend = null;
|
|
5564
|
-
}
|
|
5565
|
-
if (this.fulfillmentBackend) {
|
|
5566
|
-
await this.fulfillmentBackend.destroy();
|
|
5567
|
-
this.fulfillmentBackend = null;
|
|
5568
|
-
}
|
|
5569
|
-
if (this.worker) {
|
|
5570
|
-
this.worker.terminate();
|
|
5571
|
-
this.worker = null;
|
|
5572
|
-
}
|
|
5573
|
-
this.fundingNoir = null;
|
|
5574
|
-
this.validityNoir = null;
|
|
5575
|
-
this.fulfillmentNoir = null;
|
|
5576
|
-
this._isReady = false;
|
|
5577
|
-
}
|
|
5578
|
-
// ─── Private Utility Methods ────────────────────────────────────────────────
|
|
5579
|
-
ensureReady() {
|
|
5580
|
-
if (!this._isReady) {
|
|
5581
|
-
throw new ProofError(
|
|
5582
|
-
"BrowserNoirProvider not initialized. Call initialize() first.",
|
|
5583
|
-
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
5584
|
-
);
|
|
5585
|
-
}
|
|
5586
|
-
}
|
|
5587
|
-
async computeCommitmentHash(balance, blindingFactor, assetId) {
|
|
5588
|
-
const blindingField = this.bytesToField(blindingFactor);
|
|
5589
|
-
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
5590
|
-
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
5591
|
-
const preimage = new Uint8Array([
|
|
5592
|
-
...this.bigintToBytes(balance, 8),
|
|
5593
|
-
...blindingFactor.slice(0, 32),
|
|
5594
|
-
...hexToBytes5(this.assetIdToField(assetId))
|
|
5595
|
-
]);
|
|
5596
|
-
const hash2 = sha25611(preimage);
|
|
5597
|
-
const commitmentHash = nobleToHex(hash2);
|
|
5598
|
-
return { commitmentHash, blindingField };
|
|
5599
|
-
}
|
|
5600
|
-
assetIdToField(assetId) {
|
|
5601
|
-
if (assetId.startsWith("0x")) {
|
|
5602
|
-
return assetId.slice(2).padStart(64, "0");
|
|
5603
|
-
}
|
|
5604
|
-
const encoder = new TextEncoder();
|
|
5605
|
-
const bytes = encoder.encode(assetId);
|
|
5606
|
-
let result = 0n;
|
|
5607
|
-
for (let i = 0; i < bytes.length && i < 31; i++) {
|
|
5608
|
-
result = result * 256n + BigInt(bytes[i]);
|
|
5609
|
-
}
|
|
5610
|
-
return result.toString(16).padStart(64, "0");
|
|
5611
|
-
}
|
|
5612
|
-
bytesToField(bytes) {
|
|
5613
|
-
let result = 0n;
|
|
5614
|
-
const len = Math.min(bytes.length, 31);
|
|
5615
|
-
for (let i = 0; i < len; i++) {
|
|
5616
|
-
result = result * 256n + BigInt(bytes[i]);
|
|
5617
|
-
}
|
|
5618
|
-
return result.toString();
|
|
5619
|
-
}
|
|
5620
|
-
bigintToBytes(value, length) {
|
|
5621
|
-
const bytes = new Uint8Array(length);
|
|
5622
|
-
let v = value;
|
|
5623
|
-
for (let i = length - 1; i >= 0; i--) {
|
|
5624
|
-
bytes[i] = Number(v & 0xffn);
|
|
5625
|
-
v = v >> 8n;
|
|
5626
|
-
}
|
|
5627
|
-
return bytes;
|
|
5628
|
-
}
|
|
5629
|
-
hexToField(hex) {
|
|
5630
|
-
const h = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
5631
|
-
return h.padStart(64, "0");
|
|
5632
|
-
}
|
|
5633
|
-
fieldToBytes32(field) {
|
|
5634
|
-
const hex = field.padStart(64, "0");
|
|
5635
|
-
const bytes = [];
|
|
5636
|
-
for (let i = 0; i < 32; i++) {
|
|
5637
|
-
bytes.push(parseInt(hex.slice(i * 2, i * 2 + 2), 16));
|
|
5638
|
-
}
|
|
5639
|
-
return bytes;
|
|
5640
|
-
}
|
|
5641
|
-
async computeSenderCommitment(senderAddressField, senderBlindingField) {
|
|
5642
|
-
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
5643
|
-
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
5644
|
-
const addressBytes = hexToBytes5(senderAddressField);
|
|
5645
|
-
const blindingBytes = hexToBytes5(senderBlindingField.padStart(64, "0"));
|
|
5646
|
-
const preimage = new Uint8Array([...addressBytes, ...blindingBytes]);
|
|
5647
|
-
const hash2 = sha25611(preimage);
|
|
5648
|
-
const commitmentX = nobleToHex(hash2.slice(0, 16)).padStart(64, "0");
|
|
5649
|
-
const commitmentY = nobleToHex(hash2.slice(16, 32)).padStart(64, "0");
|
|
5650
|
-
return { commitmentX, commitmentY };
|
|
5651
|
-
}
|
|
5652
|
-
async computeNullifier(senderSecretField, intentHashField, nonceField) {
|
|
5653
|
-
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
5654
|
-
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
5655
|
-
const secretBytes = hexToBytes5(senderSecretField.padStart(64, "0"));
|
|
5656
|
-
const intentBytes = hexToBytes5(intentHashField);
|
|
5657
|
-
const nonceBytes = hexToBytes5(nonceField.padStart(64, "0"));
|
|
5658
|
-
const preimage = new Uint8Array([...secretBytes, ...intentBytes, ...nonceBytes]);
|
|
5659
|
-
const hash2 = sha25611(preimage);
|
|
5660
|
-
return nobleToHex(hash2);
|
|
5661
|
-
}
|
|
5662
|
-
async computeOutputCommitment(outputAmount, outputBlinding) {
|
|
5663
|
-
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
5664
|
-
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
5665
|
-
const amountBytes = this.bigintToBytes(outputAmount, 8);
|
|
5666
|
-
const blindingBytes = outputBlinding.slice(0, 32);
|
|
5667
|
-
const preimage = new Uint8Array([...amountBytes, ...blindingBytes]);
|
|
5668
|
-
const hash2 = sha25611(preimage);
|
|
5669
|
-
const commitmentX = nobleToHex(hash2.slice(0, 16)).padStart(64, "0");
|
|
5670
|
-
const commitmentY = nobleToHex(hash2.slice(16, 32)).padStart(64, "0");
|
|
5671
|
-
return { commitmentX, commitmentY };
|
|
5672
|
-
}
|
|
5673
|
-
async computeSolverId(solverSecretField) {
|
|
5674
|
-
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
5675
|
-
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
5676
|
-
const secretBytes = hexToBytes5(solverSecretField.padStart(64, "0"));
|
|
5677
|
-
const hash2 = sha25611(secretBytes);
|
|
5678
|
-
return nobleToHex(hash2);
|
|
5679
|
-
}
|
|
5680
|
-
async computeOracleMessageHash(recipient, amount, txHash, blockNumber) {
|
|
5681
|
-
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
5682
|
-
const recipientBytes = hexToBytes5(this.hexToField(recipient));
|
|
5683
|
-
const amountBytes = this.bigintToBytes(amount, 8);
|
|
5684
|
-
const txHashBytes = hexToBytes5(this.hexToField(txHash));
|
|
5685
|
-
const blockBytes = this.bigintToBytes(blockNumber, 8);
|
|
5686
|
-
const preimage = new Uint8Array([
|
|
5687
|
-
...recipientBytes,
|
|
5688
|
-
...amountBytes,
|
|
5689
|
-
...txHashBytes,
|
|
5690
|
-
...blockBytes
|
|
5691
|
-
]);
|
|
5692
|
-
const hash2 = sha25611(preimage);
|
|
5693
|
-
return Array.from(hash2);
|
|
5694
|
-
}
|
|
5695
|
-
getPublicKeyCoordinates(privateKey) {
|
|
5696
|
-
const uncompressedPubKey = import_secp256k14.secp256k1.getPublicKey(privateKey, false);
|
|
5697
|
-
const x = Array.from(uncompressedPubKey.slice(1, 33));
|
|
5698
|
-
const y = Array.from(uncompressedPubKey.slice(33, 65));
|
|
5699
|
-
return { x, y };
|
|
5700
|
-
}
|
|
5701
|
-
};
|
|
5702
|
-
|
|
5703
5100
|
// src/oracle/types.ts
|
|
5704
5101
|
var ORACLE_DOMAIN = "SIP-ORACLE-ATTESTATION-V1";
|
|
5705
5102
|
var ATTESTATION_VERSION = 1;
|
|
@@ -7653,7 +7050,7 @@ function getPaymentSummary(payment) {
|
|
|
7653
7050
|
|
|
7654
7051
|
// src/treasury/treasury.ts
|
|
7655
7052
|
var import_types12 = require("@sip-protocol/types");
|
|
7656
|
-
var
|
|
7053
|
+
var import_secp256k14 = require("@noble/curves/secp256k1");
|
|
7657
7054
|
var import_sha25610 = require("@noble/hashes/sha256");
|
|
7658
7055
|
var import_utils12 = require("@noble/hashes/utils");
|
|
7659
7056
|
var DEFAULT_PROPOSAL_TTL = 7 * 24 * 60 * 60;
|
|
@@ -8169,7 +7566,7 @@ function signMessage(messageHash, privateKey) {
|
|
|
8169
7566
|
const keyHex = privateKey.startsWith("0x") ? privateKey.slice(2) : privateKey;
|
|
8170
7567
|
const keyBytes = (0, import_utils12.hexToBytes)(keyHex);
|
|
8171
7568
|
try {
|
|
8172
|
-
const signature =
|
|
7569
|
+
const signature = import_secp256k14.secp256k1.sign(messageHash, keyBytes);
|
|
8173
7570
|
return `0x${signature.toCompactHex()}`;
|
|
8174
7571
|
} finally {
|
|
8175
7572
|
secureWipe(keyBytes);
|
|
@@ -8181,7 +7578,7 @@ function verifySignature(messageHash, signature, publicKey) {
|
|
|
8181
7578
|
try {
|
|
8182
7579
|
const sigBytes = (0, import_utils12.hexToBytes)(sigHex);
|
|
8183
7580
|
const pubKeyBytes = (0, import_utils12.hexToBytes)(pubKeyHex);
|
|
8184
|
-
return
|
|
7581
|
+
return import_secp256k14.secp256k1.verify(sigBytes, messageHash, pubKeyBytes);
|
|
8185
7582
|
} catch {
|
|
8186
7583
|
return false;
|
|
8187
7584
|
}
|
|
@@ -12202,31 +11599,298 @@ var TrezorWalletAdapter = class extends BaseWalletAdapter {
|
|
|
12202
11599
|
"trezor"
|
|
12203
11600
|
);
|
|
12204
11601
|
}
|
|
12205
|
-
if (err.message?.includes("not found") || err.message?.includes("No device")) {
|
|
12206
|
-
return new HardwareWalletError(
|
|
12207
|
-
"Trezor device not found",
|
|
12208
|
-
HardwareErrorCode.DEVICE_NOT_FOUND,
|
|
12209
|
-
"trezor"
|
|
12210
|
-
);
|
|
11602
|
+
if (err.message?.includes("not found") || err.message?.includes("No device")) {
|
|
11603
|
+
return new HardwareWalletError(
|
|
11604
|
+
"Trezor device not found",
|
|
11605
|
+
HardwareErrorCode.DEVICE_NOT_FOUND,
|
|
11606
|
+
"trezor"
|
|
11607
|
+
);
|
|
11608
|
+
}
|
|
11609
|
+
return new HardwareWalletError(
|
|
11610
|
+
err.message ?? "Unknown Trezor error",
|
|
11611
|
+
HardwareErrorCode.TRANSPORT_ERROR,
|
|
11612
|
+
"trezor",
|
|
11613
|
+
error
|
|
11614
|
+
);
|
|
11615
|
+
}
|
|
11616
|
+
};
|
|
11617
|
+
function createTrezorAdapter(config) {
|
|
11618
|
+
return new TrezorWalletAdapter(config);
|
|
11619
|
+
}
|
|
11620
|
+
|
|
11621
|
+
// src/wallet/hardware/mock.ts
|
|
11622
|
+
var import_types29 = require("@sip-protocol/types");
|
|
11623
|
+
var import_utils14 = require("@noble/hashes/utils");
|
|
11624
|
+
var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
11625
|
+
chain;
|
|
11626
|
+
name = "mock-ledger";
|
|
11627
|
+
config;
|
|
11628
|
+
_derivationPath;
|
|
11629
|
+
_deviceInfo = null;
|
|
11630
|
+
_account = null;
|
|
11631
|
+
mockAccounts = [];
|
|
11632
|
+
constructor(config) {
|
|
11633
|
+
super();
|
|
11634
|
+
this.chain = config.chain;
|
|
11635
|
+
this.config = {
|
|
11636
|
+
model: "nanoX",
|
|
11637
|
+
accountIndex: 0,
|
|
11638
|
+
isLocked: false,
|
|
11639
|
+
signingDelay: 100,
|
|
11640
|
+
shouldReject: false,
|
|
11641
|
+
shouldFailConnect: false,
|
|
11642
|
+
accountCount: 5,
|
|
11643
|
+
...config
|
|
11644
|
+
};
|
|
11645
|
+
this._derivationPath = config.derivationPath ?? getDerivationPath(config.chain, config.accountIndex ?? 0);
|
|
11646
|
+
this.generateMockAccounts();
|
|
11647
|
+
}
|
|
11648
|
+
/**
|
|
11649
|
+
* Get device information
|
|
11650
|
+
*/
|
|
11651
|
+
get deviceInfo() {
|
|
11652
|
+
return this._deviceInfo;
|
|
11653
|
+
}
|
|
11654
|
+
/**
|
|
11655
|
+
* Get current derivation path
|
|
11656
|
+
*/
|
|
11657
|
+
get derivationPath() {
|
|
11658
|
+
return this._derivationPath;
|
|
11659
|
+
}
|
|
11660
|
+
/**
|
|
11661
|
+
* Get current account
|
|
11662
|
+
*/
|
|
11663
|
+
get account() {
|
|
11664
|
+
return this._account;
|
|
11665
|
+
}
|
|
11666
|
+
/**
|
|
11667
|
+
* Connect to mock Ledger device
|
|
11668
|
+
*/
|
|
11669
|
+
async connect() {
|
|
11670
|
+
this._connectionState = "connecting";
|
|
11671
|
+
await this.delay(200);
|
|
11672
|
+
if (this.config.shouldFailConnect) {
|
|
11673
|
+
this._connectionState = "error";
|
|
11674
|
+
throw new HardwareWalletError(
|
|
11675
|
+
"Mock connection failure",
|
|
11676
|
+
HardwareErrorCode.DEVICE_NOT_FOUND,
|
|
11677
|
+
"ledger"
|
|
11678
|
+
);
|
|
11679
|
+
}
|
|
11680
|
+
if (this.config.isLocked) {
|
|
11681
|
+
this._connectionState = "error";
|
|
11682
|
+
throw new HardwareWalletError(
|
|
11683
|
+
"Device is locked. Please enter PIN.",
|
|
11684
|
+
HardwareErrorCode.DEVICE_LOCKED,
|
|
11685
|
+
"ledger"
|
|
11686
|
+
);
|
|
11687
|
+
}
|
|
11688
|
+
this._account = this.mockAccounts[this.config.accountIndex ?? 0];
|
|
11689
|
+
this._deviceInfo = {
|
|
11690
|
+
manufacturer: "ledger",
|
|
11691
|
+
model: this.config.model ?? "Nano X",
|
|
11692
|
+
firmwareVersion: "2.1.0",
|
|
11693
|
+
isLocked: false,
|
|
11694
|
+
currentApp: this.getAppName(),
|
|
11695
|
+
label: "Mock Ledger",
|
|
11696
|
+
deviceId: "mock-ledger-001"
|
|
11697
|
+
};
|
|
11698
|
+
this.setConnected(this._account.address, this._account.publicKey);
|
|
11699
|
+
}
|
|
11700
|
+
/**
|
|
11701
|
+
* Disconnect from mock device
|
|
11702
|
+
*/
|
|
11703
|
+
async disconnect() {
|
|
11704
|
+
this._account = null;
|
|
11705
|
+
this._deviceInfo = null;
|
|
11706
|
+
this.setDisconnected();
|
|
11707
|
+
}
|
|
11708
|
+
/**
|
|
11709
|
+
* Sign a message
|
|
11710
|
+
*/
|
|
11711
|
+
async signMessage(message) {
|
|
11712
|
+
this.requireConnected();
|
|
11713
|
+
await this.delay(this.config.signingDelay ?? 100);
|
|
11714
|
+
if (this.config.shouldReject) {
|
|
11715
|
+
throw new HardwareWalletError(
|
|
11716
|
+
"User rejected on device",
|
|
11717
|
+
HardwareErrorCode.USER_REJECTED,
|
|
11718
|
+
"ledger"
|
|
11719
|
+
);
|
|
11720
|
+
}
|
|
11721
|
+
const sig = this.generateMockSignature(message);
|
|
11722
|
+
return {
|
|
11723
|
+
signature: sig,
|
|
11724
|
+
publicKey: this._account.publicKey
|
|
11725
|
+
};
|
|
11726
|
+
}
|
|
11727
|
+
/**
|
|
11728
|
+
* Sign a transaction
|
|
11729
|
+
*/
|
|
11730
|
+
async signTransaction(tx) {
|
|
11731
|
+
this.requireConnected();
|
|
11732
|
+
await this.delay(this.config.signingDelay ?? 100);
|
|
11733
|
+
if (this.config.shouldReject) {
|
|
11734
|
+
throw new HardwareWalletError(
|
|
11735
|
+
"Transaction rejected on device",
|
|
11736
|
+
HardwareErrorCode.USER_REJECTED,
|
|
11737
|
+
"ledger"
|
|
11738
|
+
);
|
|
11739
|
+
}
|
|
11740
|
+
const sig = this.generateMockSignature(
|
|
11741
|
+
new TextEncoder().encode(JSON.stringify(tx.data))
|
|
11742
|
+
);
|
|
11743
|
+
return {
|
|
11744
|
+
unsigned: tx,
|
|
11745
|
+
signatures: [
|
|
11746
|
+
{
|
|
11747
|
+
signature: sig,
|
|
11748
|
+
publicKey: this._account.publicKey
|
|
11749
|
+
}
|
|
11750
|
+
],
|
|
11751
|
+
serialized: sig
|
|
11752
|
+
};
|
|
11753
|
+
}
|
|
11754
|
+
/**
|
|
11755
|
+
* Sign and send transaction
|
|
11756
|
+
*/
|
|
11757
|
+
async signAndSendTransaction(tx) {
|
|
11758
|
+
const signed = await this.signTransaction(tx);
|
|
11759
|
+
return {
|
|
11760
|
+
txHash: signed.serialized.slice(0, 66),
|
|
11761
|
+
status: "pending"
|
|
11762
|
+
};
|
|
11763
|
+
}
|
|
11764
|
+
/**
|
|
11765
|
+
* Get balance (not supported by hardware wallets)
|
|
11766
|
+
*/
|
|
11767
|
+
async getBalance() {
|
|
11768
|
+
throw new WalletError(
|
|
11769
|
+
"Hardware wallets do not track balances",
|
|
11770
|
+
import_types29.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
11771
|
+
);
|
|
11772
|
+
}
|
|
11773
|
+
/**
|
|
11774
|
+
* Get token balance (not supported by hardware wallets)
|
|
11775
|
+
*/
|
|
11776
|
+
async getTokenBalance(_asset) {
|
|
11777
|
+
throw new WalletError(
|
|
11778
|
+
"Hardware wallets do not track balances",
|
|
11779
|
+
import_types29.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
11780
|
+
);
|
|
11781
|
+
}
|
|
11782
|
+
/**
|
|
11783
|
+
* Get multiple accounts
|
|
11784
|
+
*/
|
|
11785
|
+
async getAccounts(startIndex = 0, count = 5) {
|
|
11786
|
+
this.requireConnected();
|
|
11787
|
+
return this.mockAccounts.slice(startIndex, startIndex + count);
|
|
11788
|
+
}
|
|
11789
|
+
/**
|
|
11790
|
+
* Switch account
|
|
11791
|
+
*/
|
|
11792
|
+
async switchAccount(accountIndex) {
|
|
11793
|
+
this.requireConnected();
|
|
11794
|
+
if (accountIndex >= this.mockAccounts.length) {
|
|
11795
|
+
throw new HardwareWalletError(
|
|
11796
|
+
"Account index out of range",
|
|
11797
|
+
HardwareErrorCode.INVALID_PATH,
|
|
11798
|
+
"ledger"
|
|
11799
|
+
);
|
|
11800
|
+
}
|
|
11801
|
+
const previousAddress = this._address;
|
|
11802
|
+
this._account = this.mockAccounts[accountIndex];
|
|
11803
|
+
this._derivationPath = this._account.derivationPath;
|
|
11804
|
+
this.setConnected(this._account.address, this._account.publicKey);
|
|
11805
|
+
if (previousAddress !== this._account.address) {
|
|
11806
|
+
this.emitAccountChanged(previousAddress, this._account.address);
|
|
11807
|
+
}
|
|
11808
|
+
return this._account;
|
|
11809
|
+
}
|
|
11810
|
+
// ─── Test Helpers ───────────────────────────────────────────────────────────
|
|
11811
|
+
/**
|
|
11812
|
+
* Set whether device should reject signing
|
|
11813
|
+
*/
|
|
11814
|
+
setShouldReject(shouldReject) {
|
|
11815
|
+
this.config.shouldReject = shouldReject;
|
|
11816
|
+
}
|
|
11817
|
+
/**
|
|
11818
|
+
* Set signing delay
|
|
11819
|
+
*/
|
|
11820
|
+
setSigningDelay(delay) {
|
|
11821
|
+
this.config.signingDelay = delay;
|
|
11822
|
+
}
|
|
11823
|
+
/**
|
|
11824
|
+
* Simulate device lock
|
|
11825
|
+
*/
|
|
11826
|
+
simulateLock() {
|
|
11827
|
+
if (this._deviceInfo) {
|
|
11828
|
+
this._deviceInfo.isLocked = true;
|
|
11829
|
+
}
|
|
11830
|
+
this.config.isLocked = true;
|
|
11831
|
+
}
|
|
11832
|
+
/**
|
|
11833
|
+
* Simulate device unlock
|
|
11834
|
+
*/
|
|
11835
|
+
simulateUnlock() {
|
|
11836
|
+
if (this._deviceInfo) {
|
|
11837
|
+
this._deviceInfo.isLocked = false;
|
|
11838
|
+
}
|
|
11839
|
+
this.config.isLocked = false;
|
|
11840
|
+
}
|
|
11841
|
+
// ─── Private Methods ────────────────────────────────────────────────────────
|
|
11842
|
+
getAppName() {
|
|
11843
|
+
switch (this.chain) {
|
|
11844
|
+
case "ethereum":
|
|
11845
|
+
return "Ethereum";
|
|
11846
|
+
case "solana":
|
|
11847
|
+
return "Solana";
|
|
11848
|
+
default:
|
|
11849
|
+
return "Unknown";
|
|
11850
|
+
}
|
|
11851
|
+
}
|
|
11852
|
+
generateMockAccounts() {
|
|
11853
|
+
const count = this.config.accountCount ?? 5;
|
|
11854
|
+
for (let i = 0; i < count; i++) {
|
|
11855
|
+
const path = getDerivationPath(this.chain, i);
|
|
11856
|
+
const address = this.config.mockAddress && i === 0 ? this.config.mockAddress : this.generateMockAddress(i);
|
|
11857
|
+
const publicKey = this.config.mockPublicKey && i === 0 ? this.config.mockPublicKey : this.generateMockPublicKey(i);
|
|
11858
|
+
this.mockAccounts.push({
|
|
11859
|
+
address,
|
|
11860
|
+
publicKey,
|
|
11861
|
+
derivationPath: path,
|
|
11862
|
+
index: i,
|
|
11863
|
+
chain: this.chain
|
|
11864
|
+
});
|
|
11865
|
+
}
|
|
11866
|
+
}
|
|
11867
|
+
generateMockAddress(index) {
|
|
11868
|
+
const bytes = (0, import_utils14.randomBytes)(20);
|
|
11869
|
+
bytes[0] = index;
|
|
11870
|
+
return `0x${(0, import_utils14.bytesToHex)(bytes)}`;
|
|
11871
|
+
}
|
|
11872
|
+
generateMockPublicKey(index) {
|
|
11873
|
+
const bytes = (0, import_utils14.randomBytes)(33);
|
|
11874
|
+
bytes[0] = 2;
|
|
11875
|
+
bytes[1] = index;
|
|
11876
|
+
return `0x${(0, import_utils14.bytesToHex)(bytes)}`;
|
|
11877
|
+
}
|
|
11878
|
+
generateMockSignature(data) {
|
|
11879
|
+
const sig = new Uint8Array(65);
|
|
11880
|
+
for (let i = 0; i < 32; i++) {
|
|
11881
|
+
sig[i] = (data[i % data.length] ?? 0) ^ i * 7;
|
|
11882
|
+
sig[32 + i] = (data[i % data.length] ?? 0) ^ i * 11;
|
|
12211
11883
|
}
|
|
12212
|
-
|
|
12213
|
-
|
|
12214
|
-
|
|
12215
|
-
|
|
12216
|
-
|
|
12217
|
-
);
|
|
11884
|
+
sig[64] = 27;
|
|
11885
|
+
return `0x${(0, import_utils14.bytesToHex)(sig)}`;
|
|
11886
|
+
}
|
|
11887
|
+
delay(ms) {
|
|
11888
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12218
11889
|
}
|
|
12219
11890
|
};
|
|
12220
|
-
|
|
12221
|
-
return new TrezorWalletAdapter(config);
|
|
12222
|
-
}
|
|
12223
|
-
|
|
12224
|
-
// src/wallet/hardware/mock.ts
|
|
12225
|
-
var import_types29 = require("@sip-protocol/types");
|
|
12226
|
-
var import_utils14 = require("@noble/hashes/utils");
|
|
12227
|
-
var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
11891
|
+
var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
12228
11892
|
chain;
|
|
12229
|
-
name = "mock-
|
|
11893
|
+
name = "mock-trezor";
|
|
12230
11894
|
config;
|
|
12231
11895
|
_derivationPath;
|
|
12232
11896
|
_deviceInfo = null;
|
|
@@ -12236,7 +11900,7 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
12236
11900
|
super();
|
|
12237
11901
|
this.chain = config.chain;
|
|
12238
11902
|
this.config = {
|
|
12239
|
-
model: "
|
|
11903
|
+
model: "T",
|
|
12240
11904
|
accountIndex: 0,
|
|
12241
11905
|
isLocked: false,
|
|
12242
11906
|
signingDelay: 100,
|
|
@@ -12248,27 +11912,15 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
12248
11912
|
this._derivationPath = config.derivationPath ?? getDerivationPath(config.chain, config.accountIndex ?? 0);
|
|
12249
11913
|
this.generateMockAccounts();
|
|
12250
11914
|
}
|
|
12251
|
-
/**
|
|
12252
|
-
* Get device information
|
|
12253
|
-
*/
|
|
12254
11915
|
get deviceInfo() {
|
|
12255
11916
|
return this._deviceInfo;
|
|
12256
11917
|
}
|
|
12257
|
-
/**
|
|
12258
|
-
* Get current derivation path
|
|
12259
|
-
*/
|
|
12260
11918
|
get derivationPath() {
|
|
12261
11919
|
return this._derivationPath;
|
|
12262
11920
|
}
|
|
12263
|
-
/**
|
|
12264
|
-
* Get current account
|
|
12265
|
-
*/
|
|
12266
11921
|
get account() {
|
|
12267
11922
|
return this._account;
|
|
12268
11923
|
}
|
|
12269
|
-
/**
|
|
12270
|
-
* Connect to mock Ledger device
|
|
12271
|
-
*/
|
|
12272
11924
|
async connect() {
|
|
12273
11925
|
this._connectionState = "connecting";
|
|
12274
11926
|
await this.delay(200);
|
|
@@ -12277,40 +11929,33 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
12277
11929
|
throw new HardwareWalletError(
|
|
12278
11930
|
"Mock connection failure",
|
|
12279
11931
|
HardwareErrorCode.DEVICE_NOT_FOUND,
|
|
12280
|
-
"
|
|
11932
|
+
"trezor"
|
|
12281
11933
|
);
|
|
12282
11934
|
}
|
|
12283
11935
|
if (this.config.isLocked) {
|
|
12284
11936
|
this._connectionState = "error";
|
|
12285
11937
|
throw new HardwareWalletError(
|
|
12286
|
-
"Device
|
|
11938
|
+
"Device requires PIN",
|
|
12287
11939
|
HardwareErrorCode.DEVICE_LOCKED,
|
|
12288
|
-
"
|
|
11940
|
+
"trezor"
|
|
12289
11941
|
);
|
|
12290
11942
|
}
|
|
12291
11943
|
this._account = this.mockAccounts[this.config.accountIndex ?? 0];
|
|
12292
11944
|
this._deviceInfo = {
|
|
12293
|
-
manufacturer: "
|
|
12294
|
-
model: this.config.model ?? "
|
|
12295
|
-
firmwareVersion: "2.
|
|
11945
|
+
manufacturer: "trezor",
|
|
11946
|
+
model: this.config.model ?? "Model T",
|
|
11947
|
+
firmwareVersion: "2.5.3",
|
|
12296
11948
|
isLocked: false,
|
|
12297
|
-
|
|
12298
|
-
|
|
12299
|
-
deviceId: "mock-ledger-001"
|
|
11949
|
+
label: "Mock Trezor",
|
|
11950
|
+
deviceId: "mock-trezor-001"
|
|
12300
11951
|
};
|
|
12301
11952
|
this.setConnected(this._account.address, this._account.publicKey);
|
|
12302
11953
|
}
|
|
12303
|
-
/**
|
|
12304
|
-
* Disconnect from mock device
|
|
12305
|
-
*/
|
|
12306
11954
|
async disconnect() {
|
|
12307
11955
|
this._account = null;
|
|
12308
11956
|
this._deviceInfo = null;
|
|
12309
11957
|
this.setDisconnected();
|
|
12310
11958
|
}
|
|
12311
|
-
/**
|
|
12312
|
-
* Sign a message
|
|
12313
|
-
*/
|
|
12314
11959
|
async signMessage(message) {
|
|
12315
11960
|
this.requireConnected();
|
|
12316
11961
|
await this.delay(this.config.signingDelay ?? 100);
|
|
@@ -12318,7 +11963,7 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
12318
11963
|
throw new HardwareWalletError(
|
|
12319
11964
|
"User rejected on device",
|
|
12320
11965
|
HardwareErrorCode.USER_REJECTED,
|
|
12321
|
-
"
|
|
11966
|
+
"trezor"
|
|
12322
11967
|
);
|
|
12323
11968
|
}
|
|
12324
11969
|
const sig = this.generateMockSignature(message);
|
|
@@ -12327,9 +11972,6 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
12327
11972
|
publicKey: this._account.publicKey
|
|
12328
11973
|
};
|
|
12329
11974
|
}
|
|
12330
|
-
/**
|
|
12331
|
-
* Sign a transaction
|
|
12332
|
-
*/
|
|
12333
11975
|
async signTransaction(tx) {
|
|
12334
11976
|
this.requireConnected();
|
|
12335
11977
|
await this.delay(this.config.signingDelay ?? 100);
|
|
@@ -12337,7 +11979,7 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
12337
11979
|
throw new HardwareWalletError(
|
|
12338
11980
|
"Transaction rejected on device",
|
|
12339
11981
|
HardwareErrorCode.USER_REJECTED,
|
|
12340
|
-
"
|
|
11982
|
+
"trezor"
|
|
12341
11983
|
);
|
|
12342
11984
|
}
|
|
12343
11985
|
const sig = this.generateMockSignature(
|
|
@@ -12354,9 +11996,6 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
12354
11996
|
serialized: sig
|
|
12355
11997
|
};
|
|
12356
11998
|
}
|
|
12357
|
-
/**
|
|
12358
|
-
* Sign and send transaction
|
|
12359
|
-
*/
|
|
12360
11999
|
async signAndSendTransaction(tx) {
|
|
12361
12000
|
const signed = await this.signTransaction(tx);
|
|
12362
12001
|
return {
|
|
@@ -12364,348 +12003,709 @@ var MockLedgerAdapter = class extends BaseWalletAdapter {
|
|
|
12364
12003
|
status: "pending"
|
|
12365
12004
|
};
|
|
12366
12005
|
}
|
|
12367
|
-
/**
|
|
12368
|
-
* Get balance (not supported by hardware wallets)
|
|
12369
|
-
*/
|
|
12370
12006
|
async getBalance() {
|
|
12371
12007
|
throw new WalletError(
|
|
12372
12008
|
"Hardware wallets do not track balances",
|
|
12373
12009
|
import_types29.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
12374
12010
|
);
|
|
12375
12011
|
}
|
|
12376
|
-
/**
|
|
12377
|
-
* Get token balance (not supported by hardware wallets)
|
|
12378
|
-
*/
|
|
12379
12012
|
async getTokenBalance(_asset) {
|
|
12380
12013
|
throw new WalletError(
|
|
12381
12014
|
"Hardware wallets do not track balances",
|
|
12382
12015
|
import_types29.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
12383
12016
|
);
|
|
12384
12017
|
}
|
|
12018
|
+
async getAccounts(startIndex = 0, count = 5) {
|
|
12019
|
+
this.requireConnected();
|
|
12020
|
+
return this.mockAccounts.slice(startIndex, startIndex + count);
|
|
12021
|
+
}
|
|
12022
|
+
async switchAccount(accountIndex) {
|
|
12023
|
+
this.requireConnected();
|
|
12024
|
+
if (accountIndex >= this.mockAccounts.length) {
|
|
12025
|
+
throw new HardwareWalletError(
|
|
12026
|
+
"Account index out of range",
|
|
12027
|
+
HardwareErrorCode.INVALID_PATH,
|
|
12028
|
+
"trezor"
|
|
12029
|
+
);
|
|
12030
|
+
}
|
|
12031
|
+
const previousAddress = this._address;
|
|
12032
|
+
this._account = this.mockAccounts[accountIndex];
|
|
12033
|
+
this._derivationPath = this._account.derivationPath;
|
|
12034
|
+
this.setConnected(this._account.address, this._account.publicKey);
|
|
12035
|
+
if (previousAddress !== this._account.address) {
|
|
12036
|
+
this.emitAccountChanged(previousAddress, this._account.address);
|
|
12037
|
+
}
|
|
12038
|
+
return this._account;
|
|
12039
|
+
}
|
|
12040
|
+
setShouldReject(shouldReject) {
|
|
12041
|
+
this.config.shouldReject = shouldReject;
|
|
12042
|
+
}
|
|
12043
|
+
setSigningDelay(delay) {
|
|
12044
|
+
this.config.signingDelay = delay;
|
|
12045
|
+
}
|
|
12046
|
+
simulateLock() {
|
|
12047
|
+
if (this._deviceInfo) {
|
|
12048
|
+
this._deviceInfo.isLocked = true;
|
|
12049
|
+
}
|
|
12050
|
+
this.config.isLocked = true;
|
|
12051
|
+
}
|
|
12052
|
+
simulateUnlock() {
|
|
12053
|
+
if (this._deviceInfo) {
|
|
12054
|
+
this._deviceInfo.isLocked = false;
|
|
12055
|
+
}
|
|
12056
|
+
this.config.isLocked = false;
|
|
12057
|
+
}
|
|
12058
|
+
generateMockAccounts() {
|
|
12059
|
+
const count = this.config.accountCount ?? 5;
|
|
12060
|
+
for (let i = 0; i < count; i++) {
|
|
12061
|
+
const path = getDerivationPath(this.chain, i);
|
|
12062
|
+
const address = this.config.mockAddress && i === 0 ? this.config.mockAddress : this.generateMockAddress(i);
|
|
12063
|
+
const publicKey = this.config.mockPublicKey && i === 0 ? this.config.mockPublicKey : this.generateMockPublicKey(i);
|
|
12064
|
+
this.mockAccounts.push({
|
|
12065
|
+
address,
|
|
12066
|
+
publicKey,
|
|
12067
|
+
derivationPath: path,
|
|
12068
|
+
index: i,
|
|
12069
|
+
chain: this.chain
|
|
12070
|
+
});
|
|
12071
|
+
}
|
|
12072
|
+
}
|
|
12073
|
+
generateMockAddress(index) {
|
|
12074
|
+
const bytes = (0, import_utils14.randomBytes)(20);
|
|
12075
|
+
bytes[0] = index + 100;
|
|
12076
|
+
return `0x${(0, import_utils14.bytesToHex)(bytes)}`;
|
|
12077
|
+
}
|
|
12078
|
+
generateMockPublicKey(index) {
|
|
12079
|
+
const bytes = (0, import_utils14.randomBytes)(33);
|
|
12080
|
+
bytes[0] = 3;
|
|
12081
|
+
bytes[1] = index + 100;
|
|
12082
|
+
return `0x${(0, import_utils14.bytesToHex)(bytes)}`;
|
|
12083
|
+
}
|
|
12084
|
+
generateMockSignature(data) {
|
|
12085
|
+
const sig = new Uint8Array(65);
|
|
12086
|
+
for (let i = 0; i < 32; i++) {
|
|
12087
|
+
sig[i] = (data[i % data.length] ?? 0) ^ i * 13;
|
|
12088
|
+
sig[32 + i] = (data[i % data.length] ?? 0) ^ i * 17;
|
|
12089
|
+
}
|
|
12090
|
+
sig[64] = 28;
|
|
12091
|
+
return `0x${(0, import_utils14.bytesToHex)(sig)}`;
|
|
12092
|
+
}
|
|
12093
|
+
delay(ms) {
|
|
12094
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12095
|
+
}
|
|
12096
|
+
};
|
|
12097
|
+
function createMockLedgerAdapter(config) {
|
|
12098
|
+
return new MockLedgerAdapter({ ...config, deviceType: "ledger" });
|
|
12099
|
+
}
|
|
12100
|
+
function createMockTrezorAdapter(config) {
|
|
12101
|
+
return new MockTrezorAdapter({ ...config, deviceType: "trezor" });
|
|
12102
|
+
}
|
|
12103
|
+
|
|
12104
|
+
// src/wallet/index.ts
|
|
12105
|
+
var import_types32 = require("@sip-protocol/types");
|
|
12106
|
+
|
|
12107
|
+
// src/proofs/browser.ts
|
|
12108
|
+
var import_noir_js2 = require("@noir-lang/noir_js");
|
|
12109
|
+
var import_bb2 = require("@aztec/bb.js");
|
|
12110
|
+
var import_secp256k15 = require("@noble/curves/secp256k1");
|
|
12111
|
+
var BrowserNoirProvider = class _BrowserNoirProvider {
|
|
12112
|
+
framework = "noir";
|
|
12113
|
+
_isReady = false;
|
|
12114
|
+
config;
|
|
12115
|
+
// Circuit instances
|
|
12116
|
+
fundingNoir = null;
|
|
12117
|
+
fundingBackend = null;
|
|
12118
|
+
validityNoir = null;
|
|
12119
|
+
validityBackend = null;
|
|
12120
|
+
fulfillmentNoir = null;
|
|
12121
|
+
fulfillmentBackend = null;
|
|
12122
|
+
// Worker instance (optional)
|
|
12123
|
+
worker = null;
|
|
12124
|
+
workerPending = /* @__PURE__ */ new Map();
|
|
12125
|
+
constructor(config = {}) {
|
|
12126
|
+
this.config = {
|
|
12127
|
+
useWorker: config.useWorker ?? true,
|
|
12128
|
+
verbose: config.verbose ?? false,
|
|
12129
|
+
oraclePublicKey: config.oraclePublicKey ?? void 0,
|
|
12130
|
+
timeout: config.timeout ?? 6e4
|
|
12131
|
+
};
|
|
12132
|
+
if (!isBrowser()) {
|
|
12133
|
+
console.warn(
|
|
12134
|
+
"[BrowserNoirProvider] Not running in browser environment. Consider using NoirProofProvider for Node.js."
|
|
12135
|
+
);
|
|
12136
|
+
}
|
|
12137
|
+
}
|
|
12138
|
+
get isReady() {
|
|
12139
|
+
return this._isReady;
|
|
12140
|
+
}
|
|
12141
|
+
/**
|
|
12142
|
+
* Get browser environment info
|
|
12143
|
+
*/
|
|
12144
|
+
static getBrowserInfo() {
|
|
12145
|
+
return getBrowserInfo();
|
|
12146
|
+
}
|
|
12147
|
+
/**
|
|
12148
|
+
* Check if browser supports all required features
|
|
12149
|
+
*/
|
|
12150
|
+
static checkBrowserSupport() {
|
|
12151
|
+
const missing = [];
|
|
12152
|
+
if (!isBrowser()) {
|
|
12153
|
+
missing.push("browser environment");
|
|
12154
|
+
}
|
|
12155
|
+
if (typeof WebAssembly === "undefined") {
|
|
12156
|
+
missing.push("WebAssembly");
|
|
12157
|
+
}
|
|
12158
|
+
if (!supportsSharedArrayBuffer()) {
|
|
12159
|
+
missing.push("SharedArrayBuffer (requires COOP/COEP headers)");
|
|
12160
|
+
}
|
|
12161
|
+
return {
|
|
12162
|
+
supported: missing.length === 0,
|
|
12163
|
+
missing
|
|
12164
|
+
};
|
|
12165
|
+
}
|
|
12385
12166
|
/**
|
|
12386
|
-
*
|
|
12167
|
+
* Derive secp256k1 public key coordinates from a private key
|
|
12387
12168
|
*/
|
|
12388
|
-
|
|
12389
|
-
|
|
12390
|
-
|
|
12169
|
+
static derivePublicKey(privateKey) {
|
|
12170
|
+
const uncompressedPubKey = import_secp256k15.secp256k1.getPublicKey(privateKey, false);
|
|
12171
|
+
const x = Array.from(uncompressedPubKey.slice(1, 33));
|
|
12172
|
+
const y = Array.from(uncompressedPubKey.slice(33, 65));
|
|
12173
|
+
return { x, y };
|
|
12391
12174
|
}
|
|
12392
12175
|
/**
|
|
12393
|
-
*
|
|
12176
|
+
* Initialize the browser provider
|
|
12177
|
+
*
|
|
12178
|
+
* Loads WASM and circuit artifacts. This should be called before any
|
|
12179
|
+
* proof generation. Consider showing a loading indicator during init.
|
|
12180
|
+
*
|
|
12181
|
+
* @param onProgress - Optional progress callback
|
|
12394
12182
|
*/
|
|
12395
|
-
async
|
|
12396
|
-
this.
|
|
12397
|
-
|
|
12398
|
-
|
|
12399
|
-
|
|
12400
|
-
|
|
12401
|
-
|
|
12183
|
+
async initialize(onProgress) {
|
|
12184
|
+
if (this._isReady) {
|
|
12185
|
+
return;
|
|
12186
|
+
}
|
|
12187
|
+
const { supported, missing } = _BrowserNoirProvider.checkBrowserSupport();
|
|
12188
|
+
if (!supported) {
|
|
12189
|
+
throw new ProofError(
|
|
12190
|
+
`Browser missing required features: ${missing.join(", ")}`,
|
|
12191
|
+
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
12402
12192
|
);
|
|
12403
12193
|
}
|
|
12404
|
-
|
|
12405
|
-
|
|
12406
|
-
|
|
12407
|
-
|
|
12408
|
-
|
|
12409
|
-
|
|
12194
|
+
try {
|
|
12195
|
+
onProgress?.({
|
|
12196
|
+
stage: "initializing",
|
|
12197
|
+
percent: 0,
|
|
12198
|
+
message: "Loading WASM runtime..."
|
|
12199
|
+
});
|
|
12200
|
+
if (this.config.verbose) {
|
|
12201
|
+
console.log("[BrowserNoirProvider] Initializing...");
|
|
12202
|
+
console.log("[BrowserNoirProvider] Browser info:", getBrowserInfo());
|
|
12203
|
+
}
|
|
12204
|
+
const fundingCircuit = funding_proof_default;
|
|
12205
|
+
const validityCircuit = validity_proof_default;
|
|
12206
|
+
const fulfillmentCircuit = fulfillment_proof_default;
|
|
12207
|
+
onProgress?.({
|
|
12208
|
+
stage: "initializing",
|
|
12209
|
+
percent: 20,
|
|
12210
|
+
message: "Creating proof backends..."
|
|
12211
|
+
});
|
|
12212
|
+
this.fundingBackend = new import_bb2.UltraHonkBackend(fundingCircuit.bytecode);
|
|
12213
|
+
this.validityBackend = new import_bb2.UltraHonkBackend(validityCircuit.bytecode);
|
|
12214
|
+
this.fulfillmentBackend = new import_bb2.UltraHonkBackend(fulfillmentCircuit.bytecode);
|
|
12215
|
+
onProgress?.({
|
|
12216
|
+
stage: "initializing",
|
|
12217
|
+
percent: 60,
|
|
12218
|
+
message: "Initializing Noir circuits..."
|
|
12219
|
+
});
|
|
12220
|
+
this.fundingNoir = new import_noir_js2.Noir(fundingCircuit);
|
|
12221
|
+
this.validityNoir = new import_noir_js2.Noir(validityCircuit);
|
|
12222
|
+
this.fulfillmentNoir = new import_noir_js2.Noir(fulfillmentCircuit);
|
|
12223
|
+
onProgress?.({
|
|
12224
|
+
stage: "initializing",
|
|
12225
|
+
percent: 90,
|
|
12226
|
+
message: "Setting up worker..."
|
|
12227
|
+
});
|
|
12228
|
+
if (this.config.useWorker && supportsWebWorkers()) {
|
|
12229
|
+
await this.initializeWorker();
|
|
12230
|
+
}
|
|
12231
|
+
this._isReady = true;
|
|
12232
|
+
onProgress?.({
|
|
12233
|
+
stage: "complete",
|
|
12234
|
+
percent: 100,
|
|
12235
|
+
message: "Ready for proof generation"
|
|
12236
|
+
});
|
|
12237
|
+
if (this.config.verbose) {
|
|
12238
|
+
console.log("[BrowserNoirProvider] Initialization complete");
|
|
12239
|
+
}
|
|
12240
|
+
} catch (error) {
|
|
12241
|
+
throw new ProofError(
|
|
12242
|
+
`Failed to initialize BrowserNoirProvider: ${error instanceof Error ? error.message : String(error)}`,
|
|
12243
|
+
"SIP_4003" /* PROOF_NOT_IMPLEMENTED */,
|
|
12244
|
+
{ context: { error } }
|
|
12245
|
+
);
|
|
12410
12246
|
}
|
|
12411
|
-
return this._account;
|
|
12412
12247
|
}
|
|
12413
|
-
// ─── Test Helpers ───────────────────────────────────────────────────────────
|
|
12414
12248
|
/**
|
|
12415
|
-
*
|
|
12249
|
+
* Initialize Web Worker for off-main-thread proof generation
|
|
12416
12250
|
*/
|
|
12417
|
-
|
|
12418
|
-
this.config.
|
|
12251
|
+
async initializeWorker() {
|
|
12252
|
+
if (this.config.verbose) {
|
|
12253
|
+
console.log("[BrowserNoirProvider] Worker support: using async main-thread");
|
|
12254
|
+
}
|
|
12419
12255
|
}
|
|
12420
12256
|
/**
|
|
12421
|
-
*
|
|
12257
|
+
* Generate a Funding Proof
|
|
12258
|
+
*
|
|
12259
|
+
* Proves: balance >= minimumRequired without revealing balance
|
|
12260
|
+
*
|
|
12261
|
+
* @param params - Funding proof parameters
|
|
12262
|
+
* @param onProgress - Optional progress callback
|
|
12422
12263
|
*/
|
|
12423
|
-
|
|
12424
|
-
this.
|
|
12264
|
+
async generateFundingProof(params, onProgress) {
|
|
12265
|
+
this.ensureReady();
|
|
12266
|
+
if (!this.fundingNoir || !this.fundingBackend) {
|
|
12267
|
+
throw new ProofGenerationError("funding", "Funding circuit not initialized");
|
|
12268
|
+
}
|
|
12269
|
+
try {
|
|
12270
|
+
onProgress?.({
|
|
12271
|
+
stage: "witness",
|
|
12272
|
+
percent: 10,
|
|
12273
|
+
message: "Preparing witness inputs..."
|
|
12274
|
+
});
|
|
12275
|
+
const { commitmentHash, blindingField } = await this.computeCommitmentHash(
|
|
12276
|
+
params.balance,
|
|
12277
|
+
params.blindingFactor,
|
|
12278
|
+
params.assetId
|
|
12279
|
+
);
|
|
12280
|
+
const witnessInputs = {
|
|
12281
|
+
commitment_hash: commitmentHash,
|
|
12282
|
+
minimum_required: params.minimumRequired.toString(),
|
|
12283
|
+
asset_id: this.assetIdToField(params.assetId),
|
|
12284
|
+
balance: params.balance.toString(),
|
|
12285
|
+
blinding: blindingField
|
|
12286
|
+
};
|
|
12287
|
+
onProgress?.({
|
|
12288
|
+
stage: "witness",
|
|
12289
|
+
percent: 30,
|
|
12290
|
+
message: "Generating witness..."
|
|
12291
|
+
});
|
|
12292
|
+
const { witness } = await this.fundingNoir.execute(witnessInputs);
|
|
12293
|
+
onProgress?.({
|
|
12294
|
+
stage: "proving",
|
|
12295
|
+
percent: 50,
|
|
12296
|
+
message: "Generating proof (this may take a moment)..."
|
|
12297
|
+
});
|
|
12298
|
+
const proofData = await this.fundingBackend.generateProof(witness);
|
|
12299
|
+
onProgress?.({
|
|
12300
|
+
stage: "complete",
|
|
12301
|
+
percent: 100,
|
|
12302
|
+
message: "Proof generated successfully"
|
|
12303
|
+
});
|
|
12304
|
+
const publicInputs = [
|
|
12305
|
+
`0x${commitmentHash}`,
|
|
12306
|
+
`0x${params.minimumRequired.toString(16).padStart(16, "0")}`,
|
|
12307
|
+
`0x${this.assetIdToField(params.assetId)}`
|
|
12308
|
+
];
|
|
12309
|
+
const proof = {
|
|
12310
|
+
type: "funding",
|
|
12311
|
+
proof: `0x${bytesToHex7(proofData.proof)}`,
|
|
12312
|
+
publicInputs
|
|
12313
|
+
};
|
|
12314
|
+
return { proof, publicInputs };
|
|
12315
|
+
} catch (error) {
|
|
12316
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12317
|
+
throw new ProofGenerationError(
|
|
12318
|
+
"funding",
|
|
12319
|
+
`Failed to generate funding proof: ${message}`,
|
|
12320
|
+
error instanceof Error ? error : void 0
|
|
12321
|
+
);
|
|
12322
|
+
}
|
|
12425
12323
|
}
|
|
12426
12324
|
/**
|
|
12427
|
-
*
|
|
12325
|
+
* Generate a Validity Proof
|
|
12326
|
+
*
|
|
12327
|
+
* Proves: Intent is authorized by sender without revealing identity
|
|
12428
12328
|
*/
|
|
12429
|
-
|
|
12430
|
-
|
|
12431
|
-
|
|
12329
|
+
async generateValidityProof(params, onProgress) {
|
|
12330
|
+
this.ensureReady();
|
|
12331
|
+
if (!this.validityNoir || !this.validityBackend) {
|
|
12332
|
+
throw new ProofGenerationError("validity", "Validity circuit not initialized");
|
|
12333
|
+
}
|
|
12334
|
+
try {
|
|
12335
|
+
onProgress?.({
|
|
12336
|
+
stage: "witness",
|
|
12337
|
+
percent: 10,
|
|
12338
|
+
message: "Preparing validity witness..."
|
|
12339
|
+
});
|
|
12340
|
+
const intentHashField = this.hexToField(params.intentHash);
|
|
12341
|
+
const senderAddressField = this.hexToField(params.senderAddress);
|
|
12342
|
+
const senderBlindingField = this.bytesToField(params.senderBlinding);
|
|
12343
|
+
const senderSecretField = this.bytesToField(params.senderSecret);
|
|
12344
|
+
const nonceField = this.bytesToField(params.nonce);
|
|
12345
|
+
const { commitmentX, commitmentY } = await this.computeSenderCommitment(
|
|
12346
|
+
senderAddressField,
|
|
12347
|
+
senderBlindingField
|
|
12348
|
+
);
|
|
12349
|
+
const nullifier = await this.computeNullifier(senderSecretField, intentHashField, nonceField);
|
|
12350
|
+
const signature = Array.from(params.authorizationSignature);
|
|
12351
|
+
const messageHash = this.fieldToBytes32(intentHashField);
|
|
12352
|
+
let pubKeyX;
|
|
12353
|
+
let pubKeyY;
|
|
12354
|
+
if (params.senderPublicKey) {
|
|
12355
|
+
pubKeyX = Array.from(params.senderPublicKey.x);
|
|
12356
|
+
pubKeyY = Array.from(params.senderPublicKey.y);
|
|
12357
|
+
} else {
|
|
12358
|
+
const coords = this.getPublicKeyCoordinates(params.senderSecret);
|
|
12359
|
+
pubKeyX = coords.x;
|
|
12360
|
+
pubKeyY = coords.y;
|
|
12361
|
+
}
|
|
12362
|
+
const witnessInputs = {
|
|
12363
|
+
intent_hash: intentHashField,
|
|
12364
|
+
sender_commitment_x: commitmentX,
|
|
12365
|
+
sender_commitment_y: commitmentY,
|
|
12366
|
+
nullifier,
|
|
12367
|
+
timestamp: params.timestamp.toString(),
|
|
12368
|
+
expiry: params.expiry.toString(),
|
|
12369
|
+
sender_address: senderAddressField,
|
|
12370
|
+
sender_blinding: senderBlindingField,
|
|
12371
|
+
sender_secret: senderSecretField,
|
|
12372
|
+
pub_key_x: pubKeyX,
|
|
12373
|
+
pub_key_y: pubKeyY,
|
|
12374
|
+
signature,
|
|
12375
|
+
message_hash: messageHash,
|
|
12376
|
+
nonce: nonceField
|
|
12377
|
+
};
|
|
12378
|
+
onProgress?.({
|
|
12379
|
+
stage: "witness",
|
|
12380
|
+
percent: 30,
|
|
12381
|
+
message: "Generating witness..."
|
|
12382
|
+
});
|
|
12383
|
+
const { witness } = await this.validityNoir.execute(witnessInputs);
|
|
12384
|
+
onProgress?.({
|
|
12385
|
+
stage: "proving",
|
|
12386
|
+
percent: 50,
|
|
12387
|
+
message: "Generating validity proof..."
|
|
12388
|
+
});
|
|
12389
|
+
const proofData = await this.validityBackend.generateProof(witness);
|
|
12390
|
+
onProgress?.({
|
|
12391
|
+
stage: "complete",
|
|
12392
|
+
percent: 100,
|
|
12393
|
+
message: "Validity proof generated"
|
|
12394
|
+
});
|
|
12395
|
+
const publicInputs = [
|
|
12396
|
+
`0x${intentHashField}`,
|
|
12397
|
+
`0x${commitmentX}`,
|
|
12398
|
+
`0x${commitmentY}`,
|
|
12399
|
+
`0x${nullifier}`,
|
|
12400
|
+
`0x${params.timestamp.toString(16).padStart(16, "0")}`,
|
|
12401
|
+
`0x${params.expiry.toString(16).padStart(16, "0")}`
|
|
12402
|
+
];
|
|
12403
|
+
const proof = {
|
|
12404
|
+
type: "validity",
|
|
12405
|
+
proof: `0x${bytesToHex7(proofData.proof)}`,
|
|
12406
|
+
publicInputs
|
|
12407
|
+
};
|
|
12408
|
+
return { proof, publicInputs };
|
|
12409
|
+
} catch (error) {
|
|
12410
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12411
|
+
throw new ProofGenerationError(
|
|
12412
|
+
"validity",
|
|
12413
|
+
`Failed to generate validity proof: ${message}`,
|
|
12414
|
+
error instanceof Error ? error : void 0
|
|
12415
|
+
);
|
|
12432
12416
|
}
|
|
12433
|
-
this.config.isLocked = true;
|
|
12434
12417
|
}
|
|
12435
12418
|
/**
|
|
12436
|
-
*
|
|
12419
|
+
* Generate a Fulfillment Proof
|
|
12420
|
+
*
|
|
12421
|
+
* Proves: Solver correctly executed the intent
|
|
12437
12422
|
*/
|
|
12438
|
-
|
|
12439
|
-
|
|
12440
|
-
|
|
12441
|
-
|
|
12442
|
-
this.config.isLocked = false;
|
|
12443
|
-
}
|
|
12444
|
-
// ─── Private Methods ────────────────────────────────────────────────────────
|
|
12445
|
-
getAppName() {
|
|
12446
|
-
switch (this.chain) {
|
|
12447
|
-
case "ethereum":
|
|
12448
|
-
return "Ethereum";
|
|
12449
|
-
case "solana":
|
|
12450
|
-
return "Solana";
|
|
12451
|
-
default:
|
|
12452
|
-
return "Unknown";
|
|
12423
|
+
async generateFulfillmentProof(params, onProgress) {
|
|
12424
|
+
this.ensureReady();
|
|
12425
|
+
if (!this.fulfillmentNoir || !this.fulfillmentBackend) {
|
|
12426
|
+
throw new ProofGenerationError("fulfillment", "Fulfillment circuit not initialized");
|
|
12453
12427
|
}
|
|
12454
|
-
|
|
12455
|
-
|
|
12456
|
-
|
|
12457
|
-
|
|
12458
|
-
|
|
12459
|
-
const address = this.config.mockAddress && i === 0 ? this.config.mockAddress : this.generateMockAddress(i);
|
|
12460
|
-
const publicKey = this.config.mockPublicKey && i === 0 ? this.config.mockPublicKey : this.generateMockPublicKey(i);
|
|
12461
|
-
this.mockAccounts.push({
|
|
12462
|
-
address,
|
|
12463
|
-
publicKey,
|
|
12464
|
-
derivationPath: path,
|
|
12465
|
-
index: i,
|
|
12466
|
-
chain: this.chain
|
|
12428
|
+
try {
|
|
12429
|
+
onProgress?.({
|
|
12430
|
+
stage: "witness",
|
|
12431
|
+
percent: 10,
|
|
12432
|
+
message: "Preparing fulfillment witness..."
|
|
12467
12433
|
});
|
|
12434
|
+
const intentHashField = this.hexToField(params.intentHash);
|
|
12435
|
+
const recipientStealthField = this.hexToField(params.recipientStealth);
|
|
12436
|
+
const { commitmentX, commitmentY } = await this.computeOutputCommitment(
|
|
12437
|
+
params.outputAmount,
|
|
12438
|
+
params.outputBlinding
|
|
12439
|
+
);
|
|
12440
|
+
const solverSecretField = this.bytesToField(params.solverSecret);
|
|
12441
|
+
const solverId = await this.computeSolverId(solverSecretField);
|
|
12442
|
+
const outputBlindingField = this.bytesToField(params.outputBlinding);
|
|
12443
|
+
const attestation = params.oracleAttestation;
|
|
12444
|
+
const attestationRecipientField = this.hexToField(attestation.recipient);
|
|
12445
|
+
const attestationTxHashField = this.hexToField(attestation.txHash);
|
|
12446
|
+
const oracleSignature = Array.from(attestation.signature);
|
|
12447
|
+
const oracleMessageHash = await this.computeOracleMessageHash(
|
|
12448
|
+
attestation.recipient,
|
|
12449
|
+
attestation.amount,
|
|
12450
|
+
attestation.txHash,
|
|
12451
|
+
attestation.blockNumber
|
|
12452
|
+
);
|
|
12453
|
+
const oraclePubKeyX = this.config.oraclePublicKey?.x ?? new Array(32).fill(0);
|
|
12454
|
+
const oraclePubKeyY = this.config.oraclePublicKey?.y ?? new Array(32).fill(0);
|
|
12455
|
+
const witnessInputs = {
|
|
12456
|
+
intent_hash: intentHashField,
|
|
12457
|
+
output_commitment_x: commitmentX,
|
|
12458
|
+
output_commitment_y: commitmentY,
|
|
12459
|
+
recipient_stealth: recipientStealthField,
|
|
12460
|
+
min_output_amount: params.minOutputAmount.toString(),
|
|
12461
|
+
solver_id: solverId,
|
|
12462
|
+
fulfillment_time: params.fulfillmentTime.toString(),
|
|
12463
|
+
expiry: params.expiry.toString(),
|
|
12464
|
+
output_amount: params.outputAmount.toString(),
|
|
12465
|
+
output_blinding: outputBlindingField,
|
|
12466
|
+
solver_secret: solverSecretField,
|
|
12467
|
+
attestation_recipient: attestationRecipientField,
|
|
12468
|
+
attestation_amount: attestation.amount.toString(),
|
|
12469
|
+
attestation_tx_hash: attestationTxHashField,
|
|
12470
|
+
attestation_block: attestation.blockNumber.toString(),
|
|
12471
|
+
oracle_signature: oracleSignature,
|
|
12472
|
+
oracle_message_hash: oracleMessageHash,
|
|
12473
|
+
oracle_pub_key_x: oraclePubKeyX,
|
|
12474
|
+
oracle_pub_key_y: oraclePubKeyY
|
|
12475
|
+
};
|
|
12476
|
+
onProgress?.({
|
|
12477
|
+
stage: "witness",
|
|
12478
|
+
percent: 30,
|
|
12479
|
+
message: "Generating witness..."
|
|
12480
|
+
});
|
|
12481
|
+
const { witness } = await this.fulfillmentNoir.execute(witnessInputs);
|
|
12482
|
+
onProgress?.({
|
|
12483
|
+
stage: "proving",
|
|
12484
|
+
percent: 50,
|
|
12485
|
+
message: "Generating fulfillment proof..."
|
|
12486
|
+
});
|
|
12487
|
+
const proofData = await this.fulfillmentBackend.generateProof(witness);
|
|
12488
|
+
onProgress?.({
|
|
12489
|
+
stage: "complete",
|
|
12490
|
+
percent: 100,
|
|
12491
|
+
message: "Fulfillment proof generated"
|
|
12492
|
+
});
|
|
12493
|
+
const publicInputs = [
|
|
12494
|
+
`0x${intentHashField}`,
|
|
12495
|
+
`0x${commitmentX}`,
|
|
12496
|
+
`0x${commitmentY}`,
|
|
12497
|
+
`0x${recipientStealthField}`,
|
|
12498
|
+
`0x${params.minOutputAmount.toString(16).padStart(16, "0")}`,
|
|
12499
|
+
`0x${solverId}`,
|
|
12500
|
+
`0x${params.fulfillmentTime.toString(16).padStart(16, "0")}`,
|
|
12501
|
+
`0x${params.expiry.toString(16).padStart(16, "0")}`
|
|
12502
|
+
];
|
|
12503
|
+
const proof = {
|
|
12504
|
+
type: "fulfillment",
|
|
12505
|
+
proof: `0x${bytesToHex7(proofData.proof)}`,
|
|
12506
|
+
publicInputs
|
|
12507
|
+
};
|
|
12508
|
+
return { proof, publicInputs };
|
|
12509
|
+
} catch (error) {
|
|
12510
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12511
|
+
throw new ProofGenerationError(
|
|
12512
|
+
"fulfillment",
|
|
12513
|
+
`Failed to generate fulfillment proof: ${message}`,
|
|
12514
|
+
error instanceof Error ? error : void 0
|
|
12515
|
+
);
|
|
12468
12516
|
}
|
|
12469
12517
|
}
|
|
12470
|
-
|
|
12471
|
-
|
|
12472
|
-
|
|
12473
|
-
|
|
12474
|
-
|
|
12475
|
-
|
|
12476
|
-
|
|
12477
|
-
|
|
12478
|
-
|
|
12479
|
-
|
|
12480
|
-
|
|
12481
|
-
|
|
12482
|
-
|
|
12483
|
-
|
|
12484
|
-
|
|
12485
|
-
|
|
12486
|
-
|
|
12487
|
-
|
|
12488
|
-
return `0x${(0, import_utils14.bytesToHex)(sig)}`;
|
|
12489
|
-
}
|
|
12490
|
-
delay(ms) {
|
|
12491
|
-
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
12492
|
-
}
|
|
12493
|
-
};
|
|
12494
|
-
var MockTrezorAdapter = class extends BaseWalletAdapter {
|
|
12495
|
-
chain;
|
|
12496
|
-
name = "mock-trezor";
|
|
12497
|
-
config;
|
|
12498
|
-
_derivationPath;
|
|
12499
|
-
_deviceInfo = null;
|
|
12500
|
-
_account = null;
|
|
12501
|
-
mockAccounts = [];
|
|
12502
|
-
constructor(config) {
|
|
12503
|
-
super();
|
|
12504
|
-
this.chain = config.chain;
|
|
12505
|
-
this.config = {
|
|
12506
|
-
model: "T",
|
|
12507
|
-
accountIndex: 0,
|
|
12508
|
-
isLocked: false,
|
|
12509
|
-
signingDelay: 100,
|
|
12510
|
-
shouldReject: false,
|
|
12511
|
-
shouldFailConnect: false,
|
|
12512
|
-
accountCount: 5,
|
|
12513
|
-
...config
|
|
12514
|
-
};
|
|
12515
|
-
this._derivationPath = config.derivationPath ?? getDerivationPath(config.chain, config.accountIndex ?? 0);
|
|
12516
|
-
this.generateMockAccounts();
|
|
12517
|
-
}
|
|
12518
|
-
get deviceInfo() {
|
|
12519
|
-
return this._deviceInfo;
|
|
12520
|
-
}
|
|
12521
|
-
get derivationPath() {
|
|
12522
|
-
return this._derivationPath;
|
|
12523
|
-
}
|
|
12524
|
-
get account() {
|
|
12525
|
-
return this._account;
|
|
12526
|
-
}
|
|
12527
|
-
async connect() {
|
|
12528
|
-
this._connectionState = "connecting";
|
|
12529
|
-
await this.delay(200);
|
|
12530
|
-
if (this.config.shouldFailConnect) {
|
|
12531
|
-
this._connectionState = "error";
|
|
12532
|
-
throw new HardwareWalletError(
|
|
12533
|
-
"Mock connection failure",
|
|
12534
|
-
HardwareErrorCode.DEVICE_NOT_FOUND,
|
|
12535
|
-
"trezor"
|
|
12536
|
-
);
|
|
12518
|
+
/**
|
|
12519
|
+
* Verify a proof
|
|
12520
|
+
*/
|
|
12521
|
+
async verifyProof(proof) {
|
|
12522
|
+
this.ensureReady();
|
|
12523
|
+
let backend = null;
|
|
12524
|
+
switch (proof.type) {
|
|
12525
|
+
case "funding":
|
|
12526
|
+
backend = this.fundingBackend;
|
|
12527
|
+
break;
|
|
12528
|
+
case "validity":
|
|
12529
|
+
backend = this.validityBackend;
|
|
12530
|
+
break;
|
|
12531
|
+
case "fulfillment":
|
|
12532
|
+
backend = this.fulfillmentBackend;
|
|
12533
|
+
break;
|
|
12534
|
+
default:
|
|
12535
|
+
throw new ProofError(`Unknown proof type: ${proof.type}`, "SIP_4003" /* PROOF_NOT_IMPLEMENTED */);
|
|
12537
12536
|
}
|
|
12538
|
-
if (
|
|
12539
|
-
|
|
12540
|
-
|
|
12541
|
-
"
|
|
12542
|
-
HardwareErrorCode.DEVICE_LOCKED,
|
|
12543
|
-
"trezor"
|
|
12537
|
+
if (!backend) {
|
|
12538
|
+
throw new ProofError(
|
|
12539
|
+
`${proof.type} backend not initialized`,
|
|
12540
|
+
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
12544
12541
|
);
|
|
12545
12542
|
}
|
|
12546
|
-
|
|
12547
|
-
|
|
12548
|
-
|
|
12549
|
-
|
|
12550
|
-
|
|
12551
|
-
|
|
12552
|
-
|
|
12553
|
-
|
|
12554
|
-
|
|
12555
|
-
|
|
12556
|
-
|
|
12557
|
-
|
|
12558
|
-
|
|
12559
|
-
|
|
12560
|
-
|
|
12543
|
+
try {
|
|
12544
|
+
const proofHex = proof.proof.startsWith("0x") ? proof.proof.slice(2) : proof.proof;
|
|
12545
|
+
const proofBytes = hexToBytes5(proofHex);
|
|
12546
|
+
const isValid = await backend.verifyProof({
|
|
12547
|
+
proof: proofBytes,
|
|
12548
|
+
publicInputs: proof.publicInputs.map(
|
|
12549
|
+
(input) => input.startsWith("0x") ? input.slice(2) : input
|
|
12550
|
+
)
|
|
12551
|
+
});
|
|
12552
|
+
return isValid;
|
|
12553
|
+
} catch (error) {
|
|
12554
|
+
if (this.config.verbose) {
|
|
12555
|
+
console.error("[BrowserNoirProvider] Verification error:", error);
|
|
12556
|
+
}
|
|
12557
|
+
return false;
|
|
12558
|
+
}
|
|
12561
12559
|
}
|
|
12562
|
-
|
|
12563
|
-
|
|
12564
|
-
|
|
12565
|
-
|
|
12566
|
-
|
|
12567
|
-
|
|
12568
|
-
|
|
12569
|
-
"trezor"
|
|
12570
|
-
);
|
|
12560
|
+
/**
|
|
12561
|
+
* Destroy the provider and free resources
|
|
12562
|
+
*/
|
|
12563
|
+
async destroy() {
|
|
12564
|
+
if (this.fundingBackend) {
|
|
12565
|
+
await this.fundingBackend.destroy();
|
|
12566
|
+
this.fundingBackend = null;
|
|
12571
12567
|
}
|
|
12572
|
-
|
|
12573
|
-
|
|
12574
|
-
|
|
12575
|
-
|
|
12576
|
-
|
|
12568
|
+
if (this.validityBackend) {
|
|
12569
|
+
await this.validityBackend.destroy();
|
|
12570
|
+
this.validityBackend = null;
|
|
12571
|
+
}
|
|
12572
|
+
if (this.fulfillmentBackend) {
|
|
12573
|
+
await this.fulfillmentBackend.destroy();
|
|
12574
|
+
this.fulfillmentBackend = null;
|
|
12575
|
+
}
|
|
12576
|
+
if (this.worker) {
|
|
12577
|
+
this.worker.terminate();
|
|
12578
|
+
this.worker = null;
|
|
12579
|
+
}
|
|
12580
|
+
this.fundingNoir = null;
|
|
12581
|
+
this.validityNoir = null;
|
|
12582
|
+
this.fulfillmentNoir = null;
|
|
12583
|
+
this._isReady = false;
|
|
12577
12584
|
}
|
|
12578
|
-
|
|
12579
|
-
|
|
12580
|
-
|
|
12581
|
-
|
|
12582
|
-
|
|
12583
|
-
"
|
|
12584
|
-
HardwareErrorCode.USER_REJECTED,
|
|
12585
|
-
"trezor"
|
|
12585
|
+
// ─── Private Utility Methods ────────────────────────────────────────────────
|
|
12586
|
+
ensureReady() {
|
|
12587
|
+
if (!this._isReady) {
|
|
12588
|
+
throw new ProofError(
|
|
12589
|
+
"BrowserNoirProvider not initialized. Call initialize() first.",
|
|
12590
|
+
"SIP_4004" /* PROOF_PROVIDER_NOT_READY */
|
|
12586
12591
|
);
|
|
12587
12592
|
}
|
|
12588
|
-
const sig = this.generateMockSignature(
|
|
12589
|
-
new TextEncoder().encode(JSON.stringify(tx.data))
|
|
12590
|
-
);
|
|
12591
|
-
return {
|
|
12592
|
-
unsigned: tx,
|
|
12593
|
-
signatures: [
|
|
12594
|
-
{
|
|
12595
|
-
signature: sig,
|
|
12596
|
-
publicKey: this._account.publicKey
|
|
12597
|
-
}
|
|
12598
|
-
],
|
|
12599
|
-
serialized: sig
|
|
12600
|
-
};
|
|
12601
|
-
}
|
|
12602
|
-
async signAndSendTransaction(tx) {
|
|
12603
|
-
const signed = await this.signTransaction(tx);
|
|
12604
|
-
return {
|
|
12605
|
-
txHash: signed.serialized.slice(0, 66),
|
|
12606
|
-
status: "pending"
|
|
12607
|
-
};
|
|
12608
|
-
}
|
|
12609
|
-
async getBalance() {
|
|
12610
|
-
throw new WalletError(
|
|
12611
|
-
"Hardware wallets do not track balances",
|
|
12612
|
-
import_types29.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
12613
|
-
);
|
|
12614
|
-
}
|
|
12615
|
-
async getTokenBalance(_asset) {
|
|
12616
|
-
throw new WalletError(
|
|
12617
|
-
"Hardware wallets do not track balances",
|
|
12618
|
-
import_types29.WalletErrorCode.UNSUPPORTED_OPERATION
|
|
12619
|
-
);
|
|
12620
12593
|
}
|
|
12621
|
-
async
|
|
12622
|
-
this.
|
|
12623
|
-
|
|
12594
|
+
async computeCommitmentHash(balance, blindingFactor, assetId) {
|
|
12595
|
+
const blindingField = this.bytesToField(blindingFactor);
|
|
12596
|
+
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
12597
|
+
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
12598
|
+
const preimage = new Uint8Array([
|
|
12599
|
+
...this.bigintToBytes(balance, 8),
|
|
12600
|
+
...blindingFactor.slice(0, 32),
|
|
12601
|
+
...hexToBytes5(this.assetIdToField(assetId))
|
|
12602
|
+
]);
|
|
12603
|
+
const hash2 = sha25611(preimage);
|
|
12604
|
+
const commitmentHash = nobleToHex(hash2);
|
|
12605
|
+
return { commitmentHash, blindingField };
|
|
12624
12606
|
}
|
|
12625
|
-
|
|
12626
|
-
|
|
12627
|
-
|
|
12628
|
-
throw new HardwareWalletError(
|
|
12629
|
-
"Account index out of range",
|
|
12630
|
-
HardwareErrorCode.INVALID_PATH,
|
|
12631
|
-
"trezor"
|
|
12632
|
-
);
|
|
12607
|
+
assetIdToField(assetId) {
|
|
12608
|
+
if (assetId.startsWith("0x")) {
|
|
12609
|
+
return assetId.slice(2).padStart(64, "0");
|
|
12633
12610
|
}
|
|
12634
|
-
const
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
this.emitAccountChanged(previousAddress, this._account.address);
|
|
12611
|
+
const encoder = new TextEncoder();
|
|
12612
|
+
const bytes = encoder.encode(assetId);
|
|
12613
|
+
let result = 0n;
|
|
12614
|
+
for (let i = 0; i < bytes.length && i < 31; i++) {
|
|
12615
|
+
result = result * 256n + BigInt(bytes[i]);
|
|
12640
12616
|
}
|
|
12641
|
-
return
|
|
12642
|
-
}
|
|
12643
|
-
setShouldReject(shouldReject) {
|
|
12644
|
-
this.config.shouldReject = shouldReject;
|
|
12645
|
-
}
|
|
12646
|
-
setSigningDelay(delay) {
|
|
12647
|
-
this.config.signingDelay = delay;
|
|
12617
|
+
return result.toString(16).padStart(64, "0");
|
|
12648
12618
|
}
|
|
12649
|
-
|
|
12650
|
-
|
|
12651
|
-
|
|
12619
|
+
bytesToField(bytes) {
|
|
12620
|
+
let result = 0n;
|
|
12621
|
+
const len = Math.min(bytes.length, 31);
|
|
12622
|
+
for (let i = 0; i < len; i++) {
|
|
12623
|
+
result = result * 256n + BigInt(bytes[i]);
|
|
12652
12624
|
}
|
|
12653
|
-
|
|
12625
|
+
return result.toString();
|
|
12654
12626
|
}
|
|
12655
|
-
|
|
12656
|
-
|
|
12657
|
-
|
|
12627
|
+
bigintToBytes(value, length) {
|
|
12628
|
+
const bytes = new Uint8Array(length);
|
|
12629
|
+
let v = value;
|
|
12630
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
12631
|
+
bytes[i] = Number(v & 0xffn);
|
|
12632
|
+
v = v >> 8n;
|
|
12658
12633
|
}
|
|
12659
|
-
|
|
12634
|
+
return bytes;
|
|
12660
12635
|
}
|
|
12661
|
-
|
|
12662
|
-
const
|
|
12663
|
-
|
|
12664
|
-
|
|
12665
|
-
|
|
12666
|
-
|
|
12667
|
-
|
|
12668
|
-
|
|
12669
|
-
|
|
12670
|
-
derivationPath: path,
|
|
12671
|
-
index: i,
|
|
12672
|
-
chain: this.chain
|
|
12673
|
-
});
|
|
12636
|
+
hexToField(hex) {
|
|
12637
|
+
const h = hex.startsWith("0x") ? hex.slice(2) : hex;
|
|
12638
|
+
return h.padStart(64, "0");
|
|
12639
|
+
}
|
|
12640
|
+
fieldToBytes32(field) {
|
|
12641
|
+
const hex = field.padStart(64, "0");
|
|
12642
|
+
const bytes = [];
|
|
12643
|
+
for (let i = 0; i < 32; i++) {
|
|
12644
|
+
bytes.push(parseInt(hex.slice(i * 2, i * 2 + 2), 16));
|
|
12674
12645
|
}
|
|
12646
|
+
return bytes;
|
|
12675
12647
|
}
|
|
12676
|
-
|
|
12677
|
-
const
|
|
12678
|
-
|
|
12679
|
-
|
|
12648
|
+
async computeSenderCommitment(senderAddressField, senderBlindingField) {
|
|
12649
|
+
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
12650
|
+
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
12651
|
+
const addressBytes = hexToBytes5(senderAddressField);
|
|
12652
|
+
const blindingBytes = hexToBytes5(senderBlindingField.padStart(64, "0"));
|
|
12653
|
+
const preimage = new Uint8Array([...addressBytes, ...blindingBytes]);
|
|
12654
|
+
const hash2 = sha25611(preimage);
|
|
12655
|
+
const commitmentX = nobleToHex(hash2.slice(0, 16)).padStart(64, "0");
|
|
12656
|
+
const commitmentY = nobleToHex(hash2.slice(16, 32)).padStart(64, "0");
|
|
12657
|
+
return { commitmentX, commitmentY };
|
|
12680
12658
|
}
|
|
12681
|
-
|
|
12682
|
-
const
|
|
12683
|
-
|
|
12684
|
-
|
|
12685
|
-
|
|
12659
|
+
async computeNullifier(senderSecretField, intentHashField, nonceField) {
|
|
12660
|
+
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
12661
|
+
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
12662
|
+
const secretBytes = hexToBytes5(senderSecretField.padStart(64, "0"));
|
|
12663
|
+
const intentBytes = hexToBytes5(intentHashField);
|
|
12664
|
+
const nonceBytes = hexToBytes5(nonceField.padStart(64, "0"));
|
|
12665
|
+
const preimage = new Uint8Array([...secretBytes, ...intentBytes, ...nonceBytes]);
|
|
12666
|
+
const hash2 = sha25611(preimage);
|
|
12667
|
+
return nobleToHex(hash2);
|
|
12686
12668
|
}
|
|
12687
|
-
|
|
12688
|
-
const
|
|
12689
|
-
|
|
12690
|
-
|
|
12691
|
-
|
|
12692
|
-
|
|
12693
|
-
|
|
12694
|
-
|
|
12669
|
+
async computeOutputCommitment(outputAmount, outputBlinding) {
|
|
12670
|
+
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
12671
|
+
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
12672
|
+
const amountBytes = this.bigintToBytes(outputAmount, 8);
|
|
12673
|
+
const blindingBytes = outputBlinding.slice(0, 32);
|
|
12674
|
+
const preimage = new Uint8Array([...amountBytes, ...blindingBytes]);
|
|
12675
|
+
const hash2 = sha25611(preimage);
|
|
12676
|
+
const commitmentX = nobleToHex(hash2.slice(0, 16)).padStart(64, "0");
|
|
12677
|
+
const commitmentY = nobleToHex(hash2.slice(16, 32)).padStart(64, "0");
|
|
12678
|
+
return { commitmentX, commitmentY };
|
|
12695
12679
|
}
|
|
12696
|
-
|
|
12697
|
-
|
|
12680
|
+
async computeSolverId(solverSecretField) {
|
|
12681
|
+
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
12682
|
+
const { bytesToHex: nobleToHex } = await import("@noble/hashes/utils");
|
|
12683
|
+
const secretBytes = hexToBytes5(solverSecretField.padStart(64, "0"));
|
|
12684
|
+
const hash2 = sha25611(secretBytes);
|
|
12685
|
+
return nobleToHex(hash2);
|
|
12686
|
+
}
|
|
12687
|
+
async computeOracleMessageHash(recipient, amount, txHash, blockNumber) {
|
|
12688
|
+
const { sha256: sha25611 } = await import("@noble/hashes/sha256");
|
|
12689
|
+
const recipientBytes = hexToBytes5(this.hexToField(recipient));
|
|
12690
|
+
const amountBytes = this.bigintToBytes(amount, 8);
|
|
12691
|
+
const txHashBytes = hexToBytes5(this.hexToField(txHash));
|
|
12692
|
+
const blockBytes = this.bigintToBytes(blockNumber, 8);
|
|
12693
|
+
const preimage = new Uint8Array([
|
|
12694
|
+
...recipientBytes,
|
|
12695
|
+
...amountBytes,
|
|
12696
|
+
...txHashBytes,
|
|
12697
|
+
...blockBytes
|
|
12698
|
+
]);
|
|
12699
|
+
const hash2 = sha25611(preimage);
|
|
12700
|
+
return Array.from(hash2);
|
|
12701
|
+
}
|
|
12702
|
+
getPublicKeyCoordinates(privateKey) {
|
|
12703
|
+
const uncompressedPubKey = import_secp256k15.secp256k1.getPublicKey(privateKey, false);
|
|
12704
|
+
const x = Array.from(uncompressedPubKey.slice(1, 33));
|
|
12705
|
+
const y = Array.from(uncompressedPubKey.slice(33, 65));
|
|
12706
|
+
return { x, y };
|
|
12698
12707
|
}
|
|
12699
12708
|
};
|
|
12700
|
-
function createMockLedgerAdapter(config) {
|
|
12701
|
-
return new MockLedgerAdapter({ ...config, deviceType: "ledger" });
|
|
12702
|
-
}
|
|
12703
|
-
function createMockTrezorAdapter(config) {
|
|
12704
|
-
return new MockTrezorAdapter({ ...config, deviceType: "trezor" });
|
|
12705
|
-
}
|
|
12706
|
-
|
|
12707
|
-
// src/wallet/index.ts
|
|
12708
|
-
var import_types32 = require("@sip-protocol/types");
|
|
12709
12709
|
// Annotate the CommonJS export names for ESM import in node:
|
|
12710
12710
|
0 && (module.exports = {
|
|
12711
12711
|
ATTESTATION_VERSION,
|