@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,608 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NEAR Pedersen Commitment Implementation
|
|
3
|
+
*
|
|
4
|
+
* Ed25519-based Pedersen commitments for NEP-141 token privacy on NEAR.
|
|
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
|
+
* ## Ed25519 Curve
|
|
13
|
+
*
|
|
14
|
+
* This implementation uses ed25519 (Curve25519 in Edwards form) for
|
|
15
|
+
* compatibility with NEAR's native cryptography and implicit accounts.
|
|
16
|
+
*
|
|
17
|
+
* ## NEAR Token Amounts
|
|
18
|
+
*
|
|
19
|
+
* NEAR uses u128 for native NEAR (24 decimals) and u128 for NEP-141 tokens.
|
|
20
|
+
* Pedersen commitments operate on values < curve order (2^252 + ...).
|
|
21
|
+
*
|
|
22
|
+
* @module chains/near/commitment
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { ed25519 } from '@noble/curves/ed25519'
|
|
26
|
+
import { sha256 } from '@noble/hashes/sha2'
|
|
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 { isValidHex } from '../../validation'
|
|
31
|
+
|
|
32
|
+
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* A Pedersen commitment with associated blinding factor
|
|
36
|
+
*/
|
|
37
|
+
export interface NEARPedersenCommitment {
|
|
38
|
+
/**
|
|
39
|
+
* The commitment point C = v*G + r*H (compressed ed25519, 32 bytes)
|
|
40
|
+
*/
|
|
41
|
+
commitment: HexString
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* The blinding factor r (32 bytes, secret)
|
|
45
|
+
* Required to open/verify the commitment
|
|
46
|
+
*/
|
|
47
|
+
blinding: HexString
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A commitment point without the blinding factor (for public sharing)
|
|
52
|
+
*/
|
|
53
|
+
export interface NEARCommitmentPoint {
|
|
54
|
+
/**
|
|
55
|
+
* The commitment point (compressed ed25519, 32 bytes)
|
|
56
|
+
*/
|
|
57
|
+
commitment: HexString
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* NEP-141 token commitment with amount and token info
|
|
62
|
+
*/
|
|
63
|
+
export interface NEP141TokenCommitment extends NEARPedersenCommitment {
|
|
64
|
+
/**
|
|
65
|
+
* NEP-141 token contract address
|
|
66
|
+
*/
|
|
67
|
+
tokenContract: string
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Token decimals (e.g., 24 for NEAR, 6 for USDC)
|
|
71
|
+
*/
|
|
72
|
+
decimals: number
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Original amount in smallest units (u128)
|
|
76
|
+
*/
|
|
77
|
+
amountRaw?: bigint
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ─── Constants ────────────────────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Domain separation tag for H generation (NEAR version)
|
|
84
|
+
*/
|
|
85
|
+
const H_DOMAIN = 'SIP-NEAR-PEDERSEN-GENERATOR-H-v1'
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* The generator G (ed25519 base point)
|
|
89
|
+
*/
|
|
90
|
+
const G = ed25519.ExtendedPoint.BASE
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* The ed25519 curve order L (number of points in the subgroup)
|
|
94
|
+
*/
|
|
95
|
+
export const ED25519_ORDER = 2n ** 252n + 27742317777372353535851937790883648493n
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Ed25519 cofactor (the curve has order 8*L where L is the prime subgroup order)
|
|
99
|
+
*/
|
|
100
|
+
const ED25519_COFACTOR = 8n
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Maximum NEAR amount (u128::MAX)
|
|
104
|
+
* Note: Actual NEAR total supply is much less, but u128 is the storage type
|
|
105
|
+
*/
|
|
106
|
+
export const MAX_NEAR_AMOUNT = 2n ** 128n - 1n
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Maximum value that can be committed (must be < curve order)
|
|
110
|
+
*/
|
|
111
|
+
export const MAX_COMMITMENT_VALUE = ED25519_ORDER - 1n
|
|
112
|
+
|
|
113
|
+
// ─── Generator H Construction ─────────────────────────────────────────────────
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* The independent generator H (NUMS point)
|
|
117
|
+
* Constructed via hash-to-curve with nothing-up-my-sleeve string.
|
|
118
|
+
*/
|
|
119
|
+
const H = generateH()
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Generate the independent generator H using NUMS method for ed25519
|
|
123
|
+
*
|
|
124
|
+
* Uses a hash-and-check approach:
|
|
125
|
+
* 1. Hash domain||counter to get 32 bytes
|
|
126
|
+
* 2. Try to decode as an ed25519 point
|
|
127
|
+
* 3. Clear the cofactor by multiplying by 8
|
|
128
|
+
* 4. If valid and not identity/G, use it
|
|
129
|
+
*/
|
|
130
|
+
function generateH(): typeof G {
|
|
131
|
+
let counter = 0
|
|
132
|
+
|
|
133
|
+
while (counter < 256) {
|
|
134
|
+
const input = new TextEncoder().encode(`${H_DOMAIN}:${counter}`)
|
|
135
|
+
const hashBytes = sha256(input)
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const rawPoint = ed25519.ExtendedPoint.fromHex(hashBytes)
|
|
139
|
+
const point = rawPoint.multiply(ED25519_COFACTOR)
|
|
140
|
+
|
|
141
|
+
if (!point.equals(ed25519.ExtendedPoint.ZERO)) {
|
|
142
|
+
const gBytes = G.toRawBytes()
|
|
143
|
+
const hBytes = point.toRawBytes()
|
|
144
|
+
if (bytesToHex(gBytes) !== bytesToHex(hBytes)) {
|
|
145
|
+
return point
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
// Not a valid point encoding, try next counter
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
counter++
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
throw new CryptoError(
|
|
156
|
+
'Failed to generate H point - this should never happen',
|
|
157
|
+
ErrorCode.CRYPTO_FAILED,
|
|
158
|
+
{ context: { domain: H_DOMAIN } }
|
|
159
|
+
)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ─── Utility Functions ────────────────────────────────────────────────────────
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Convert bytes to bigint (little-endian)
|
|
166
|
+
*/
|
|
167
|
+
function bytesToBigInt(bytes: Uint8Array): bigint {
|
|
168
|
+
let result = 0n
|
|
169
|
+
for (let i = bytes.length - 1; i >= 0; i--) {
|
|
170
|
+
result = result * 256n + BigInt(bytes[i])
|
|
171
|
+
}
|
|
172
|
+
return result
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Convert bigint to bytes (little-endian)
|
|
177
|
+
*/
|
|
178
|
+
function bigIntToBytes(n: bigint, length: number): Uint8Array {
|
|
179
|
+
const result = new Uint8Array(length)
|
|
180
|
+
let temp = n
|
|
181
|
+
for (let i = 0; i < length; i++) {
|
|
182
|
+
result[i] = Number(temp & 0xffn)
|
|
183
|
+
temp = temp >> 8n
|
|
184
|
+
}
|
|
185
|
+
return result
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Convert hex string to bytes
|
|
190
|
+
*/
|
|
191
|
+
function hexToBytes(hex: string): Uint8Array {
|
|
192
|
+
const result = new Uint8Array(hex.length / 2)
|
|
193
|
+
for (let i = 0; i < hex.length; i += 2) {
|
|
194
|
+
result[i / 2] = parseInt(hex.substring(i, i + 2), 16)
|
|
195
|
+
}
|
|
196
|
+
return result
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// ─── Core Functions ───────────────────────────────────────────────────────────
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Create a Pedersen commitment to a value (ed25519)
|
|
203
|
+
*
|
|
204
|
+
* C = v*G + r*H
|
|
205
|
+
*
|
|
206
|
+
* @param value - The value to commit to (must be < curve order)
|
|
207
|
+
* @param blinding - Optional blinding factor (random 32 bytes if not provided)
|
|
208
|
+
* @returns The commitment and blinding factor
|
|
209
|
+
*
|
|
210
|
+
* @example
|
|
211
|
+
* ```typescript
|
|
212
|
+
* // Commit to 1 NEAR (in yoctoNEAR)
|
|
213
|
+
* const { commitment, blinding } = commitNEAR(1_000_000_000_000_000_000_000_000n)
|
|
214
|
+
*
|
|
215
|
+
* // Verify the commitment
|
|
216
|
+
* const valid = verifyOpeningNEAR(commitment, 1_000_000_000_000_000_000_000_000n, blinding)
|
|
217
|
+
* ```
|
|
218
|
+
*/
|
|
219
|
+
export function commitNEAR(
|
|
220
|
+
value: bigint,
|
|
221
|
+
blinding?: Uint8Array
|
|
222
|
+
): NEARPedersenCommitment {
|
|
223
|
+
if (typeof value !== 'bigint') {
|
|
224
|
+
throw new ValidationError('must be a bigint', 'value', { received: typeof value })
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (value < 0n) {
|
|
228
|
+
throw new ValidationError('must be non-negative', 'value')
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
if (value >= ED25519_ORDER) {
|
|
232
|
+
throw new ValidationError(
|
|
233
|
+
'must be less than curve order',
|
|
234
|
+
'value',
|
|
235
|
+
{ curveOrder: ED25519_ORDER.toString(16) }
|
|
236
|
+
)
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
const r = blinding ?? randomBytes(32)
|
|
240
|
+
if (r.length !== 32) {
|
|
241
|
+
throw new ValidationError('must be 32 bytes', 'blinding', { received: r.length })
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const rScalar = bytesToBigInt(r) % ED25519_ORDER
|
|
245
|
+
if (rScalar === 0n) {
|
|
246
|
+
return commitNEAR(value, randomBytes(32))
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
let C: typeof G
|
|
250
|
+
|
|
251
|
+
if (value === 0n) {
|
|
252
|
+
C = H.multiply(rScalar)
|
|
253
|
+
} else {
|
|
254
|
+
const vG = G.multiply(value)
|
|
255
|
+
const rH = H.multiply(rScalar)
|
|
256
|
+
C = vG.add(rH)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const rScalarBytes = bigIntToBytes(rScalar, 32)
|
|
260
|
+
|
|
261
|
+
return {
|
|
262
|
+
commitment: `0x${bytesToHex(C.toRawBytes())}` as HexString,
|
|
263
|
+
blinding: `0x${bytesToHex(rScalarBytes)}` as HexString,
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Verify that a commitment opens to a specific value
|
|
269
|
+
*
|
|
270
|
+
* @param commitment - The commitment point to verify
|
|
271
|
+
* @param value - The claimed value
|
|
272
|
+
* @param blinding - The blinding factor used
|
|
273
|
+
* @returns true if the commitment opens correctly
|
|
274
|
+
*/
|
|
275
|
+
export function verifyOpeningNEAR(
|
|
276
|
+
commitment: HexString,
|
|
277
|
+
value: bigint,
|
|
278
|
+
blinding: HexString
|
|
279
|
+
): boolean {
|
|
280
|
+
try {
|
|
281
|
+
const commitmentBytes = hexToBytes(commitment.slice(2))
|
|
282
|
+
const C = ed25519.ExtendedPoint.fromHex(commitmentBytes)
|
|
283
|
+
|
|
284
|
+
const blindingBytes = hexToBytes(blinding.slice(2))
|
|
285
|
+
const rScalar = bytesToBigInt(blindingBytes) % ED25519_ORDER
|
|
286
|
+
|
|
287
|
+
let expected: typeof G
|
|
288
|
+
|
|
289
|
+
if (value === 0n) {
|
|
290
|
+
expected = H.multiply(rScalar)
|
|
291
|
+
} else if (rScalar === 0n) {
|
|
292
|
+
expected = G.multiply(value)
|
|
293
|
+
} else {
|
|
294
|
+
const vG = G.multiply(value)
|
|
295
|
+
const rH = H.multiply(rScalar)
|
|
296
|
+
expected = vG.add(rH)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return C.equals(expected)
|
|
300
|
+
} catch {
|
|
301
|
+
return false
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
// ─── NEP-141 Token Specific Functions ─────────────────────────────────────────
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Create a commitment for a NEP-141 token amount
|
|
309
|
+
*
|
|
310
|
+
* Handles NEAR token decimals and u128 amount validation.
|
|
311
|
+
*
|
|
312
|
+
* @param amount - Token amount in smallest units (u128)
|
|
313
|
+
* @param tokenContract - NEP-141 token contract address
|
|
314
|
+
* @param decimals - Token decimals (e.g., 24 for NEAR, 6 for USDC)
|
|
315
|
+
* @returns NEP-141 token commitment with metadata
|
|
316
|
+
*
|
|
317
|
+
* @example
|
|
318
|
+
* ```typescript
|
|
319
|
+
* // Commit to 100 USDC (6 decimals)
|
|
320
|
+
* const commitment = commitNEP141Token(
|
|
321
|
+
* 100_000_000n, // 100 USDC in smallest units
|
|
322
|
+
* 'usdc.near',
|
|
323
|
+
* 6
|
|
324
|
+
* )
|
|
325
|
+
* ```
|
|
326
|
+
*/
|
|
327
|
+
export function commitNEP141Token(
|
|
328
|
+
amount: bigint,
|
|
329
|
+
tokenContract: string,
|
|
330
|
+
decimals: number,
|
|
331
|
+
blinding?: Uint8Array
|
|
332
|
+
): NEP141TokenCommitment {
|
|
333
|
+
if (amount < 0n || amount > MAX_NEAR_AMOUNT) {
|
|
334
|
+
throw new ValidationError(
|
|
335
|
+
'NEP-141 token amount must be a valid u128 (0 to 2^128-1)',
|
|
336
|
+
'amount',
|
|
337
|
+
{ max: MAX_NEAR_AMOUNT.toString() }
|
|
338
|
+
)
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// For amounts larger than curve order, we need to split
|
|
342
|
+
// However, for most practical purposes (total NEAR supply is ~1.1B * 10^24),
|
|
343
|
+
// we can commit directly as long as amount < ED25519_ORDER
|
|
344
|
+
if (amount >= ED25519_ORDER) {
|
|
345
|
+
throw new ValidationError(
|
|
346
|
+
'Amount exceeds maximum committable value (curve order)',
|
|
347
|
+
'amount',
|
|
348
|
+
{ max: MAX_COMMITMENT_VALUE.toString() }
|
|
349
|
+
)
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (decimals < 0 || decimals > 24 || !Number.isInteger(decimals)) {
|
|
353
|
+
throw new ValidationError(
|
|
354
|
+
'decimals must be an integer between 0 and 24',
|
|
355
|
+
'decimals'
|
|
356
|
+
)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
const { commitment, blinding: blindingHex } = commitNEAR(amount, blinding)
|
|
360
|
+
|
|
361
|
+
return {
|
|
362
|
+
commitment,
|
|
363
|
+
blinding: blindingHex,
|
|
364
|
+
tokenContract,
|
|
365
|
+
decimals,
|
|
366
|
+
amountRaw: amount,
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Verify a NEP-141 token commitment
|
|
372
|
+
*
|
|
373
|
+
* @param tokenCommitment - The NEP-141 token commitment to verify
|
|
374
|
+
* @param expectedAmount - The expected amount in smallest units
|
|
375
|
+
* @returns true if the commitment opens correctly
|
|
376
|
+
*/
|
|
377
|
+
export function verifyNEP141TokenCommitment(
|
|
378
|
+
tokenCommitment: NEP141TokenCommitment,
|
|
379
|
+
expectedAmount: bigint
|
|
380
|
+
): boolean {
|
|
381
|
+
return verifyOpeningNEAR(
|
|
382
|
+
tokenCommitment.commitment,
|
|
383
|
+
expectedAmount,
|
|
384
|
+
tokenCommitment.blinding
|
|
385
|
+
)
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
/**
|
|
389
|
+
* Convert human-readable token amount to smallest units
|
|
390
|
+
*
|
|
391
|
+
* @param amount - Human-readable amount (e.g., 100.5)
|
|
392
|
+
* @param decimals - Token decimals
|
|
393
|
+
* @returns Amount in smallest units as bigint
|
|
394
|
+
*
|
|
395
|
+
* @example
|
|
396
|
+
* ```typescript
|
|
397
|
+
* // 1 NEAR (24 decimals) = 10^24 yoctoNEAR
|
|
398
|
+
* const units = toYoctoNEAR(1, 24)
|
|
399
|
+
* // 1_000_000_000_000_000_000_000_000n
|
|
400
|
+
*
|
|
401
|
+
* // 100.5 USDC (6 decimals) = 100,500,000 units
|
|
402
|
+
* const usdc = toYoctoNEAR(100.5, 6)
|
|
403
|
+
* // 100_500_000n
|
|
404
|
+
* ```
|
|
405
|
+
*/
|
|
406
|
+
export function toYoctoNEAR(amount: number | string, decimals: number): bigint {
|
|
407
|
+
const [whole, fraction = ''] = String(amount).split('.')
|
|
408
|
+
const paddedFraction = fraction.padEnd(decimals, '0').slice(0, decimals)
|
|
409
|
+
return BigInt(whole + paddedFraction)
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Convert smallest units to human-readable amount
|
|
414
|
+
*
|
|
415
|
+
* @param amount - Amount in smallest units
|
|
416
|
+
* @param decimals - Token decimals
|
|
417
|
+
* @returns Human-readable string
|
|
418
|
+
*
|
|
419
|
+
* @example
|
|
420
|
+
* ```typescript
|
|
421
|
+
* // 1_000_000_000_000_000_000_000_000 yoctoNEAR = "1"
|
|
422
|
+
* const readable = fromYoctoNEAR(1_000_000_000_000_000_000_000_000n, 24)
|
|
423
|
+
* // "1"
|
|
424
|
+
* ```
|
|
425
|
+
*/
|
|
426
|
+
export function fromYoctoNEAR(amount: bigint, decimals: number): string {
|
|
427
|
+
const str = amount.toString().padStart(decimals + 1, '0')
|
|
428
|
+
const whole = str.slice(0, -decimals) || '0'
|
|
429
|
+
const fraction = str.slice(-decimals).replace(/0+$/, '')
|
|
430
|
+
return fraction ? `${whole}.${fraction}` : whole
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
// ─── Homomorphic Operations ───────────────────────────────────────────────────
|
|
434
|
+
|
|
435
|
+
/**
|
|
436
|
+
* Add two commitments homomorphically (ed25519)
|
|
437
|
+
*
|
|
438
|
+
* C1 + C2 = (v1+v2)*G + (r1+r2)*H
|
|
439
|
+
*
|
|
440
|
+
* @param c1 - First commitment point
|
|
441
|
+
* @param c2 - Second commitment point
|
|
442
|
+
* @returns Sum of commitments
|
|
443
|
+
*/
|
|
444
|
+
export function addCommitmentsNEAR(
|
|
445
|
+
c1: HexString,
|
|
446
|
+
c2: HexString
|
|
447
|
+
): NEARCommitmentPoint {
|
|
448
|
+
if (!isValidHex(c1)) {
|
|
449
|
+
throw new ValidationError('must be a valid hex string', 'c1')
|
|
450
|
+
}
|
|
451
|
+
if (!isValidHex(c2)) {
|
|
452
|
+
throw new ValidationError('must be a valid hex string', 'c2')
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
let point1: typeof G
|
|
456
|
+
let point2: typeof G
|
|
457
|
+
|
|
458
|
+
try {
|
|
459
|
+
point1 = ed25519.ExtendedPoint.fromHex(hexToBytes(c1.slice(2)))
|
|
460
|
+
} catch {
|
|
461
|
+
throw new ValidationError('must be a valid ed25519 point', 'c1')
|
|
462
|
+
}
|
|
463
|
+
try {
|
|
464
|
+
point2 = ed25519.ExtendedPoint.fromHex(hexToBytes(c2.slice(2)))
|
|
465
|
+
} catch {
|
|
466
|
+
throw new ValidationError('must be a valid ed25519 point', 'c2')
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
const sum = point1.add(point2)
|
|
470
|
+
|
|
471
|
+
return {
|
|
472
|
+
commitment: `0x${bytesToHex(sum.toRawBytes())}` as HexString,
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Subtract two commitments homomorphically (ed25519)
|
|
478
|
+
*
|
|
479
|
+
* C1 - C2 = (v1-v2)*G + (r1-r2)*H
|
|
480
|
+
*
|
|
481
|
+
* @param c1 - First commitment point
|
|
482
|
+
* @param c2 - Second commitment point (to subtract)
|
|
483
|
+
* @returns Difference of commitments
|
|
484
|
+
*/
|
|
485
|
+
export function subtractCommitmentsNEAR(
|
|
486
|
+
c1: HexString,
|
|
487
|
+
c2: HexString
|
|
488
|
+
): NEARCommitmentPoint {
|
|
489
|
+
if (!isValidHex(c1)) {
|
|
490
|
+
throw new ValidationError('must be a valid hex string', 'c1')
|
|
491
|
+
}
|
|
492
|
+
if (!isValidHex(c2)) {
|
|
493
|
+
throw new ValidationError('must be a valid hex string', 'c2')
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
let point1: typeof G
|
|
497
|
+
let point2: typeof G
|
|
498
|
+
|
|
499
|
+
try {
|
|
500
|
+
point1 = ed25519.ExtendedPoint.fromHex(hexToBytes(c1.slice(2)))
|
|
501
|
+
} catch {
|
|
502
|
+
throw new ValidationError('must be a valid ed25519 point', 'c1')
|
|
503
|
+
}
|
|
504
|
+
try {
|
|
505
|
+
point2 = ed25519.ExtendedPoint.fromHex(hexToBytes(c2.slice(2)))
|
|
506
|
+
} catch {
|
|
507
|
+
throw new ValidationError('must be a valid ed25519 point', 'c2')
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const diff = point1.subtract(point2)
|
|
511
|
+
|
|
512
|
+
if (diff.equals(ed25519.ExtendedPoint.ZERO)) {
|
|
513
|
+
return {
|
|
514
|
+
commitment: ('0x' + '00'.repeat(32)) as HexString,
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
return {
|
|
519
|
+
commitment: `0x${bytesToHex(diff.toRawBytes())}` as HexString,
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
/**
|
|
524
|
+
* Add blinding factors (ed25519)
|
|
525
|
+
*
|
|
526
|
+
* @param b1 - First blinding factor
|
|
527
|
+
* @param b2 - Second blinding factor
|
|
528
|
+
* @returns Sum of blindings mod curve order
|
|
529
|
+
*/
|
|
530
|
+
export function addBlindingsNEAR(b1: HexString, b2: HexString): HexString {
|
|
531
|
+
if (!isValidHex(b1)) {
|
|
532
|
+
throw new ValidationError('must be a valid hex string', 'b1')
|
|
533
|
+
}
|
|
534
|
+
if (!isValidHex(b2)) {
|
|
535
|
+
throw new ValidationError('must be a valid hex string', 'b2')
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const b1Bytes = hexToBytes(b1.slice(2))
|
|
539
|
+
const b2Bytes = hexToBytes(b2.slice(2))
|
|
540
|
+
|
|
541
|
+
const b1Scalar = bytesToBigInt(b1Bytes)
|
|
542
|
+
const b2Scalar = bytesToBigInt(b2Bytes)
|
|
543
|
+
|
|
544
|
+
const sum = (b1Scalar + b2Scalar) % ED25519_ORDER
|
|
545
|
+
const sumBytes = bigIntToBytes(sum, 32)
|
|
546
|
+
|
|
547
|
+
return `0x${bytesToHex(sumBytes)}` as HexString
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Subtract blinding factors (ed25519)
|
|
552
|
+
*
|
|
553
|
+
* @param b1 - First blinding factor
|
|
554
|
+
* @param b2 - Second blinding factor (to subtract)
|
|
555
|
+
* @returns Difference of blindings mod curve order
|
|
556
|
+
*/
|
|
557
|
+
export function subtractBlindingsNEAR(b1: HexString, b2: HexString): HexString {
|
|
558
|
+
if (!isValidHex(b1)) {
|
|
559
|
+
throw new ValidationError('must be a valid hex string', 'b1')
|
|
560
|
+
}
|
|
561
|
+
if (!isValidHex(b2)) {
|
|
562
|
+
throw new ValidationError('must be a valid hex string', 'b2')
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
const b1Bytes = hexToBytes(b1.slice(2))
|
|
566
|
+
const b2Bytes = hexToBytes(b2.slice(2))
|
|
567
|
+
|
|
568
|
+
const b1Scalar = bytesToBigInt(b1Bytes)
|
|
569
|
+
const b2Scalar = bytesToBigInt(b2Bytes)
|
|
570
|
+
|
|
571
|
+
// Handle subtraction with modular arithmetic
|
|
572
|
+
const diff = (b1Scalar - b2Scalar + ED25519_ORDER) % ED25519_ORDER
|
|
573
|
+
const diffBytes = bigIntToBytes(diff, 32)
|
|
574
|
+
|
|
575
|
+
return `0x${bytesToHex(diffBytes)}` as HexString
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// ─── Utility Functions ────────────────────────────────────────────────────────
|
|
579
|
+
|
|
580
|
+
/**
|
|
581
|
+
* Get the generators G and H for verification/debugging
|
|
582
|
+
*
|
|
583
|
+
* @returns The generator points as hex strings
|
|
584
|
+
*/
|
|
585
|
+
export function getGeneratorsNEAR(): { G: HexString; H: HexString } {
|
|
586
|
+
return {
|
|
587
|
+
G: `0x${bytesToHex(G.toRawBytes())}` as HexString,
|
|
588
|
+
H: `0x${bytesToHex(H.toRawBytes())}` as HexString,
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
/**
|
|
593
|
+
* Generate a random blinding factor
|
|
594
|
+
*
|
|
595
|
+
* @returns Random 32-byte blinding factor as hex string
|
|
596
|
+
*/
|
|
597
|
+
export function generateBlindingNEAR(): HexString {
|
|
598
|
+
const bytes = randomBytes(32)
|
|
599
|
+
const scalar = bytesToBigInt(bytes) % ED25519_ORDER
|
|
600
|
+
|
|
601
|
+
// Ensure non-zero
|
|
602
|
+
if (scalar === 0n) {
|
|
603
|
+
return generateBlindingNEAR()
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
const scalarBytes = bigIntToBytes(scalar, 32)
|
|
607
|
+
return `0x${bytesToHex(scalarBytes)}` as HexString
|
|
608
|
+
}
|