@sip-protocol/sdk 0.7.3 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +267 -0
- package/dist/{TransportWebUSB-TQ7WZ4LE.mjs → TransportWebUSB-YQMAGJAJ.mjs} +12 -9
- package/dist/browser.d.mts +10 -4
- package/dist/browser.d.ts +10 -4
- package/dist/browser.js +47556 -19603
- package/dist/browser.mjs +628 -48
- package/dist/chunk-4GRJ5MAW.mjs +152 -0
- package/dist/chunk-5D7A3L3W.mjs +717 -0
- package/dist/chunk-64AYA5F5.mjs +7834 -0
- package/dist/chunk-GMDGB22A.mjs +379 -0
- package/dist/chunk-I534WKN7.mjs +328 -0
- package/dist/chunk-IBZVA5Y7.mjs +1003 -0
- package/dist/chunk-PRRZAWJE.mjs +223 -0
- package/dist/{chunk-UJCSKKID.mjs → chunk-XGB3TDIC.mjs} +13 -1
- package/dist/{chunk-3M3HNQCW.mjs → chunk-YWGJ77A2.mjs} +28656 -13103
- package/dist/{chunk-6WGN57S2.mjs → chunk-Z3K7W5S3.mjs} +48 -0
- package/dist/constants-LHAAUC2T.mjs +51 -0
- package/dist/dist-2OGQ7FED.mjs +3957 -0
- package/dist/dist-IFHPYLDX.mjs +254 -0
- package/dist/fulfillment_proof-ANHVPKTB.mjs +21 -0
- package/dist/funding_proof-ICFZ5LHY.mjs +21 -0
- package/dist/{index-DIBZHOOQ.d.ts → index-DXh2IGkz.d.ts} +21239 -10304
- package/dist/{index-8MQz13eJ.d.mts → index-DeE1ZzA4.d.mts} +21239 -10304
- package/dist/index.d.mts +9 -3
- package/dist/index.d.ts +9 -3
- package/dist/index.js +48396 -19623
- package/dist/index.mjs +537 -19
- package/dist/interface-Bf7w1PLW.d.mts +679 -0
- package/dist/interface-Bf7w1PLW.d.ts +679 -0
- package/dist/{noir-DKfEzWy9.d.mts → noir-kzbLVTei.d.mts} +31 -21
- package/dist/{noir-DKfEzWy9.d.ts → noir-kzbLVTei.d.ts} +31 -21
- package/dist/proofs/halo2.d.mts +151 -0
- package/dist/proofs/halo2.d.ts +151 -0
- package/dist/proofs/halo2.js +350 -0
- package/dist/proofs/halo2.mjs +11 -0
- package/dist/proofs/kimchi.d.mts +160 -0
- package/dist/proofs/kimchi.d.ts +160 -0
- package/dist/proofs/kimchi.js +431 -0
- package/dist/proofs/kimchi.mjs +13 -0
- package/dist/proofs/noir.d.mts +1 -1
- package/dist/proofs/noir.d.ts +1 -1
- package/dist/proofs/noir.js +74 -18
- package/dist/proofs/noir.mjs +84 -24
- package/dist/solana-U3MEGU7W.mjs +280 -0
- package/dist/validity_proof-3POXLPNY.mjs +21 -0
- package/package.json +44 -11
- package/src/adapters/index.ts +41 -0
- package/src/adapters/jupiter.ts +571 -0
- package/src/adapters/near-intents.ts +135 -0
- package/src/advisor/advisor.ts +653 -0
- package/src/advisor/index.ts +54 -0
- package/src/advisor/tools.ts +303 -0
- package/src/advisor/types.ts +164 -0
- package/src/chains/ethereum/announcement.ts +536 -0
- package/src/chains/ethereum/bnb-optimizations.ts +474 -0
- package/src/chains/ethereum/commitment.ts +522 -0
- package/src/chains/ethereum/constants.ts +462 -0
- package/src/chains/ethereum/deployment.ts +596 -0
- package/src/chains/ethereum/gas-estimation.ts +538 -0
- package/src/chains/ethereum/index.ts +268 -0
- package/src/chains/ethereum/optimizations.ts +614 -0
- package/src/chains/ethereum/privacy-adapter.ts +855 -0
- package/src/chains/ethereum/registry.ts +584 -0
- package/src/chains/ethereum/rpc.ts +905 -0
- package/src/chains/ethereum/stealth.ts +491 -0
- package/src/chains/ethereum/token.ts +790 -0
- package/src/chains/ethereum/transfer.ts +637 -0
- package/src/chains/ethereum/types.ts +456 -0
- package/src/chains/ethereum/viewing-key.ts +455 -0
- package/src/chains/near/commitment.ts +608 -0
- package/src/chains/near/constants.ts +284 -0
- package/src/chains/near/function-call.ts +871 -0
- package/src/chains/near/history.ts +654 -0
- package/src/chains/near/implicit-account.ts +840 -0
- package/src/chains/near/index.ts +393 -0
- package/src/chains/near/native-transfer.ts +658 -0
- package/src/chains/near/nep141.ts +775 -0
- package/src/chains/near/privacy-adapter.ts +889 -0
- package/src/chains/near/resolver.ts +971 -0
- package/src/chains/near/rpc.ts +1016 -0
- package/src/chains/near/stealth.ts +419 -0
- package/src/chains/near/types.ts +317 -0
- package/src/chains/near/viewing-key.ts +876 -0
- package/src/chains/solana/anchor-transfer.ts +386 -0
- package/src/chains/solana/commitment.ts +577 -0
- package/src/chains/solana/constants.ts +126 -12
- package/src/chains/solana/ephemeral-keys.ts +543 -0
- package/src/chains/solana/index.ts +252 -1
- package/src/chains/solana/key-derivation.ts +418 -0
- package/src/chains/solana/kit-compat.ts +334 -0
- package/src/chains/solana/optimizations.ts +560 -0
- package/src/chains/solana/privacy-adapter.ts +605 -0
- package/src/chains/solana/providers/generic.ts +47 -6
- package/src/chains/solana/providers/helius-enhanced-types.ts +336 -0
- package/src/chains/solana/providers/helius-enhanced.ts +623 -0
- package/src/chains/solana/providers/helius.ts +186 -33
- package/src/chains/solana/providers/index.ts +31 -0
- package/src/chains/solana/providers/interface.ts +61 -18
- package/src/chains/solana/providers/quicknode.ts +409 -0
- package/src/chains/solana/providers/triton.ts +426 -0
- package/src/chains/solana/providers/webhook.ts +338 -67
- package/src/chains/solana/rpc-client.ts +1150 -0
- package/src/chains/solana/scan.ts +83 -66
- package/src/chains/solana/sol-transfer.ts +732 -0
- package/src/chains/solana/spl-transfer.ts +886 -0
- package/src/chains/solana/stealth-scanner.ts +703 -0
- package/src/chains/solana/sunspot-verifier.ts +453 -0
- package/src/chains/solana/transaction-builder.ts +755 -0
- package/src/chains/solana/transfer.ts +74 -5
- package/src/chains/solana/types.ts +57 -6
- package/src/chains/solana/utils.ts +110 -0
- package/src/chains/solana/viewing-key.ts +807 -0
- package/src/compliance/fireblocks.ts +921 -0
- package/src/compliance/index.ts +23 -0
- package/src/compliance/range-sas.ts +398 -33
- package/src/config/endpoints.ts +100 -0
- package/src/crypto.ts +11 -8
- package/src/errors.ts +82 -0
- package/src/evm/erc4337-relayer.ts +830 -0
- package/src/evm/index.ts +47 -0
- package/src/fees/calculator.ts +396 -0
- package/src/fees/index.ts +87 -0
- package/src/fees/near-contract.ts +429 -0
- package/src/fees/types.ts +268 -0
- package/src/index.ts +686 -1
- package/src/intent.ts +6 -3
- package/src/logger.ts +324 -0
- package/src/network/index.ts +80 -0
- package/src/network/proxy.ts +691 -0
- package/src/optimizations/index.ts +541 -0
- package/src/oracle/types.ts +1 -0
- package/src/privacy-backends/arcium-types.ts +727 -0
- package/src/privacy-backends/arcium.ts +719 -0
- package/src/privacy-backends/combined-privacy.ts +866 -0
- package/src/privacy-backends/cspl-token.ts +595 -0
- package/src/privacy-backends/cspl-types.ts +512 -0
- package/src/privacy-backends/cspl.ts +907 -0
- package/src/privacy-backends/health.ts +488 -0
- package/src/privacy-backends/inco-types.ts +323 -0
- package/src/privacy-backends/inco.ts +616 -0
- package/src/privacy-backends/index.ts +254 -4
- package/src/privacy-backends/interface.ts +649 -6
- package/src/privacy-backends/lru-cache.ts +343 -0
- package/src/privacy-backends/magicblock.ts +458 -0
- package/src/privacy-backends/mock.ts +258 -0
- package/src/privacy-backends/privacycash.ts +13 -17
- package/src/privacy-backends/private-swap.ts +570 -0
- package/src/privacy-backends/rate-limiter.ts +683 -0
- package/src/privacy-backends/registry.ts +414 -2
- package/src/privacy-backends/router.ts +283 -3
- package/src/privacy-backends/shadowwire.ts +449 -0
- package/src/privacy-backends/sip-native.ts +3 -0
- package/src/privacy-logger.ts +191 -0
- package/src/production-safety.ts +373 -0
- package/src/proofs/aggregator.ts +1029 -0
- package/src/proofs/browser-composer.ts +1150 -0
- package/src/proofs/browser.ts +113 -25
- package/src/proofs/cache/index.ts +127 -0
- package/src/proofs/cache/interface.ts +545 -0
- package/src/proofs/cache/key-generator.ts +188 -0
- package/src/proofs/cache/lru-cache.ts +481 -0
- package/src/proofs/cache/multi-tier-cache.ts +575 -0
- package/src/proofs/cache/persistent-cache.ts +788 -0
- package/src/proofs/compliance-proof.ts +872 -0
- package/src/proofs/composer/base.ts +923 -0
- package/src/proofs/composer/index.ts +25 -0
- package/src/proofs/composer/interface.ts +518 -0
- package/src/proofs/composer/types.ts +383 -0
- package/src/proofs/converters/halo2.ts +452 -0
- package/src/proofs/converters/index.ts +208 -0
- package/src/proofs/converters/interface.ts +363 -0
- package/src/proofs/converters/kimchi.ts +462 -0
- package/src/proofs/converters/noir.ts +451 -0
- package/src/proofs/fallback.ts +888 -0
- package/src/proofs/halo2.ts +42 -0
- package/src/proofs/index.ts +471 -0
- package/src/proofs/interface.ts +13 -0
- package/src/proofs/kimchi.ts +42 -0
- package/src/proofs/lazy.ts +1004 -0
- package/src/proofs/mock.ts +25 -1
- package/src/proofs/noir.ts +110 -29
- package/src/proofs/orchestrator.ts +960 -0
- package/src/proofs/parallel/concurrency.ts +297 -0
- package/src/proofs/parallel/dependency-graph.ts +602 -0
- package/src/proofs/parallel/executor.ts +420 -0
- package/src/proofs/parallel/index.ts +131 -0
- package/src/proofs/parallel/interface.ts +685 -0
- package/src/proofs/parallel/worker-pool.ts +644 -0
- package/src/proofs/providers/halo2.ts +560 -0
- package/src/proofs/providers/index.ts +34 -0
- package/src/proofs/providers/kimchi.ts +641 -0
- package/src/proofs/validator.ts +881 -0
- package/src/proofs/verifier.ts +867 -0
- package/src/quantum/index.ts +112 -0
- package/src/quantum/winternitz-vault.ts +639 -0
- package/src/quantum/wots.ts +611 -0
- package/src/settlement/backends/direct-chain.ts +1 -0
- package/src/settlement/index.ts +9 -0
- package/src/settlement/router.ts +732 -46
- package/src/solana/index.ts +72 -0
- package/src/solana/jito-relayer.ts +687 -0
- package/src/solana/noir-verifier-types.ts +430 -0
- package/src/solana/noir-verifier.ts +816 -0
- package/src/stealth/address-derivation.ts +193 -0
- package/src/stealth/ed25519.ts +431 -0
- package/src/stealth/index.ts +233 -0
- package/src/stealth/meta-address.ts +221 -0
- package/src/stealth/secp256k1.ts +368 -0
- package/src/stealth/utils.ts +194 -0
- package/src/stealth.ts +50 -1504
- package/src/sync/index.ts +106 -0
- package/src/sync/manager.ts +504 -0
- package/src/sync/mock-provider.ts +318 -0
- package/src/sync/oblivious.ts +625 -0
- package/src/tokens/index.ts +15 -0
- package/src/tokens/registry.ts +301 -0
- package/src/utils/deprecation.ts +94 -0
- package/src/utils/index.ts +9 -0
- package/src/wallet/ethereum/index.ts +68 -0
- package/src/wallet/ethereum/metamask-privacy.ts +420 -0
- package/src/wallet/ethereum/multi-wallet.ts +646 -0
- package/src/wallet/ethereum/privacy-adapter.ts +700 -0
- package/src/wallet/ethereum/types.ts +3 -1
- package/src/wallet/ethereum/walletconnect-adapter.ts +675 -0
- package/src/wallet/hardware/index.ts +10 -0
- package/src/wallet/hardware/ledger-privacy.ts +414 -0
- package/src/wallet/index.ts +71 -0
- package/src/wallet/near/adapter.ts +626 -0
- package/src/wallet/near/index.ts +86 -0
- package/src/wallet/near/meteor-wallet.ts +1153 -0
- package/src/wallet/near/my-near-wallet.ts +790 -0
- package/src/wallet/near/wallet-selector.ts +702 -0
- package/src/wallet/solana/adapter.ts +6 -4
- package/src/wallet/solana/index.ts +13 -0
- package/src/wallet/solana/privacy-adapter.ts +567 -0
- package/src/wallet/sui/types.ts +6 -4
- package/src/zcash/rpc-client.ts +13 -6
- package/dist/chunk-2XIVXWHA.mjs +0 -1930
- package/dist/chunk-3INS3PR5.mjs +0 -884
- package/dist/chunk-3OVABDRH.mjs +0 -17096
- package/dist/chunk-7RFRWDCW.mjs +0 -1504
- package/dist/chunk-DLDWZFYC.mjs +0 -1495
- package/dist/chunk-E6SZWREQ.mjs +0 -57
- package/dist/chunk-F6F73W35.mjs +0 -16166
- package/dist/chunk-G33LB27A.mjs +0 -16166
- package/dist/chunk-HGU6HZRC.mjs +0 -231
- package/dist/chunk-L2K34JCU.mjs +0 -1496
- package/dist/chunk-OFDBEIEK.mjs +0 -16166
- package/dist/chunk-SF7YSLF5.mjs +0 -1515
- package/dist/chunk-SN4ZDTVW.mjs +0 -16166
- package/dist/chunk-WWUSGOXE.mjs +0 -17129
- package/dist/constants-VOI7BSLK.mjs +0 -27
- package/dist/index-B71aXVzk.d.ts +0 -13264
- package/dist/index-BYZbDjal.d.ts +0 -11390
- package/dist/index-CHB3KuOB.d.mts +0 -11859
- package/dist/index-CzWPI6Le.d.ts +0 -11859
- package/dist/index-pOIIuwfV.d.mts +0 -13264
- package/dist/index-xbWjohNq.d.mts +0 -11390
- package/dist/solana-4O4K45VU.mjs +0 -46
- package/dist/solana-5EMCTPTS.mjs +0 -46
- package/dist/solana-NDABAZ6P.mjs +0 -56
- package/dist/solana-Q4NAVBTS.mjs +0 -46
- package/dist/solana-ZYO63LY5.mjs +0 -46
|
@@ -0,0 +1,522 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ethereum Pedersen Commitment Implementation
|
|
3
|
+
*
|
|
4
|
+
* Secp256k1-based Pedersen commitments for ERC-20 token privacy on Ethereum.
|
|
5
|
+
*
|
|
6
|
+
* ## Security Properties
|
|
7
|
+
*
|
|
8
|
+
* - **Hiding (Computational)**: Cannot determine value from commitment
|
|
9
|
+
* - **Binding (Computational)**: Cannot open commitment to different value
|
|
10
|
+
* - **Homomorphic**: C(v1) + C(v2) = C(v1 + v2) when blindings sum
|
|
11
|
+
*
|
|
12
|
+
* ## Secp256k1 Curve
|
|
13
|
+
*
|
|
14
|
+
* This implementation uses secp256k1 for compatibility with Ethereum's
|
|
15
|
+
* native cryptography and existing EVM tooling.
|
|
16
|
+
*
|
|
17
|
+
* ## Ethereum Token Amounts
|
|
18
|
+
*
|
|
19
|
+
* Ethereum uses uint256 for token amounts (18 decimals for ETH, varies for ERC-20).
|
|
20
|
+
* Pedersen commitments operate on values < curve order.
|
|
21
|
+
*
|
|
22
|
+
* @module chains/ethereum/commitment
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { secp256k1 } from '@noble/curves/secp256k1'
|
|
26
|
+
import { sha256 } from '@noble/hashes/sha256'
|
|
27
|
+
import { bytesToHex, randomBytes } from '@noble/hashes/utils'
|
|
28
|
+
import type { HexString } from '@sip-protocol/types'
|
|
29
|
+
import { ValidationError, CryptoError, ErrorCode } from '../../errors'
|
|
30
|
+
import type { EthereumPedersenCommitment, ERC20TokenCommitment } from './types'
|
|
31
|
+
|
|
32
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A commitment point without the blinding factor (for public sharing)
|
|
36
|
+
*/
|
|
37
|
+
export interface EthereumCommitmentPoint {
|
|
38
|
+
/** The commitment point (compressed secp256k1, 33 bytes) */
|
|
39
|
+
commitment: HexString
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Domain separation tag for H generation (Ethereum version)
|
|
46
|
+
*/
|
|
47
|
+
const H_DOMAIN = 'SIP-ETHEREUM-PEDERSEN-GENERATOR-H-v1'
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The generator G (secp256k1 base point)
|
|
51
|
+
*/
|
|
52
|
+
const G = secp256k1.ProjectivePoint.BASE
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* The secp256k1 curve order n
|
|
56
|
+
*/
|
|
57
|
+
export const SECP256K1_ORDER = secp256k1.CURVE.n
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Maximum ETH amount (theoretical max uint256, but we limit to curve order)
|
|
61
|
+
*/
|
|
62
|
+
export const MAX_ETH_AMOUNT = 2n ** 256n - 1n
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Maximum value that can be committed (must be < curve order)
|
|
66
|
+
*/
|
|
67
|
+
export const MAX_COMMITMENT_VALUE = SECP256K1_ORDER - 1n
|
|
68
|
+
|
|
69
|
+
// ─── Generator H Construction ─────────────────────────────────────────────────
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* The independent generator H (NUMS point)
|
|
73
|
+
* Constructed via hash-to-curve with nothing-up-my-sleeve string.
|
|
74
|
+
*/
|
|
75
|
+
const H = generateH()
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Generate the independent generator H using NUMS method for secp256k1
|
|
79
|
+
*
|
|
80
|
+
* Uses a hash-and-check approach:
|
|
81
|
+
* 1. Hash domain||counter to get 32 bytes
|
|
82
|
+
* 2. Try to use as x-coordinate with even y
|
|
83
|
+
* 3. If valid point and not identity/G, use it
|
|
84
|
+
*/
|
|
85
|
+
function generateH(): typeof G {
|
|
86
|
+
let counter = 0
|
|
87
|
+
|
|
88
|
+
while (counter < 256) {
|
|
89
|
+
// Create input: domain || counter
|
|
90
|
+
const input = new TextEncoder().encode(`${H_DOMAIN}:${counter}`)
|
|
91
|
+
const hashBytes = sha256(input)
|
|
92
|
+
|
|
93
|
+
try {
|
|
94
|
+
// Try to create a point with the hash as x-coordinate (compressed, even y = 0x02)
|
|
95
|
+
const compressedPoint = new Uint8Array(33)
|
|
96
|
+
compressedPoint[0] = 0x02 // even y prefix
|
|
97
|
+
compressedPoint.set(hashBytes, 1)
|
|
98
|
+
|
|
99
|
+
const point = secp256k1.ProjectivePoint.fromHex(compressedPoint)
|
|
100
|
+
|
|
101
|
+
// Verify it's not identity or G
|
|
102
|
+
if (!point.equals(secp256k1.ProjectivePoint.ZERO)) {
|
|
103
|
+
const gBytes = G.toRawBytes(true)
|
|
104
|
+
const hBytes = point.toRawBytes(true)
|
|
105
|
+
if (bytesToHex(gBytes) !== bytesToHex(hBytes)) {
|
|
106
|
+
return point
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
} catch {
|
|
110
|
+
// Not a valid x-coordinate, try next counter
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
counter++
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// Should never reach here with a proper hash function
|
|
117
|
+
throw new CryptoError(
|
|
118
|
+
'Failed to generate independent generator H after 256 attempts',
|
|
119
|
+
ErrorCode.CRYPTO_FAILED
|
|
120
|
+
)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// ─── Core Commitment Functions ────────────────────────────────────────────────
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Create a Pedersen commitment for an Ethereum amount
|
|
127
|
+
*
|
|
128
|
+
* Commitment: C = v*G + r*H where:
|
|
129
|
+
* - v is the value (amount in wei)
|
|
130
|
+
* - G is the secp256k1 generator
|
|
131
|
+
* - r is a random blinding factor
|
|
132
|
+
* - H is an independent generator (NUMS)
|
|
133
|
+
*
|
|
134
|
+
* @param value - Amount to commit (in wei or token smallest units)
|
|
135
|
+
* @param blinding - Optional blinding factor (32 bytes). Random if not provided.
|
|
136
|
+
* @returns Commitment and blinding factor
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```typescript
|
|
140
|
+
* // Commit to 1 ETH (in wei)
|
|
141
|
+
* const commitment = commitETH(10n ** 18n)
|
|
142
|
+
* console.log(commitment.commitment) // '0x02...'
|
|
143
|
+
* console.log(commitment.blinding) // '0x...' (keep secret!)
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
export function commitETH(
|
|
147
|
+
value: bigint,
|
|
148
|
+
blinding?: Uint8Array
|
|
149
|
+
): EthereumPedersenCommitment {
|
|
150
|
+
// Validate value
|
|
151
|
+
if (value < 0n) {
|
|
152
|
+
throw new ValidationError('value must be non-negative', 'value')
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
if (value > MAX_COMMITMENT_VALUE) {
|
|
156
|
+
throw new ValidationError(
|
|
157
|
+
`value must be less than curve order (${MAX_COMMITMENT_VALUE})`,
|
|
158
|
+
'value'
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Generate or use provided blinding factor
|
|
163
|
+
const blindingBytes = blinding ?? randomBytes(32)
|
|
164
|
+
|
|
165
|
+
// Convert blinding to scalar (mod n)
|
|
166
|
+
const blindingScalar = bytesToBigInt(blindingBytes) % SECP256K1_ORDER
|
|
167
|
+
|
|
168
|
+
// Compute commitment: C = v*G + r*H
|
|
169
|
+
// Special case: if value is 0, commitment is just r*H
|
|
170
|
+
let commitment: typeof G
|
|
171
|
+
if (value === 0n) {
|
|
172
|
+
commitment = H.multiply(blindingScalar)
|
|
173
|
+
} else {
|
|
174
|
+
const vG = G.multiply(value)
|
|
175
|
+
const rH = H.multiply(blindingScalar)
|
|
176
|
+
commitment = vG.add(rH)
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Compress the commitment point
|
|
180
|
+
const commitmentBytes = commitment.toRawBytes(true)
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
commitment: `0x${bytesToHex(commitmentBytes)}` as HexString,
|
|
184
|
+
blinding: `0x${bytesToHex(blindingBytes)}` as HexString,
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Verify a Pedersen commitment opening
|
|
190
|
+
*
|
|
191
|
+
* Checks that C = v*G + r*H for the given value and blinding.
|
|
192
|
+
*
|
|
193
|
+
* @param commitment - The commitment to verify
|
|
194
|
+
* @param value - The claimed value
|
|
195
|
+
* @param blinding - The blinding factor
|
|
196
|
+
* @returns True if the opening is valid
|
|
197
|
+
*
|
|
198
|
+
* @example
|
|
199
|
+
* ```typescript
|
|
200
|
+
* const isValid = verifyOpeningETH(
|
|
201
|
+
* commitment.commitment,
|
|
202
|
+
* originalValue,
|
|
203
|
+
* commitment.blinding
|
|
204
|
+
* )
|
|
205
|
+
* console.log(isValid) // true
|
|
206
|
+
* ```
|
|
207
|
+
*/
|
|
208
|
+
export function verifyOpeningETH(
|
|
209
|
+
commitment: HexString,
|
|
210
|
+
value: bigint,
|
|
211
|
+
blinding: HexString
|
|
212
|
+
): boolean {
|
|
213
|
+
try {
|
|
214
|
+
// Parse commitment point
|
|
215
|
+
const commitmentBytes = hexToBytes(commitment.slice(2))
|
|
216
|
+
const commitmentPoint = secp256k1.ProjectivePoint.fromHex(commitmentBytes)
|
|
217
|
+
|
|
218
|
+
// Parse blinding factor
|
|
219
|
+
const blindingBytes = hexToBytes(blinding.slice(2))
|
|
220
|
+
const blindingScalar = bytesToBigInt(blindingBytes) % SECP256K1_ORDER
|
|
221
|
+
|
|
222
|
+
// Recompute expected commitment
|
|
223
|
+
let expectedCommitment: typeof G
|
|
224
|
+
if (value === 0n) {
|
|
225
|
+
expectedCommitment = H.multiply(blindingScalar)
|
|
226
|
+
} else {
|
|
227
|
+
const vG = G.multiply(value)
|
|
228
|
+
const rH = H.multiply(blindingScalar)
|
|
229
|
+
expectedCommitment = vG.add(rH)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Compare
|
|
233
|
+
return commitmentPoint.equals(expectedCommitment)
|
|
234
|
+
} catch {
|
|
235
|
+
return false
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
// ─── ERC-20 Token Commitments ─────────────────────────────────────────────────
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Create a Pedersen commitment for an ERC-20 token amount
|
|
243
|
+
*
|
|
244
|
+
* @param amount - Amount in token's smallest units
|
|
245
|
+
* @param tokenContract - ERC-20 token contract address
|
|
246
|
+
* @param decimals - Token decimals
|
|
247
|
+
* @param blinding - Optional blinding factor
|
|
248
|
+
* @returns Token commitment with metadata
|
|
249
|
+
*
|
|
250
|
+
* @example
|
|
251
|
+
* ```typescript
|
|
252
|
+
* // Commit to 100 USDC (6 decimals)
|
|
253
|
+
* const commitment = commitERC20Token(
|
|
254
|
+
* 100_000_000n, // 100 USDC in smallest units
|
|
255
|
+
* '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48',
|
|
256
|
+
* 6
|
|
257
|
+
* )
|
|
258
|
+
* ```
|
|
259
|
+
*/
|
|
260
|
+
export function commitERC20Token(
|
|
261
|
+
amount: bigint,
|
|
262
|
+
tokenContract: HexString,
|
|
263
|
+
decimals: number,
|
|
264
|
+
blinding?: Uint8Array
|
|
265
|
+
): ERC20TokenCommitment {
|
|
266
|
+
const base = commitETH(amount, blinding)
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
...base,
|
|
270
|
+
tokenContract,
|
|
271
|
+
decimals,
|
|
272
|
+
amountRaw: amount,
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Verify an ERC-20 token commitment
|
|
278
|
+
*
|
|
279
|
+
* @param tokenCommitment - The token commitment to verify
|
|
280
|
+
* @param expectedAmount - The expected amount
|
|
281
|
+
* @returns True if valid
|
|
282
|
+
*/
|
|
283
|
+
export function verifyERC20TokenCommitment(
|
|
284
|
+
tokenCommitment: ERC20TokenCommitment,
|
|
285
|
+
expectedAmount: bigint
|
|
286
|
+
): boolean {
|
|
287
|
+
return verifyOpeningETH(
|
|
288
|
+
tokenCommitment.commitment,
|
|
289
|
+
expectedAmount,
|
|
290
|
+
tokenCommitment.blinding
|
|
291
|
+
)
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// ─── Homomorphic Operations ───────────────────────────────────────────────────
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Add two commitments (homomorphic addition)
|
|
298
|
+
*
|
|
299
|
+
* C(v1, r1) + C(v2, r2) = C(v1+v2, r1+r2)
|
|
300
|
+
*
|
|
301
|
+
* @param c1 - First commitment
|
|
302
|
+
* @param c2 - Second commitment
|
|
303
|
+
* @returns Sum commitment point
|
|
304
|
+
*
|
|
305
|
+
* @example
|
|
306
|
+
* ```typescript
|
|
307
|
+
* const c1 = commitETH(100n)
|
|
308
|
+
* const c2 = commitETH(50n)
|
|
309
|
+
* const sum = addCommitmentsETH(c1.commitment, c2.commitment)
|
|
310
|
+
* // sum.commitment == commitment of 150n with r1+r2 blinding
|
|
311
|
+
* ```
|
|
312
|
+
*/
|
|
313
|
+
export function addCommitmentsETH(
|
|
314
|
+
c1: HexString,
|
|
315
|
+
c2: HexString
|
|
316
|
+
): EthereumCommitmentPoint {
|
|
317
|
+
const point1 = secp256k1.ProjectivePoint.fromHex(hexToBytes(c1.slice(2)))
|
|
318
|
+
const point2 = secp256k1.ProjectivePoint.fromHex(hexToBytes(c2.slice(2)))
|
|
319
|
+
|
|
320
|
+
const sum = point1.add(point2)
|
|
321
|
+
const sumBytes = sum.toRawBytes(true)
|
|
322
|
+
|
|
323
|
+
return {
|
|
324
|
+
commitment: `0x${bytesToHex(sumBytes)}` as HexString,
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Subtract two commitments (homomorphic subtraction)
|
|
330
|
+
*
|
|
331
|
+
* C(v1, r1) - C(v2, r2) = C(v1-v2, r1-r2)
|
|
332
|
+
*
|
|
333
|
+
* @param c1 - First commitment
|
|
334
|
+
* @param c2 - Second commitment
|
|
335
|
+
* @returns Difference commitment point
|
|
336
|
+
*/
|
|
337
|
+
export function subtractCommitmentsETH(
|
|
338
|
+
c1: HexString,
|
|
339
|
+
c2: HexString
|
|
340
|
+
): EthereumCommitmentPoint {
|
|
341
|
+
const point1 = secp256k1.ProjectivePoint.fromHex(hexToBytes(c1.slice(2)))
|
|
342
|
+
const point2 = secp256k1.ProjectivePoint.fromHex(hexToBytes(c2.slice(2)))
|
|
343
|
+
|
|
344
|
+
const diff = point1.subtract(point2)
|
|
345
|
+
const diffBytes = diff.toRawBytes(true)
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
commitment: `0x${bytesToHex(diffBytes)}` as HexString,
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/**
|
|
353
|
+
* Add two blinding factors (mod curve order)
|
|
354
|
+
*
|
|
355
|
+
* @param b1 - First blinding factor
|
|
356
|
+
* @param b2 - Second blinding factor
|
|
357
|
+
* @returns Sum of blindings
|
|
358
|
+
*/
|
|
359
|
+
export function addBlindingsETH(b1: HexString, b2: HexString): HexString {
|
|
360
|
+
const scalar1 = bytesToBigInt(hexToBytes(b1.slice(2)))
|
|
361
|
+
const scalar2 = bytesToBigInt(hexToBytes(b2.slice(2)))
|
|
362
|
+
|
|
363
|
+
const sum = (scalar1 + scalar2) % SECP256K1_ORDER
|
|
364
|
+
const sumBytes = bigIntToBytes(sum, 32)
|
|
365
|
+
|
|
366
|
+
return `0x${bytesToHex(sumBytes)}` as HexString
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* Subtract two blinding factors (mod curve order)
|
|
371
|
+
*
|
|
372
|
+
* @param b1 - First blinding factor
|
|
373
|
+
* @param b2 - Second blinding factor
|
|
374
|
+
* @returns Difference of blindings
|
|
375
|
+
*/
|
|
376
|
+
export function subtractBlindingsETH(b1: HexString, b2: HexString): HexString {
|
|
377
|
+
const scalar1 = bytesToBigInt(hexToBytes(b1.slice(2)))
|
|
378
|
+
const scalar2 = bytesToBigInt(hexToBytes(b2.slice(2)))
|
|
379
|
+
|
|
380
|
+
// Handle underflow with modular arithmetic
|
|
381
|
+
const diff = (scalar1 - scalar2 + SECP256K1_ORDER) % SECP256K1_ORDER
|
|
382
|
+
const diffBytes = bigIntToBytes(diff, 32)
|
|
383
|
+
|
|
384
|
+
return `0x${bytesToHex(diffBytes)}` as HexString
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// ─── Utility Functions ────────────────────────────────────────────────────────
|
|
388
|
+
|
|
389
|
+
/**
|
|
390
|
+
* Get the generators G and H
|
|
391
|
+
*
|
|
392
|
+
* @returns Object with G and H as hex strings
|
|
393
|
+
*/
|
|
394
|
+
export function getGeneratorsETH(): { G: HexString; H: HexString } {
|
|
395
|
+
return {
|
|
396
|
+
G: `0x${bytesToHex(G.toRawBytes(true))}` as HexString,
|
|
397
|
+
H: `0x${bytesToHex(H.toRawBytes(true))}` as HexString,
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Generate a random blinding factor
|
|
403
|
+
*
|
|
404
|
+
* @returns Random 32-byte blinding factor
|
|
405
|
+
*/
|
|
406
|
+
export function generateBlindingETH(): HexString {
|
|
407
|
+
const blinding = randomBytes(32)
|
|
408
|
+
return `0x${bytesToHex(blinding)}` as HexString
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Convert ETH amount to wei
|
|
413
|
+
*
|
|
414
|
+
* @param amount - Amount in ETH (as number or string)
|
|
415
|
+
* @param decimals - Decimals (default 18 for ETH)
|
|
416
|
+
* @returns Amount in wei
|
|
417
|
+
*
|
|
418
|
+
* @example
|
|
419
|
+
* ```typescript
|
|
420
|
+
* const wei = toWei(1.5) // 1.5 ETH
|
|
421
|
+
* console.log(wei) // 1500000000000000000n
|
|
422
|
+
* ```
|
|
423
|
+
*/
|
|
424
|
+
export function toWei(amount: number | string, decimals: number = 18): bigint {
|
|
425
|
+
const str = typeof amount === 'number' ? amount.toString() : amount
|
|
426
|
+
const [whole, fraction = ''] = str.split('.')
|
|
427
|
+
|
|
428
|
+
// Pad or truncate fraction to match decimals
|
|
429
|
+
const paddedFraction = fraction.padEnd(decimals, '0').slice(0, decimals)
|
|
430
|
+
const combined = `${whole}${paddedFraction}`
|
|
431
|
+
|
|
432
|
+
return BigInt(combined)
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Convert wei to ETH
|
|
437
|
+
*
|
|
438
|
+
* @param wei - Amount in wei
|
|
439
|
+
* @param decimals - Decimals (default 18 for ETH)
|
|
440
|
+
* @returns Amount in ETH as string
|
|
441
|
+
*
|
|
442
|
+
* @example
|
|
443
|
+
* ```typescript
|
|
444
|
+
* const eth = fromWei(1500000000000000000n)
|
|
445
|
+
* console.log(eth) // '1.5'
|
|
446
|
+
* ```
|
|
447
|
+
*/
|
|
448
|
+
export function fromWei(wei: bigint, decimals: number = 18): string {
|
|
449
|
+
const divisor = 10n ** BigInt(decimals)
|
|
450
|
+
const whole = wei / divisor
|
|
451
|
+
const fraction = wei % divisor
|
|
452
|
+
|
|
453
|
+
if (fraction === 0n) {
|
|
454
|
+
return whole.toString()
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
const fractionStr = fraction.toString().padStart(decimals, '0')
|
|
458
|
+
// Remove trailing zeros
|
|
459
|
+
const trimmed = fractionStr.replace(/0+$/, '')
|
|
460
|
+
|
|
461
|
+
return `${whole}.${trimmed}`
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
/**
|
|
465
|
+
* Create a zero commitment (for proving zero balance)
|
|
466
|
+
*
|
|
467
|
+
* @returns Commitment to zero value
|
|
468
|
+
*/
|
|
469
|
+
export function createZeroCommitmentETH(): EthereumPedersenCommitment {
|
|
470
|
+
return commitETH(0n)
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/**
|
|
474
|
+
* Check if a commitment is to zero (given the blinding)
|
|
475
|
+
*
|
|
476
|
+
* @param commitment - The commitment
|
|
477
|
+
* @param blinding - The blinding factor
|
|
478
|
+
* @returns True if commitment is to zero
|
|
479
|
+
*/
|
|
480
|
+
export function isZeroCommitmentETH(
|
|
481
|
+
commitment: HexString,
|
|
482
|
+
blinding: HexString
|
|
483
|
+
): boolean {
|
|
484
|
+
return verifyOpeningETH(commitment, 0n, blinding)
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// ─── Helper Functions ─────────────────────────────────────────────────────────
|
|
488
|
+
|
|
489
|
+
/**
|
|
490
|
+
* Convert bytes to bigint (big-endian)
|
|
491
|
+
*/
|
|
492
|
+
function bytesToBigInt(bytes: Uint8Array): bigint {
|
|
493
|
+
let result = 0n
|
|
494
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
495
|
+
result = (result << 8n) + BigInt(bytes[i])
|
|
496
|
+
}
|
|
497
|
+
return result
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
/**
|
|
501
|
+
* Convert bigint to bytes (big-endian)
|
|
502
|
+
*/
|
|
503
|
+
function bigIntToBytes(num: bigint, length: number): Uint8Array {
|
|
504
|
+
const bytes = new Uint8Array(length)
|
|
505
|
+
let n = num
|
|
506
|
+
for (let i = length - 1; i >= 0; i--) {
|
|
507
|
+
bytes[i] = Number(n & 0xffn)
|
|
508
|
+
n >>= 8n
|
|
509
|
+
}
|
|
510
|
+
return bytes
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Convert hex string to bytes
|
|
515
|
+
*/
|
|
516
|
+
function hexToBytes(hex: string): Uint8Array {
|
|
517
|
+
const bytes = new Uint8Array(hex.length / 2)
|
|
518
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
519
|
+
bytes[i] = parseInt(hex.substr(i * 2, 2), 16)
|
|
520
|
+
}
|
|
521
|
+
return bytes
|
|
522
|
+
}
|