diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000..7253a5c --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +min-release-age=7 diff --git a/circom/components.circom b/circom/components.circom index 216b6d3..7f41774 100644 --- a/circom/components.circom +++ b/circom/components.circom @@ -54,14 +54,13 @@ template PoseidonDecrypt(l) { // Check the last ciphertext element ciphertext[decryptedLength] === strategies[n].out[1]; - // If length > 3, check if the last (3 - (l mod 3)) elements of the message - // are 0 + // If length not devisible by 3 then add padding if (l % 3 > 0) { if (l % 3 == 1) { decrypted[decryptedLength - 1] === 0; + decrypted[decryptedLength - 2] === 0; } else if (l % 3 == 2) { decrypted[decryptedLength - 1] === 0; - decrypted[decryptedLength - 2] === 0; } } } @@ -113,6 +112,13 @@ template ElGamalEncrypt() { checkPoint2.x <== msg[0]; checkPoint2.y <== msg[1]; + // Verify the randomness is not zero + // With random = 0 the ciphertext degenerates to (identity, msg), which any observer can + // read, so the encrypted value would no longer be private. + component checkRandomIsZero = IsZero(); + checkRandomIsZero.in <== random; + checkRandomIsZero.out === 0; + component randomBits = Num2Bits(253); randomBits.in <== random; @@ -335,6 +341,13 @@ template CheckPCT() { lt.in[1] <== baseOrder; lt.out === 1; + // Verify the randomness is not zero + // With random = 0 both the auth key and the encryption key become the identity point, + // which is public knowledge, so anyone could decrypt the PCT. + component checkRandomIsZero = IsZero(); + checkRandomIsZero.in <== random; + checkRandomIsZero.out === 0; + component checkAuthKey = BabyPbk(); checkAuthKey.in <== random; @@ -377,6 +390,13 @@ template CheckRegistrationHash() { signal input senderPrivateKey; signal input senderAddress; + // Verify the sender address fits in 160 bits + // Registrar.register() reads the account as address(uint160(input[2])). Without this + // bound, senderAddress + k * 2^160 hashes differently while resolving to the same + // account, which defeats the duplicate-registration guard. + component addressBits = Num2Bits(160); + addressBits.in <== senderAddress; + component hash = Poseidon(3); hash.inputs[0] <== chainID; hash.inputs[1] <== senderPrivateKey; diff --git a/contracts/EncryptedERC.sol b/contracts/EncryptedERC.sol index e953807..6344e36 100644 --- a/contracts/EncryptedERC.sol +++ b/contracts/EncryptedERC.sol @@ -15,10 +15,10 @@ import {BabyJubJub} from "./libraries/BabyJubJub.sol"; import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; // types -import {CreateEncryptedERCParams, Point, EGCT, EncryptedBalance, AmountPCT, MintProof, TransferProof, WithdrawProof, BurnProof, TransferInputs} from "./types/Types.sol"; +import {CreateEncryptedERCParams, Point, EGCT, AmountPCT, MintProof, TransferProof, WithdrawProof, BurnProof, TransferInputs} from "./types/Types.sol"; // errors -import {UserNotRegistered, InvalidProof, TransferFailed, UnknownToken, InvalidChainId, InvalidNullifier, ZeroAddress} from "./errors/Errors.sol"; +import {UserNotRegistered, InvalidProof, TransferFailed, UnknownToken, InvalidChainId, InvalidNullifier, ZeroAddress, AmountTooSmall} from "./errors/Errors.sol"; // interfaces import {IRegistrar} from "./interfaces/IRegistrar.sol"; @@ -27,7 +27,6 @@ import {IWithdrawVerifier} from "./interfaces/verifiers/IWithdrawVerifier.sol"; import {ITransferVerifier} from "./interfaces/verifiers/ITransferVerifier.sol"; import {IBurnVerifier} from "./interfaces/verifiers/IBurnVerifier.sol"; import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; -import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; // /$$$$$$$$ /$$$$$$$ /$$$$$$ // | $$_____/| $$__ $$ /$$__ $$ @@ -621,31 +620,32 @@ contract EncryptedERC is address tokenAddress, uint256[7] memory amountPCT ) internal returns (uint256 dust, uint256 tokenId) { - // Get token decimals and handle scaling - uint8 tokenDecimals = IERC20Metadata(tokenAddress).decimals(); + // Register the token if it's new. This captures decimals() once, at registration, so a + // token cannot report one value on deposit and another on withdrawal. + if (tokenIds[tokenAddress] == 0) { + _addToken(tokenAddress); + } + tokenId = tokenIds[tokenAddress]; + + // Get the registered token decimals and handle scaling + uint8 registeredDecimals = tokenDecimals[tokenId]; uint256 value = amount; dust = 0; // Scale down if token has more decimals - if (tokenDecimals > decimals) { - uint256 scalingFactor = 10 ** (tokenDecimals - decimals); + if (registeredDecimals > decimals) { + uint256 scalingFactor = 10 ** (registeredDecimals - decimals); value = amount / scalingFactor; dust = amount % scalingFactor; } // Scale up if token has fewer decimals - else if (tokenDecimals < decimals) { - uint256 scalingFactor = 10 ** (decimals - tokenDecimals); + else if (registeredDecimals < decimals) { + uint256 scalingFactor = 10 ** (decimals - registeredDecimals); value = amount * scalingFactor; dust = 0; } - // Register the token if it's new - if (tokenIds[tokenAddress] == 0) { - _addToken(tokenAddress); - } - tokenId = tokenIds[tokenAddress]; - // Return early if the scaled value is zero if (value == 0) { return (dust, tokenId); @@ -657,29 +657,25 @@ contract EncryptedERC is uint256[2] memory publicKey = registrar.getUserPublicKey(to); // Encrypt the value with the receiver's public key + // + // NOTE: BabyJubJub.encrypt uses a fixed randomness of 1, because a contract has no + // source of randomness. Deposit ciphertexts are therefore deterministic: equal + // amounts to the same key produce identical ciphertexts, and the accumulated + // randomness of a deposit-only account is just its publicly observable operation + // count. Such a balance is derivable by anyone from the deposit and withdrawal + // amounts, which are already public in the ERC20 transfers -- but it does mean a + // converter balance carries no confidentiality until the account receives a + // private transfer with real randomness. EGCT memory eGCT = BabyJubJub.encrypt( Point({x: publicKey[0], y: publicKey[1]}), value ); - // Add to the receiver's balance - EncryptedBalance storage balance = balances[to][tokenId]; - - if (balance.eGCT.c1.x == 0 && balance.eGCT.c1.y == 0) { - balance.eGCT = eGCT; - } else { - balance.eGCT.c1 = BabyJubJub._add(balance.eGCT.c1, eGCT.c1); - balance.eGCT.c2 = BabyJubJub._add(balance.eGCT.c2, eGCT.c2); - } - - // Update transaction history - balance.amountPCTs.push( - AmountPCT({pct: amountPCT, index: balance.transactionIndex}) - ); - balance.transactionIndex++; - - // Commit the new balance - _commitUserBalance(to, tokenId); + // Add to the receiver's balance and record the amount PCT. + // Shared with the transfer and mint paths on purpose: this used to be an inline + // copy of _addToUserBalance, which meant the MAX_PENDING_AMOUNT_PCTS ceiling in + // _addToUserHistory did not apply to deposits. + _addToUserBalance(to, tokenId, eGCT, amountPCT); } return (dust, tokenId); @@ -699,23 +695,30 @@ contract EncryptedERC is uint256 amount, address tokenAddress ) internal { - // Get token decimals and handle scaling - uint256 tokenDecimals = IERC20Metadata(tokenAddress).decimals(); + // Get the registered token decimals and handle scaling + uint256 registeredDecimals = tokenDecimals[tokenIds[tokenAddress]]; uint256 value = amount; uint256 scalingFactor = 0; // Scale up if token has more decimals - if (tokenDecimals > decimals) { - scalingFactor = 10 ** (tokenDecimals - decimals); + if (registeredDecimals > decimals) { + scalingFactor = 10 ** (registeredDecimals - decimals); value = amount * scalingFactor; } // Scale down if token has fewer decimals - else if (tokenDecimals < decimals) { - scalingFactor = 10 ** (decimals - tokenDecimals); + else if (registeredDecimals < decimals) { + scalingFactor = 10 ** (decimals - registeredDecimals); value = amount / scalingFactor; } + // Reject amounts that scale down to nothing. The caller's encrypted balance has + // already been debited by the full amount at this point, so paying out zero would + // destroy the value silently and still emit a Withdraw event for it. + if (value == 0) { + revert AmountTooSmall(); + } + // Transfer the tokens to the receiver IERC20 token = IERC20(tokenAddress); SafeERC20.safeTransfer(token, to, value); diff --git a/contracts/EncryptedUserBalances.sol b/contracts/EncryptedUserBalances.sol index 7f02b19..8221c06 100644 --- a/contracts/EncryptedUserBalances.sol +++ b/contracts/EncryptedUserBalances.sol @@ -6,7 +6,7 @@ pragma solidity 0.8.27; import {EncryptedBalance, EGCT, BalanceHistory, AmountPCT} from "./types/Types.sol"; -import {InvalidProof} from "./errors/Errors.sol"; +import {InvalidProof, PendingHistoryLimitReached} from "./errors/Errors.sol"; import {BabyJubJub} from "./libraries/BabyJubJub.sol"; /** @@ -21,6 +21,13 @@ import {BabyJubJub} from "./libraries/BabyJubJub.sol"; * allowing users to prove they have sufficient funds without revealing the actual amount. */ contract EncryptedUserBalances { + /////////////////////////////////////////////////// + /// Constants /// + /////////////////////////////////////////////////// + + // Add limit to pending history to keep the gas cost of pruning history affordable for each account. + uint256 public constant MAX_PENDING_AMOUNT_PCTS = 300; + /////////////////////////////////////////////////// /// State Variables /// /////////////////////////////////////////////////// @@ -183,6 +190,11 @@ contract EncryptedUserBalances { ) internal { EncryptedBalance storage balance = balances[user][tokenId]; + // bound the pending history so the prune loop stays affordable for the account + if (balance.amountPCTs.length >= MAX_PENDING_AMOUNT_PCTS) { + revert PendingHistoryLimitReached(); + } + uint256 nonce = balance.nonce; uint256 balanceHash = _hashEGCT(balance.eGCT); balanceHash = uint256(keccak256(abi.encode(balanceHash, nonce))); diff --git a/contracts/Registrar.sol b/contracts/Registrar.sol index c4b1cb1..c37f5c5 100644 --- a/contracts/Registrar.sol +++ b/contracts/Registrar.sol @@ -102,7 +102,7 @@ contract Registrar { } // check if the user is already registered - if (isRegistered[registrationHash] && isUserRegistered(account)) { + if (isRegistered[registrationHash] || isUserRegistered(account)) { revert UserAlreadyRegistered(); } diff --git a/contracts/errors/Errors.sol b/contracts/errors/Errors.sol index 02da42a..565019a 100644 --- a/contracts/errors/Errors.sol +++ b/contracts/errors/Errors.sol @@ -19,3 +19,5 @@ error InvalidSender(); error InvalidRegistrationHash(); error ZeroAddress(); error TokenBlacklisted(address token); +error PendingHistoryLimitReached(); +error AmountTooSmall(); diff --git a/contracts/mocks/EncryptedERCHarness.sol b/contracts/mocks/EncryptedERCHarness.sol new file mode 100644 index 0000000..2982060 --- /dev/null +++ b/contracts/mocks/EncryptedERCHarness.sol @@ -0,0 +1,31 @@ +// (c) 2026, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: Ecosystem + +pragma solidity 0.8.27; + +import {EncryptedERC} from "../EncryptedERC.sol"; +import {AmountPCT, CreateEncryptedERCParams, EncryptedBalance} from "../types/Types.sol"; + +/** + * @dev Test-only EncryptedERC variant that can construct a worst-case pending history. + */ +contract EncryptedERCHarness is EncryptedERC { + constructor(CreateEncryptedERCParams memory params) EncryptedERC(params) {} + + function seedPendingHistory( + address user, + uint256 tokenId, + uint256[7] calldata pct, + uint256 count, + uint256 checkpointIndex + ) external { + EncryptedBalance storage balance = balances[user][tokenId]; + for (uint256 i = 0; i < count; i++) { + balance.amountPCTs.push( + AmountPCT({pct: pct, index: checkpointIndex}) + ); + } + } +} diff --git a/contracts/mocks/EncryptedUserBalancesHarness.sol b/contracts/mocks/EncryptedUserBalancesHarness.sol new file mode 100644 index 0000000..27c5002 --- /dev/null +++ b/contracts/mocks/EncryptedUserBalancesHarness.sol @@ -0,0 +1,57 @@ +// (c) 2026, Ava Labs, Inc. All rights reserved. +// See the file LICENSE for licensing terms. + +// SPDX-License-Identifier: Ecosystem + +pragma solidity 0.8.27; + +import {EncryptedUserBalances} from "../EncryptedUserBalances.sol"; +import {AmountPCT, EncryptedBalance} from "../types/Types.sol"; + +/** + * @dev Test-only harness for measuring the cost of pruning pending amount PCT history. + * It seeds fully non-zero entries so the benchmark reflects the expensive storage-clear path. + */ +contract EncryptedUserBalancesHarness is EncryptedUserBalances { + function seedHistory( + address user, + uint256 tokenId, + uint256 count + ) external { + EncryptedBalance storage balance = balances[user][tokenId]; + uint256 startIndex = balance.amountPCTs.length; + + for (uint256 i = 0; i < count; i++) { + uint256[7] memory pct; + for (uint256 j = 0; j < pct.length; j++) { + pct[j] = (startIndex + i) * pct.length + j + 1; + } + balance.amountPCTs.push( + AmountPCT({pct: pct, index: startIndex + i}) + ); + } + + balance.transactionIndex = startIndex + count; + } + + function appendHistory(address user, uint256 tokenId) external { + uint256[7] memory pct; + pct[0] = 1; + _addToUserHistory(user, tokenId, pct); + } + + function pruneHistory( + address user, + uint256 tokenId, + uint256 transactionIndex + ) external { + _deleteUserHistory(user, tokenId, transactionIndex); + } + + function pendingHistoryLength( + address user, + uint256 tokenId + ) external view returns (uint256) { + return balances[user][tokenId].amountPCTs.length; + } +} diff --git a/contracts/tokens/TokenTracker.sol b/contracts/tokens/TokenTracker.sol index 3691750..7bb6745 100644 --- a/contracts/tokens/TokenTracker.sol +++ b/contracts/tokens/TokenTracker.sol @@ -7,6 +7,7 @@ pragma solidity 0.8.27; import {Ownable2Step, Ownable} from "@openzeppelin/contracts/access/Ownable2Step.sol"; import {TokenBlacklisted, InvalidOperation} from "../errors/Errors.sol"; +import {IERC20Metadata} from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol"; /** * @title TokenTracker @@ -45,6 +46,9 @@ contract TokenTracker is Ownable2Step { mapping(address tokenAddress => bool isBlacklisted) public blacklistedTokens; + /// @notice Decimals reported by each registered token, captured at registration + mapping(uint256 tokenId => uint8 decimals) public tokenDecimals; + /////////////////////////////////////////////////// /// Modifiers /// /////////////////////////////////////////////////// @@ -139,6 +143,7 @@ contract TokenTracker is Ownable2Step { uint256 newTokenId = nextTokenId; tokenIds[tokenAddress] = newTokenId; tokenAddresses[newTokenId] = tokenAddress; + tokenDecimals[newTokenId] = IERC20Metadata(tokenAddress).decimals(); tokens.push(tokenAddress); nextTokenId++; } diff --git a/contracts/verifiers/BurnCircuitGroth16Verifier.sol b/contracts/verifiers/BurnCircuitGroth16Verifier.sol index 9729b12..379b9ab 100644 --- a/contracts/verifiers/BurnCircuitGroth16Verifier.sol +++ b/contracts/verifiers/BurnCircuitGroth16Verifier.sol @@ -34,94 +34,94 @@ contract BurnCircuitGroth16Verifier { uint256 public constant GAMMA_Y2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; uint256 public constant DELTA_X1 = - 11559732032986387107991004021392285783925812861821192530917403151452391805634; + 18068269036347605663473046598932117849250599112501411921245619099639563001463; uint256 public constant DELTA_X2 = - 10857046999023057135944570762232829481370756359578518086990519993285655852781; + 2301073142475396993773978505633718782750287996612198183593216235602225785330; uint256 public constant DELTA_Y1 = - 4082367875863433681332203403145435568316851327593401208105741076214120093531; + 3073145107905170746687841711267307719073762517109452847153814168939630075772; uint256 public constant DELTA_Y2 = - 8495653923123431417604973247489272438418190587263600148770280649306958101930; + 10961296788526809772353740184537068352606427639693845063421291358100730194549; uint256 public constant IC0_X = - 6901175356638081608311197414548846861180656487838344346821425826024891512425; + 14874534560863506187492139018634993019793584672384344989283815636520951511298; uint256 public constant IC0_Y = - 16944064565335445729234872967061190126362989003416853826016805426130180238191; + 19433767728097878428205026753935379413283455462187619513628741184855994988529; uint256 public constant IC1_X = - 17908121343774581376092646765067170799970925894057937307165335210962871507135; + 766312427469543414624781412742178740436577019446000599209144238628925292414; uint256 public constant IC1_Y = - 6739483966006459958647545663755815825611388802168101513616676265213547687212; + 11956596380120466965959213032841211036588141256244479446912141909087743946449; uint256 public constant IC2_X = - 766312427469543414624781412742178740436577019446000599209144238628925292414; + 19382367631125777024854089319372587940591402333899244040325149591553843397579; uint256 public constant IC2_Y = - 11956596380120466965959213032841211036588141256244479446912141909087743946449; + 21403189616005894915395729633979911132499330629008284763677855495728980685589; uint256 public constant IC3_X = - 9834218022277006635455703178457965188100848955744692108208207593466809819916; + 16873607939260699782152987377956714326707996147740333372471409440806666007870; uint256 public constant IC3_Y = - 5985476150835890762503639978680541204908901815001963876083809679448099772187; + 4823813718136831027557208358400077597181121551803781304866108582065943338847; uint256 public constant IC4_X = - 14827234556798753501841602996273223453620286706976793196274886644504394417263; + 1929042304597372185937147232117975513235946186018483019137219886969879342564; uint256 public constant IC4_Y = - 17185284608112950506629319460803937653685676730131697135772583956246683209368; + 16041200717617907290182387211838729202813038927716409271158182722220738184272; uint256 public constant IC5_X = - 17529671244301122497049371127369274616617935801308036584230660946886543200270; + 10100132593539651075092860762732050318282008836770498758516080145892203319933; uint256 public constant IC5_Y = - 21375965875653643781871988041044406562099360028820246922430008152355558076267; + 20955597788595471241113414219690472105385243566077669548840483820580533529000; uint256 public constant IC6_X = - 2071394549783234155236090578090590694025714713435714686283263242515370887037; + 8470926007784285402889150113766497592074358400891318532322995138506403384279; uint256 public constant IC6_Y = - 1360924170815016231172148644602657489538698591468910875031083731851187567999; + 8310950274532158280101970082879701558099714295351544024093409514778108626712; uint256 public constant IC7_X = - 10294779462906061052931321788054691400173934802237652306928745571023248394387; + 19978173907576057065444722831289895208882188362747184086352903798679295119201; uint256 public constant IC7_Y = - 6555248292739776048079409559973894167013450042783785080733702895769749566613; + 15183736862969267858591121906253501216802708436126732016994140949207117595013; uint256 public constant IC8_X = - 4433257889246655161353853222728772973385032114589816543634201923482683435584; + 4241991590840894812521558873691922742505044386758211905612996694701369418750; uint256 public constant IC8_Y = - 14737241692493285661348398748630216205024305186831037514190361703045651615269; + 4712959178917328940867212891418986989954694508210057281434702756286365863599; uint256 public constant IC9_X = - 14662929317288257322870633955431196105372083992377701985085624881517883523163; + 17384256984235466163214682780551664577091564886844441439437963151187110314064; uint256 public constant IC9_Y = - 13045157851276202363238319024416490799176208505845980771766086158756862458455; + 20296571661331082956968105383442818985984992535310861363986529155505576301282; uint256 public constant IC10_X = - 10464607531594481747431773960796216724225398526452385781876076453050117351904; + 17027431616611009304378410217174272480143349850791163137585063755548142788022; uint256 public constant IC10_Y = - 17227459943128246860971844058080372581110192073599679941420162883374908732283; + 20118286149998664902129684191444860379452289136986877466159896830141693633470; uint256 public constant IC11_X = - 745839102907798772556197076666683733791895469218705021459706695701505037999; + 20835339050759225768703712848075529739635791514709813530848117559567280414938; uint256 public constant IC11_Y = - 11282995679713265974084133361652481201591627543141168082075682177048149337453; + 7040368151836048017923729126580755497072054472683430007432499359028824547816; uint256 public constant IC12_X = - 17929575843708091862123276864146152761508698565499701379217956191629740643940; + 20062320405151278545619584038566861254083477237663892701639147906154006315477; uint256 public constant IC12_Y = - 19694868618398715637769102075783868212304717698983166562284533403937378692315; + 17523041307652932190125641730118738313390334657045299125403856004388564657068; uint256 public constant IC13_X = - 19788140654052540486857453303544057569825570368720987020309299320004547960581; + 13052049171820219952433931907681657393694797308477474074698115842501295147916; uint256 public constant IC13_Y = - 6883822212531810402176678585679740471039138816982867861815020183660906571642; + 1425640142139256702451940144848264084151874944916879752002334659577479016496; uint256 public constant IC14_X = - 6016243318855719046735289125777883097005663608233773332990082345142498280371; + 4181557413177047880795852900430710069406648434565017206282272466766706932824; uint256 public constant IC14_Y = - 21204516959587943017810864594613242220785397660490599724380523851223540954454; + 1076490384996164187408939956231269371661746698521764954497727070931306852324; uint256 public constant IC15_X = - 9891573095652303648634434897797773521123041746620991186215470158961116717665; + 10477370403873963103009023823231137877228587266934872051738072656898318034377; uint256 public constant IC15_Y = - 15129361566109667756079905439551006265474721391302786501924664404711249139905; + 11502980528392834515632224102695746324276378296202650174921624745967235773112; uint256 public constant IC16_X = - 9439270817025434198507441583978754692817321436471324362734438362897111301924; + 7349403818132382069242774903158300506281160147593600216352343709478834507839; uint256 public constant IC16_Y = - 17736726489009951896104159456871058989709210357063650885766330312145063724146; + 5374170652494686658605512370545122605691962258852673576709426080364171645245; uint256 public constant IC17_X = - 7287813417026604917333767312326818451716773551965506932628922979658721400484; + 8971493727614399525916816483074861570535678898719425110239304688703813492918; uint256 public constant IC17_Y = - 21190069513632277449640126663995547292551888059992765226941465993312580710136; + 11607506224512849900066565004118629841042445789946723208255902316075236531264; uint256 public constant IC18_X = - 18870427155174730509179857527710685647524233977259143240992234215761896727263; + 11633076084066714087007356724903241887267836906856444905783519811005119761103; uint256 public constant IC18_Y = - 21595208618611453816106702920660402890633778123650117008434425697322727495324; + 15434440522489358811942244383448136662781089528873872838765763684395176114351; uint256 public constant IC19_X = - 2474736367332117814843921180480737874685068379574560055026846626150944220277; + 14649394179930981032894187227537055207828915729716249122436764256795900134741; uint256 public constant IC19_Y = - 11798959751686284671429858411798094190882362783079508053655067482307321072055; + 14359000287667049950671539992097470155808991877715693905424132958170028923673; /// @dev memory pointer sizes uint16 public constant P_PUBLIC_SIGNALS_ACCUMULATOR_SIZE = 128; diff --git a/contracts/verifiers/MintCircuitGroth16Verifier.sol b/contracts/verifiers/MintCircuitGroth16Verifier.sol index 2d82ad6..1185292 100644 --- a/contracts/verifiers/MintCircuitGroth16Verifier.sol +++ b/contracts/verifiers/MintCircuitGroth16Verifier.sol @@ -34,114 +34,114 @@ contract MintCircuitGroth16Verifier { uint256 public constant GAMMA_Y2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; uint256 public constant DELTA_X1 = - 11559732032986387107991004021392285783925812861821192530917403151452391805634; + 18310150044426911246155186910490046153313456452399821848345822479171865644945; uint256 public constant DELTA_X2 = - 10857046999023057135944570762232829481370756359578518086990519993285655852781; + 5264749735931748850388186461242850611426001497774606367467905923816395425584; uint256 public constant DELTA_Y1 = - 4082367875863433681332203403145435568316851327593401208105741076214120093531; + 14605690245348196568105292901835213150229505840089104796535493429006577126729; uint256 public constant DELTA_Y2 = - 8495653923123431417604973247489272438418190587263600148770280649306958101930; + 6630427478337662007171878244275165608118871321429624618994700701405970952688; uint256 public constant IC0_X = - 10121904041541460154551260390411876526139574666949788432677764574044027742051; + 20861492296691856165309547776629146952527944203201524873006782894760706976421; uint256 public constant IC0_Y = - 6395114105467352463516423639828272877440036954754220055848039516989817256674; + 3358824539307473736604976612722723713450165337804134402240835675528178962335; uint256 public constant IC1_X = - 5586762719201810155133862083740714325655748243483738877755810028542797644739; + 5511753296331491509569296110445894989507167702892869680373063711781065132586; uint256 public constant IC1_Y = - 9387879719287370926595730382657598610335084850078203728936667449453246554359; + 13287934466428012933987353229261913144286871473679533187235673876285899045743; uint256 public constant IC2_X = - 19420434315212518030589186167981244595406343548992012458488730749825996100239; + 19440605787728638102373686494108905895654642611628169437813543523912920918974; uint256 public constant IC2_Y = - 3482657374383353276279298693752239555763142972311841530862645391131143881873; + 14274851756231214444056769636488865604307347698663402267645432934893285974382; uint256 public constant IC3_X = - 21667521945257749121492909465236139091096077691835364325355606431375269082282; + 15096206644290302729673494593775111017994893610444238941512555843761977798983; uint256 public constant IC3_Y = - 12156175257782822331801928906256367913221851960540994586932487722549923413345; + 10592933405320090517798391416276382767273192109395080940602914940118569597175; uint256 public constant IC4_X = - 16828357126590671631798447095302651492589140460428270542352941484237941156483; + 11189740705109916645368104876865492850094752501799788866350480656624008137866; uint256 public constant IC4_Y = - 3785759973408012513975276660945174958105045591429994983968533282503371539336; + 6373283667837734104667322526110821843542106635322725504401355277194447781077; uint256 public constant IC5_X = - 21244321325522105477060254124915502034148248502931960755663601081500950076300; + 12519464150710176464255689182191223185996416021638864414936748671904429695824; uint256 public constant IC5_Y = - 14687177467139662957844534389099557537735007475047254307829149459337997284150; + 2150352325795278553853916266025032932948033124823106315746500341814425169422; uint256 public constant IC6_X = - 21404447565616225355770439075122853382066792760583316781611395109968504614761; + 15670400985668054227710197257556796204699390148155253521504180141434411169010; uint256 public constant IC6_Y = - 3777910210505077428584254669424713454396973987622630869249106067166590299357; + 8015372489282794800866289250911385611602689183902606383808208685650011045563; uint256 public constant IC7_X = - 5644690004940482546460856256670502914882531219591199090065888636589494736039; + 12391374210603786527505301556990321980257270091806041113978279818540065899945; uint256 public constant IC7_Y = - 16345970805899097192278870928687506101715169625232631539981164972434652655022; + 8515915070842771734194345922664587925823550006589425467896744043022744763705; uint256 public constant IC8_X = - 16593367704572145491497340027058421406291597779030039134573703992464863830646; + 13807538579064566476415694067988365108026713189554400912099239363422127740084; uint256 public constant IC8_Y = - 19275772679724763916884927502599327291258343548738975909520313332884772129528; + 20995630364107562144456318907019459226461425603435703531146140720469843551846; uint256 public constant IC9_X = - 18338635157990571739660769292280252719367811451620901782236478705200001456515; + 16081085598581166173056602246854317663562052634922574354324946451000607120736; uint256 public constant IC9_Y = - 12580365946981294431067603413481570211192375767222833113101936660967490853342; + 4806824913347623486886828480516106843275460973906843187481538273603254862860; uint256 public constant IC10_X = - 19880773599746588943745194809450382516728304373879942615347513263173728275196; + 11631320333320389002311111478825925862454422531020071627586226192130355210011; uint256 public constant IC10_Y = - 128548754750873577554444615682746852358621588347676854260473817368140033519; + 2122514671452018862991564551128667346496598894933582018300009947844480163204; uint256 public constant IC11_X = - 6476719107464483530164368276818653110527411272303410163053488615734788766586; + 15815064186883060030591419160901286559864343154013673260150235611788231912868; uint256 public constant IC11_Y = - 13331539055996208679678758084320772815107338352425913859433335410845899223811; + 20370993525566739028237212283048185476369537192297038935645044346593403445660; uint256 public constant IC12_X = - 17393436839515851750885277096607160266036302533767007170590322671069079326483; + 6595190593163887992768043198968800372382627330961015186275030802761168515160; uint256 public constant IC12_Y = - 17336491525577930609097646312281682071744277090982994234361498925040239739760; + 2507789053059248650011919918385719955910150531313679742117670915630070953153; uint256 public constant IC13_X = - 14059139663320156276001577403575266145309546640724899667521029234074221180403; + 4769024494559532962607971843474329930995364751968913219837397535853989902361; uint256 public constant IC13_Y = - 5963232262834884334488206091864494084893490405377454589196552297795638041488; + 19797571185823382274710714732907626050151097014530262793833343110696004901030; uint256 public constant IC14_X = - 13813470258321934033051704279698252148783024920181797002453328082368105474789; + 3741095076389852568348466376789570229681540891762671038336587701809594295528; uint256 public constant IC14_Y = - 19760333797981660449134124218356560284106192590380149679255903109561686546313; + 21880696756868695397495499774269592625633170331780293853746719644130396141624; uint256 public constant IC15_X = - 11858117840318587547791069185551586430435948995333725070770764697634898894992; + 19517234766997622544803863027312351274688065611950961197914008880953737422764; uint256 public constant IC15_Y = - 16621799951101200543458233987158204772158254202860685491749532125765298740749; + 12766977633088554535159910591318146119749041565098004885165775551772871421614; uint256 public constant IC16_X = - 13584356250500421508084566767718022822120888453124821650989966819848963029582; + 10127707076448967603220797369646569980071434903529645864304691091289486555787; uint256 public constant IC16_Y = - 21121442557480691564262522113115528175177021588076736568194595390503813944019; + 8950621622365938933033410282918462563356088154788396334376499614106955989143; uint256 public constant IC17_X = - 4326226245481542040767942040881999777137473163343274779447151141265545792486; + 320788284794753344254157752272658952160576068967386302073453451172649214954; uint256 public constant IC17_Y = - 21183580388477113613358837765893868421637670220571970210021457037640835173809; + 12072329550178607667412696356075787995621403634036884084426834721001660976904; uint256 public constant IC18_X = - 2704745980008452624320271214496436840853635777289985169457654318338905712053; + 9716709810086398193300932341527162316204048472244916702006365450976523531860; uint256 public constant IC18_Y = - 5498942242451865915343845370075402718280213375705928811712272696867696623122; + 18512681717254787569432573766259952720830104316573624498577507861680140169670; uint256 public constant IC19_X = - 18021323881247358977456866382503667963535769536490271165761105041938333860259; + 15583210451318479388973607383966221956407458266371632140871864321825927352219; uint256 public constant IC19_Y = - 15056011404667104875167366478630077579580289596849055349190254216447781136049; + 7052911310999904477056051359102541062683487166996917722730719394904318138991; uint256 public constant IC20_X = - 2428670635260390602473903592482933886252233168437493591205178349351514000281; + 14254488977079195307288668274622096883962637439954171948445632822972231171922; uint256 public constant IC20_Y = - 862350060646299115005420081148519933461348146447694025974629367115211964519; + 16635798420556842961701542474296813958571732882037007055705935524616967766953; uint256 public constant IC21_X = - 20557922324599650576215164022162024912213509843003042307546636524489843547931; + 15442808645804769798081357271547630043038154266326625746271433261881929480822; uint256 public constant IC21_Y = - 1061522392679391742130691544383963509531829000498209937975610885874122363387; + 15692133379817904664248323757151648294530592660167042783943929714054883152410; uint256 public constant IC22_X = - 9114256858842496488535186312068922854228150055952688114444862375910254881995; + 3959038117463195264225173297414802417787229629774522795646934460427059533984; uint256 public constant IC22_Y = - 20868937436899006110617091404782344741103549613810098330797141428653796030423; + 18559902898279327965625446054916413498906915191943220953721617187208287362108; uint256 public constant IC23_X = - 392332888128429361037702708407695212788446855280618226506466973682041689462; + 13117164475757255667489585615497830505771053345067993075233739336894728532922; uint256 public constant IC23_Y = - 10986782868722900357976121669302445297980271976862420955075995610762868745084; + 7549162224805556704746428222814274942147810722690549422145605522701753608061; uint256 public constant IC24_X = - 12335561474727855982123382035622477594232361573497391299243618736725476900631; + 14334222819352589667606721913122724056272442669634927211261504255948038740273; uint256 public constant IC24_Y = - 20340286770637453607265533856091115758478742882346824576410498508028320071146; + 2481751947144260802788900797067145915535069398032899055229950556775735697875; /// @dev memory pointer sizes uint16 public constant P_PUBLIC_SIGNALS_ACCUMULATOR_SIZE = 128; diff --git a/contracts/verifiers/RegistrationCircuitGroth16Verifier.sol b/contracts/verifiers/RegistrationCircuitGroth16Verifier.sol index 4c73ac2..c7dc437 100644 --- a/contracts/verifiers/RegistrationCircuitGroth16Verifier.sol +++ b/contracts/verifiers/RegistrationCircuitGroth16Verifier.sol @@ -34,38 +34,38 @@ contract RegistrationCircuitGroth16Verifier { uint256 public constant GAMMA_Y2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; uint256 public constant DELTA_X1 = - 11559732032986387107991004021392285783925812861821192530917403151452391805634; + 17876654898335325630068479520728289743106751388573052234350723906294440839692; uint256 public constant DELTA_X2 = - 10857046999023057135944570762232829481370756359578518086990519993285655852781; + 19282391219741381721894031299608776000039341958173844018547499085433811244729; uint256 public constant DELTA_Y1 = - 4082367875863433681332203403145435568316851327593401208105741076214120093531; + 15871735808708861193067982989955676797325237075069869946722392318532642264642; uint256 public constant DELTA_Y2 = - 8495653923123431417604973247489272438418190587263600148770280649306958101930; + 19708622698696259895236324656242665245096896533632764685573452118252374979496; uint256 public constant IC0_X = - 4004410872179300339480249405398939298715031489893009961199535208964457923750; + 692105244798714282968778033574767764788237535539454617180733345581560966526; uint256 public constant IC0_Y = - 11142026210898871476346451274761099606196839371161747578101583645702654533240; + 14949244044653984138443076667526001433989242452238052053640315799204091900706; uint256 public constant IC1_X = - 14970325264892984291437720194401230916657388050759523602370378142660744831477; + 21624277186876277282610441935385969538861234782040498867008018611983063222295; uint256 public constant IC1_Y = - 15860538555168123807647719982845297214031403618163443664157964964439662885432; + 9560437690960488495368890950231067296265617249061671980466162364249184005034; uint256 public constant IC2_X = - 2280562765509182195246897364500489648120102222444059313572774422753200337271; + 20975413741014623923220607600192046765007607319092408363742354325276831378512; uint256 public constant IC2_Y = - 7147694953124310609924568435428058789638619830198023240430532891482445253803; + 17098496999943410739691157771500542090730527298216613791131394980089852049506; uint256 public constant IC3_X = - 7737404298715916349870992960929602974683638711993694006376159661700137192127; + 11115533847113251325546915709756661686214330311154568812439324739880035102953; uint256 public constant IC3_Y = - 7116770325362339113448473214465082117296435085200119804036017348236401720128; + 17534035871294802715323825733736090079789520156028784272032671096408474909815; uint256 public constant IC4_X = - 3130277824222995531291107528843021785954629147236040284065307643519664903928; + 11574661945916509572718310335470045504590589360285124181916070574857759592473; uint256 public constant IC4_Y = - 11742475342174768235971584303810158858484260897318069476115756668898865449280; + 16617592405786925561930723699988576764724991912935168189284557159888787690750; uint256 public constant IC5_X = - 14791539702458079086636207858304521437578092734215012107895193807307152746110; + 18014926008436876908878223643157973700321174654128239431311107643294114881073; uint256 public constant IC5_Y = - 12489284483607948781669905789845942689563255773386215312172350852214666005897; + 15299062161003064518451841683402629795680575009368842994113276129387303699181; /// @dev memory pointer sizes uint16 public constant P_PUBLIC_SIGNALS_ACCUMULATOR_SIZE = 128; diff --git a/contracts/verifiers/TransferCircuitGroth16Verifier.sol b/contracts/verifiers/TransferCircuitGroth16Verifier.sol index 148128e..24c7ba6 100644 --- a/contracts/verifiers/TransferCircuitGroth16Verifier.sol +++ b/contracts/verifiers/TransferCircuitGroth16Verifier.sol @@ -34,146 +34,146 @@ contract TransferCircuitGroth16Verifier { uint256 public constant GAMMA_Y2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; uint256 public constant DELTA_X1 = - 11559732032986387107991004021392285783925812861821192530917403151452391805634; + 7373421924848631289729447888934244711954095305224812054165477109239634485930; uint256 public constant DELTA_X2 = - 10857046999023057135944570762232829481370756359578518086990519993285655852781; + 17573321420925543398098938841372725442795740456981756646006455900667019185665; uint256 public constant DELTA_Y1 = - 4082367875863433681332203403145435568316851327593401208105741076214120093531; + 6692063395579459319241310567160387612371059945372121369244265991917716889279; uint256 public constant DELTA_Y2 = - 8495653923123431417604973247489272438418190587263600148770280649306958101930; + 14769154824729601962487485960591065507136111829346285041829452037354398605022; uint256 public constant IC0_X = - 11078456175176508947665060839367063181390473473270508006260718733884763446509; + 12860613047485174337572800144367534566676749966427263510786233641288361323072; uint256 public constant IC0_Y = - 6041753414651001127438360352721137264917051499794520184043293475204165190685; + 3117092304906614020388401274042152195443668310800814064571900198159814372456; uint256 public constant IC1_X = - 15162904757480315297547642942646568889101029164132171480256830884259150251283; + 3987203900176313648721373326838294062064875524041579268053604363771992813663; uint256 public constant IC1_Y = - 5543236365374398176471504758808152977042933422387633848583378303299793270756; + 2540870705672409242382324915793065925212335203467790590740070818381371996118; uint256 public constant IC2_X = - 17328060769291355736429270023867089282242463190765930364066672240606322731528; + 2160351009242570345101990598387012245257165805803521679126798467310545830036; uint256 public constant IC2_Y = - 16889028711432227360380575065980535632722375252171627947743748499665179759152; + 2050456376645372578396035075358789073979003008436938146845128992698746141877; uint256 public constant IC3_X = - 8534951274187844857754798765054711469756707542878193818609654720983424682295; + 9819249055709022471783469269872195968940696597382036472257350992099603166183; uint256 public constant IC3_Y = - 8945913628923857906349475216922865350407303486167834270986003060482590360541; + 2401786491025438669071658710401341692741617050151593778325339189669301220899; uint256 public constant IC4_X = - 15451872962493168690150192361017318203301132735619727602712141758148948638807; + 7422007307044478259226064473692631752662233050292352222869411054288745570789; uint256 public constant IC4_Y = - 3257041611034212540028719703800773323519734826811773698850078555263697393038; + 10017850150189997840383565765235365224515214690165127564532641750692280241903; uint256 public constant IC5_X = - 16501527896500369578902237454836690085885521711966021988157538332449691146412; + 19221738488703246937975790853705478702845308522128613703152831351556301989763; uint256 public constant IC5_Y = - 16277901177749764148365216633606366116251292755281475194298759272707407824018; + 10183107801189396942167758711051912294619018039092495644809682417460643023810; uint256 public constant IC6_X = - 10378146563933233933703734244718759999027501367391365750021798315897563444591; + 9076649205859590603560715606056701346727113477211950055621087628388769368386; uint256 public constant IC6_Y = - 6842563751857803307953802478770242999171402515835370020586447923920873099219; + 52455929519905290524842189199006340052096446699011578823444788358568039702; uint256 public constant IC7_X = - 20352721715392263662971537971767346903027859101481416488967643016592847282380; + 18103653070682127942942702359086473888645990538117645003998683697246715437040; uint256 public constant IC7_Y = - 14260881413352838566197164407396428620727197892843554333450508049100242677628; + 20937350421085763292785746194370377209032774713987029070743280053317168289872; uint256 public constant IC8_X = - 21057739816355151565092401964767622282102551265481668904500681957228063344238; + 9758634944624942528872916404218984802068150789828935243358049923155742940304; uint256 public constant IC8_Y = - 16180780523793713645254963281457716926007937226125045923262954827309238281194; + 5615975277864739173632599296778201253863610964605697390030280177993730165032; uint256 public constant IC9_X = - 14537516127080012005197736574343683034537191970611258246890082854105324760933; + 10670001473472856457996828759289176589182316531259991403627649917035565048429; uint256 public constant IC9_Y = - 18442918359750026099515052740471376065513561505084248781730547784475549682043; + 16737644016567474899525575815101539395782539042839027261623709392334896614435; uint256 public constant IC10_X = - 9945678304537190581884908568330352663212605281307078311554845796978128487311; + 5697191124914901219408901513601442561324208164645566497511242718204397743535; uint256 public constant IC10_Y = - 9922952547073080040816726971142108048165624682232524310828932207260681346925; + 13398161619207397794324308592162009615115451562662451839052676578420491271203; uint256 public constant IC11_X = - 121018551111798889520476374750956766867835537125258291153678626712032749835; + 703123888741314718612309048386350636226232723398947337322732826265873810481; uint256 public constant IC11_Y = - 29265305386115914605361057732389333018602730942100360415826037370925178043; + 17990589954423602614263242460599822606354926012790592127594635530017447736000; uint256 public constant IC12_X = - 19393638291779014670875425462009705376277440547297152509532737472607672105229; + 20393624977578917018885892283158705958560546595002668452425361396957472131164; uint256 public constant IC12_Y = - 12637387498267415299358604851073087307458804722402979421904536853588103603115; + 19590758776110701291071416345258278715869484586955132519963026375488500561474; uint256 public constant IC13_X = - 19535226022618801566939497106610112373065946755466822996888611481583748235579; + 12436544099918355712785605826913391779448933207323030677346777208134860342988; uint256 public constant IC13_Y = - 18338463551063409694995636016403970595398232669703454914987172540276159653613; + 12934270829268999096893372612764637040591991408236553218822437244622467331607; uint256 public constant IC14_X = - 8008700345935321927788580584227425845966574602899033915258149217767990418718; + 17956572623335638994475857660706169025078837539836899885807999861812007891829; uint256 public constant IC14_Y = - 185856258559502906253092650522696470738095546583256434424552656167093996151; + 15788541231435136223906443344147580532437154635912716511551645127845433777427; uint256 public constant IC15_X = - 7820954574137895573811525844670273368496497357173205474113176992404687726697; + 17372427373514078940943510142559667491564581290960965924927622740257982261705; uint256 public constant IC15_Y = - 956512349033607095044956195378412396626953742914598187567649677456879320228; + 15857915612980925933684826813016864811106014452704060191542323376399865010576; uint256 public constant IC16_X = - 15573333703789237575530866563016649620625650785245004564133502761898657171416; + 17706658396584983918235581578937131335399954610126317122698339854402062323466; uint256 public constant IC16_Y = - 4318045992191734813427473662920467578914718989290966190779465757655054024866; + 19825721779656394025821381305312046990958274866881259324875151902399022916528; uint256 public constant IC17_X = - 14251137277887630388639941167105402370548590355743069148064181443318051385186; + 20620988361254936794552318469605522229142851776281478715836384141520080141570; uint256 public constant IC17_Y = - 3156000259325297871563018277964544792850822239901608666349236165443650945279; + 8859059503123755609281367511103088644004110641968218967910338769873511051761; uint256 public constant IC18_X = - 5872390235919681263129087861488743087046671364741206348090856282223602944462; + 12631122413809660711555817700981016176438142813482101243197149713058144542227; uint256 public constant IC18_Y = - 16668195091836658784208651432085131085595308441293778882239710806888813163568; + 2556186502760854102348974448979574846991952002272770169461095031136952271616; uint256 public constant IC19_X = - 18514753246385905128088201279079181382420042068951125186140903026107781270079; + 17458248129570466726463169081527160609041285936662432661537029195640964876334; uint256 public constant IC19_Y = - 12671409848969278422503585680858897360251449228569325218012677111477592298915; + 13311660137139351881541212173790929136853538186322689971135798269503166365287; uint256 public constant IC20_X = - 14795534685259818800016539466295714973315210330368104927561037919830323460988; + 20376216183950978302528448687935566484992782628561612737636988612841263279656; uint256 public constant IC20_Y = - 2713630188989527621944627278467445252191128824455445277832095608562212679464; + 20169118954698379344261930520187924042126994913369409717143332017835499608184; uint256 public constant IC21_X = - 14146928308724125026725614632454585439232772772913032956834281111360859175326; + 13590288787452426901921148286585278258898382446775320387044914269174787786911; uint256 public constant IC21_Y = - 11696713101615308965286605927940420687716057765241336395590899692577157174575; + 8747169299236194328036487885749156195653967424912382461452920152586239170329; uint256 public constant IC22_X = - 2235128209339941496221360806283506282754206127175685907922436886644178469613; + 7674325401976365261930217729547312366599000999965896222120534931642700524203; uint256 public constant IC22_Y = - 6082007467329063519640234159158138154643669546952627326867255812484441045661; + 19068217506565083003578053277160250956988289919655860507582338843332571021978; uint256 public constant IC23_X = - 4778277300486848528134752164009065478749360605826055092389954662792598494091; + 19352748579310488859684030546811483397732185861890924210248349868791909751480; uint256 public constant IC23_Y = - 3024652709566317167468475499107319235166534387809203994443662489737171429439; + 12154048074587184269542372566563175850267148361618941040848511983070399994545; uint256 public constant IC24_X = - 20553119678962413077240456112807143224561227202753679727141414460261204287602; + 5781302722013869065299528236353742940267161069046098906267033438704274873397; uint256 public constant IC24_Y = - 353033850139697523308575010181001615711175280648155651143918443424069251681; + 17692093638206231489380310174596348635669977742969481065378179222721950073816; uint256 public constant IC25_X = - 12320369853960213401201536713826981257726604458607453897067807791457490307319; + 1822112472095935411318382311555409139784633448197418086992049484249877317223; uint256 public constant IC25_Y = - 12895878247228443034004154694080502857256319561028939353010666652708930585511; + 21492042244465545003762241091589873862989079378893002689743486138813696694800; uint256 public constant IC26_X = - 772255132879173785462217420966153746864602649093557997703481412106975381771; + 5603351942102452705019860367516099398860849474250143800383911460118571587263; uint256 public constant IC26_Y = - 7590818764269556518156184415909156972825437157984074557355089651665498212893; + 3094600863124428771041895118538692524518496368868992103906097304480737853640; uint256 public constant IC27_X = - 15656520006351949412863400564011439085326031727827048952749172502151384928426; + 7441415126376982767803363803637519563709295595343439983482489919240779377645; uint256 public constant IC27_Y = - 9520418046246602777065803395409630022848696572538622647916460498453086071681; + 3076359757048038301182852617243931521181585988154293760812390384006896356182; uint256 public constant IC28_X = - 203389407731559972686963839373673159907560284831081500283956869457261227598; + 14900441524872817256320500300380092737890857259674155501716427566825132598416; uint256 public constant IC28_Y = - 7452820531660814855014532611843194786449585917006722468041952200572306428747; + 12494120348218091892039246129978021993414195558596456765490457556412967109951; uint256 public constant IC29_X = - 1294403555916294449795173178919244618506718557207433405402610910324041999043; + 5750365781992332384417028751570408231938568123690438954844611265235763415721; uint256 public constant IC29_Y = - 3417552333935828954715155980714171844696841479989449134034592386673267645237; + 12272625903360264588429425090935995728552800950462484265649059624128745160550; uint256 public constant IC30_X = - 4057510152773123091521740504550701903278483323514428067579004823698831606746; + 1862621976991045800447155762811695415777350522333110092968742495664769562796; uint256 public constant IC30_Y = - 255222888879429197662829341108999392987181390679120827600125684828907967217; + 18559201839005851072407866227831468715642200861728631518878477425805757269298; uint256 public constant IC31_X = - 16993165161373202096858097803614125959054307247005919250330093739286073007809; + 1385302304779399923164390639587851358941432391526277932382765163789040623703; uint256 public constant IC31_Y = - 1630518864111342581154347255970093862315458024055440432677999240937750277089; + 11968611566051487792573876012784928369981716184185714307126319967096287002644; uint256 public constant IC32_X = - 1342624472930637816128297475680967043884959574033915950794605458813343173455; + 16587830688199775995326445992945741349754658301661942765538031557545371551275; uint256 public constant IC32_Y = - 10644443477057701293111051850964191288457516065268084028669805887784546476470; + 19754146478491369725133569461490869112850762561747377519184934519660398688407; /// @dev memory pointer sizes uint16 public constant P_PUBLIC_SIGNALS_ACCUMULATOR_SIZE = 128; diff --git a/contracts/verifiers/WithdrawCircuitGroth16Verifier.sol b/contracts/verifiers/WithdrawCircuitGroth16Verifier.sol index f500169..48d31b1 100644 --- a/contracts/verifiers/WithdrawCircuitGroth16Verifier.sol +++ b/contracts/verifiers/WithdrawCircuitGroth16Verifier.sol @@ -34,82 +34,82 @@ contract WithdrawCircuitGroth16Verifier { uint256 public constant GAMMA_Y2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; uint256 public constant DELTA_X1 = - 11559732032986387107991004021392285783925812861821192530917403151452391805634; + 18413979168680880508427857573499344678105139700199040952837451066239717429821; uint256 public constant DELTA_X2 = - 10857046999023057135944570762232829481370756359578518086990519993285655852781; + 9898626626077518568379228412902424898657681523885533885565411617328460389922; uint256 public constant DELTA_Y1 = - 4082367875863433681332203403145435568316851327593401208105741076214120093531; + 6007184160786324903714517413881807875499448146223314045078954717411897818016; uint256 public constant DELTA_Y2 = - 8495653923123431417604973247489272438418190587263600148770280649306958101930; + 17841574180482311547923292068248229483419102900173905611468380600372583372822; uint256 public constant IC0_X = - 11668030768982174988315578800515098268095958336328620786726427170889418741301; + 1989347808741798604476145984547616952751352055055300243388942465316163536890; uint256 public constant IC0_Y = - 12830128751532076647154044575439533260884816271528132751378948213598797056659; + 18287141091950813472142285432947217857255288156969105476385431648941747790000; uint256 public constant IC1_X = - 122553302691155487971695272446778073436405101025840723275402329359390195354; + 21588062611189889344864608007646956350568930448852990739689758952508651394965; uint256 public constant IC1_Y = - 20406127155715319057309683179282528477509489482001054804640976841555607842541; + 98867617019240069306705043616311394330926299234980402726491820133169484093; uint256 public constant IC2_X = - 10893636774628876142899763192646905724708189468282917758613650147010478133301; + 15550575461234686720063491014368064382464483659875934656158426803714221382565; uint256 public constant IC2_Y = - 148896310776292842756025446759984436974180847194558332931999839598427070960; + 19120379509284667271969003793820599158352811626916363073794854942946766897866; uint256 public constant IC3_X = - 15550575461234686720063491014368064382464483659875934656158426803714221382565; + 20223630843990402409968710763948629834919161710796588491358359466297300700679; uint256 public constant IC3_Y = - 19120379509284667271969003793820599158352811626916363073794854942946766897866; + 2675223734590396478598414102060532012408669002722152868471093004240099725728; uint256 public constant IC4_X = - 11997276881897936472837561222757310995977345728486444480476752931527806516438; + 9784390272502725404771544918680482012603159796207186791664900226814915108846; uint256 public constant IC4_Y = - 737024421379298120335516868702549484509013191532965487105618647991650298484; + 4889052086745915475149417214030367513059993224424723225882729911060823610425; uint256 public constant IC5_X = - 19677974929815656195387967292048914984373675040193074047636585472049442720491; + 2802268021394373347198041589581099782960862283447005903992849422477600826465; uint256 public constant IC5_Y = - 10141508255865662035934756555228488100770997341006900106739896716315583398755; + 10141289372445744520279703235726021593976465063055028344566354047067642069932; uint256 public constant IC6_X = - 17729740485077231525915005240789252003871266035358118446803131706576150070834; + 17981075212502931682373066520328626140643179374293563468968969591565544442937; uint256 public constant IC6_Y = - 21463211066327337387171909090874947331633898607474204358116806224285045707724; + 12322953543578476859639640121428089812676529591711769361698560759547148735859; uint256 public constant IC7_X = - 2541364605460121444367617049274470896879571465893010763118465395946894872402; + 17529192146275002547478358208807882132911034198502579757089079197086721890541; uint256 public constant IC7_Y = - 15666472859923637808751528199087900998876037477297252503877624663975157070339; + 4388812328349628025776515576481472717076265011573169880617467587465858259016; uint256 public constant IC8_X = - 19412597310563204613184634003034326013515621831694714651927930505680641506032; + 13462596197467101747423899664117767499325135553613560455509720229714799487830; uint256 public constant IC8_Y = - 7090834739055515275081335901169439667521190970728112165903260270557944931447; + 12083203262673030953642459095709136489775976186296926881097299438023841911749; uint256 public constant IC9_X = - 687622791121058684572490068566579804627881043520672621913250421784418936468; + 17019906054902305959332406672890853967066335368735806389106047492332171614235; uint256 public constant IC9_Y = - 12438570622645808676528087047069161296724662341925122787880168407993098364378; + 11321377648794280332725602412481768552079979051137249946557057349865848834435; uint256 public constant IC10_X = - 2256336126216590424153819634776022210916631465813758319833132994414000265810; + 12004837936896928828186069165842330195823900241045766933887963792976213731479; uint256 public constant IC10_Y = - 14871133877320414522348861289280860819407005829851620950752250168049105134244; + 2795017854439755881864709191776142922107159587230115159310641655955551793825; uint256 public constant IC11_X = - 5268036746963758940162316014618837296844723451466645707274717691934126976172; + 21721751483859419544076386106520492385804231583471287102329184574269367382127; uint256 public constant IC11_Y = - 14043587525208299419769690167114748602978120733028534419518881521020011459176; + 1494799036427623303630306049192407908077332540741044828452816678230690958760; uint256 public constant IC12_X = - 2154876666208174266715465795960362078373910330071013833946880236172287268609; + 2761434005088267474318136430578008369202159868741997526572692295542766967068; uint256 public constant IC12_Y = - 21039580639663636314965780229016132769762902314737515280504608091159095741241; + 4036048972999556212132214896337493500664620928442864032564561739128205321674; uint256 public constant IC13_X = - 16336909857979898535516215802114635770223252233010396112078559223843933803808; + 3489522740644890307435542545453392570336902680579166380511301988065761857470; uint256 public constant IC13_Y = - 7004567302322641279975389394870214367266003425057422009964578684235048564110; + 20937161376515314963749249507373036130492475294409777928513175104326755904935; uint256 public constant IC14_X = - 7510101589966203229059356316761275261569766791979628349139748348788399588502; + 15246253735871791668224050351529893541576242280197703313685085786454308195198; uint256 public constant IC14_Y = - 6787100935552764653462602515138571334407597634374519037897835434137613528973; + 14542825447756802434365841254734849043796005892758280359295110591666008608130; uint256 public constant IC15_X = - 15839334625619375482935791705322004043072260453789756012451905370323543014491; + 1875928679557964182259760561824797539257356137127515597882745846130733296261; uint256 public constant IC15_Y = - 21752850639855585991626846970887014669858240281956242791436741246893327062812; + 15445101728156033566794154649854201878640042973936971994075877498715300589664; uint256 public constant IC16_X = - 8486962044828549404108781901934570149077571365702200623962117478945962708012; + 7704361725176004808064710428275595097272350957161158742117148391001036974188; uint256 public constant IC16_Y = - 5177923901509395134163622097195381342319188207383408808200785221500245384712; + 2616681396458669498399019027534121017878488418160952267486192744404696102688; /// @dev memory pointer sizes uint16 public constant P_PUBLIC_SIGNALS_ACCUMULATOR_SIZE = 128; diff --git a/hardhat.config.ts b/hardhat.config.ts index b865883..61f1892 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -54,7 +54,7 @@ const config: HardhatUserConfig = { setupSettings: { contributionSettings: { provingSystem: "groth16", - contributions: 0, + contributions: 1, }, onlyFiles: [], skipFiles: [], diff --git a/package-lock.json b/package-lock.json index d6b0b8f..4517cf6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,8 @@ "prettier": "^3.5.3", "prettier-plugin-solidity": "^1.4.2", "solhint": "^5.0.5", - "solidity-coverage": "^0.8.14" + "solidity-coverage": "^0.8.14", + "ts-node": "^10.9.2" } }, "node_modules/@adraffy/ens-normalize": { @@ -241,8 +242,7 @@ "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "0.3.9" }, @@ -949,27 +949,24 @@ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.0.3", "@jridgewell/sourcemap-codec": "^1.4.10" @@ -1874,36 +1871,32 @@ } }, "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.13.tgz", + "integrity": "sha512-gcLdvR9HO1ZJBypsOGqaP6TFEzb6vIta0KSTLt9NAQ6pXQO3cRgSVyCN6pzYqI9DlJgY71XKO0dpDhCf08b3pg==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/@typechain/ethers-v6": { "version": "0.5.1", @@ -2233,12 +2226,11 @@ } }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -2247,12 +2239,11 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { "acorn": "^8.11.0" }, @@ -2412,8 +2403,7 @@ "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", @@ -3425,8 +3415,7 @@ "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -5952,8 +5941,7 @@ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, - "optional": true, - "peer": true + "license": "ISC" }, "node_modules/markdown-table": { "version": "2.0.0", @@ -8433,8 +8421,7 @@ "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -8474,12 +8461,11 @@ } }, "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", "dev": true, - "optional": true, - "peer": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } @@ -8791,8 +8777,7 @@ "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, - "optional": true, - "peer": true + "license": "MIT" }, "node_modules/viem": { "version": "2.29.3", @@ -9223,8 +9208,7 @@ "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, - "optional": true, - "peer": true, + "license": "MIT", "engines": { "node": ">=6" } diff --git a/package.json b/package.json index f4bcde9..0b98094 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "prettier": "^3.5.3", "prettier-plugin-solidity": "^1.4.2", "solhint": "^5.0.5", - "solidity-coverage": "^0.8.14" + "solidity-coverage": "^0.8.14", + "ts-node": "^10.9.2" }, "scripts": { "test": "mocha 'src/**/*.test.js'", diff --git a/scripts/deploy-converter.ts b/scripts/deploy-converter.ts index ffc4221..267e625 100644 --- a/scripts/deploy-converter.ts +++ b/scripts/deploy-converter.ts @@ -8,14 +8,13 @@ const main = async () => { const [deployer] = await ethers.getSigners(); // deploy verifiers - // if true, deploys verifiers for prod, generated with proper trusted setup const { registrationVerifier, mintVerifier, withdrawVerifier, transferVerifier, burnVerifier, - } = await deployVerifiers(deployer); + } = await deployVerifiers(deployer, true); // deploy babyjub library const babyJubJub = await deployLibrary(deployer); diff --git a/scripts/deploy-standalone.ts b/scripts/deploy-standalone.ts index b28f6ca..d8ecd48 100644 --- a/scripts/deploy-standalone.ts +++ b/scripts/deploy-standalone.ts @@ -8,14 +8,13 @@ const main = async () => { const [deployer] = await ethers.getSigners(); // deploy verifiers - // if true, deploys verifiers for prod, generated with proper trusted setup const { registrationVerifier, mintVerifier, withdrawVerifier, transferVerifier, burnVerifier, - } = await deployVerifiers(deployer); + } = await deployVerifiers(deployer, true); // deploy babyjub library const babyJubJub = await deployLibrary(deployer); diff --git a/test/EncryptedERC-Converter.ts b/test/EncryptedERC-Converter.ts index bbe04b8..1ef75c4 100644 --- a/test/EncryptedERC-Converter.ts +++ b/test/EncryptedERC-Converter.ts @@ -58,7 +58,7 @@ describe("EncryptedERC - Converter", () => { withdrawVerifier, transferVerifier, burnVerifier, - } = await deployVerifiers(owner); + } = await deployVerifiers(owner, false); const babyJubJub = await deployLibrary(owner); for (const d of [6, 18, DECIMALS]) { @@ -302,7 +302,9 @@ describe("EncryptedERC - Converter", () => { expect(balance).to.equal(mintAmount); }); - it("should deposit tokens to EncryptedERC and return the dust properly and mint the proper balance", async () => { + it("should deposit tokens to EncryptedERC and return the dust properly and mint the proper balance", async function () { + this.timeout(120_000); + const ownerUser = users[0]; const erc20 = erc20s[1]; @@ -790,7 +792,8 @@ describe("EncryptedERC - Converter", () => { describe("Withdrawing Tokens - Lower ERC20 Decimals (6)", () => { const tokenId = 2; - const withdrawAmount = 1000n; + // eERC has 10 decimals and this token has 6, check that the scaling factor is applied properly + const withdrawAmount = 10_000n; let userInitialBalance: bigint; let validProof: { proof: CalldataWithdrawCircuitGroth16; @@ -834,6 +837,9 @@ describe("EncryptedERC - Converter", () => { const encryptedMetadata = encryptMetadata(user.publicKey, MESSAGE); + const token = erc20s[0]; // tokenId 2 is the 6-decimal token + const erc20BalanceBefore = await token.balanceOf(user.signer.address); + const tx = await encryptedERC .connect(user.signer) [ @@ -841,6 +847,12 @@ describe("EncryptedERC - Converter", () => { ](tokenId, proof, userBalancePCT, encryptedMetadata); const receipt = await tx.wait(); + const erc20BalanceAfter = await token.balanceOf(user.signer.address); + expect(erc20BalanceAfter).to.be.greaterThan(erc20BalanceBefore); + expect(erc20BalanceAfter).to.equal( + erc20BalanceBefore + withdrawAmount / 10n ** BigInt(DECIMALS - 6), + ); + const events = await encryptedERC.queryFilter( encryptedERC.filters.PrivateMessage, receipt?.blockNumber || 0, @@ -879,6 +891,40 @@ describe("EncryptedERC - Converter", () => { expect(totalBalance).to.equal(userInitialBalance - withdrawAmount); }); + it("should revert if the amount scales down to zero tokens", async () => { + const user = users[0]; + const balance = await encryptedERC.balanceOf( + user.signer.address, + tokenId, + ); + const userEncryptedBalance = [...balance.eGCT.c1, ...balance.eGCT.c2]; + const currentBalance = await getDecryptedBalance( + user.privateKey, + balance.amountPCTs, + balance.balancePCT, + balance.eGCT, + ); + + // below the 10^4 scaling factor, so _convertTo would floor the payout to 0 + // while the encrypted balance had already been debited in full + const dustAmount = 999n; + const { proof, userBalancePCT } = await withdraw( + dustAmount, + user, + userEncryptedBalance, + currentBalance, + auditorPublicKey, + ); + + await expect( + encryptedERC + .connect(user.signer) + [ + "withdraw(uint256,((uint256[2],uint256[2][2],uint256[2]),uint256[16]),uint256[7])" + ](tokenId, proof, userBalancePCT), + ).to.be.revertedWithCustomError(encryptedERC, "AmountTooSmall"); + }); + it("should revert if public keys are not matching", async () => { const user = users[1]; @@ -956,6 +1002,12 @@ describe("EncryptedERC - Converter", () => { auditorPublicKey, ); + const tokenAddress = await encryptedERC.tokenAddresses(tokenId); + const token = erc20s.find((t) => t.target === tokenAddress); + if (!token) throw new Error("token for tokenId not found"); + const tokenDecimals = Number(await token.decimals()); + const erc20BalanceBefore = await token.balanceOf(user.signer.address); + expect( await encryptedERC .connect(user.signer) @@ -964,6 +1016,16 @@ describe("EncryptedERC - Converter", () => { ](tokenId, proof, userBalancePCT), ).to.be.not.reverted; + // the underlying token must actually move, and by the scaled amount + const expectedRaw = + tokenDecimals >= DECIMALS + ? withdrawAmount * 10n ** BigInt(tokenDecimals - DECIMALS) + : withdrawAmount / 10n ** BigInt(DECIMALS - tokenDecimals); + expect(expectedRaw).to.be.greaterThan(0n); + expect(await token.balanceOf(user.signer.address)).to.equal( + erc20BalanceBefore + expectedRaw, + ); + validProof = { proof, userBalancePCT }; }); @@ -1080,6 +1142,12 @@ describe("EncryptedERC - Converter", () => { auditorPublicKey, ); + const tokenAddress = await encryptedERC.tokenAddresses(tokenId); + const token = erc20s.find((t) => t.target === tokenAddress); + if (!token) throw new Error("token for tokenId not found"); + const tokenDecimals = Number(await token.decimals()); + const erc20BalanceBefore = await token.balanceOf(user.signer.address); + expect( await encryptedERC .connect(user.signer) @@ -1088,6 +1156,16 @@ describe("EncryptedERC - Converter", () => { ](tokenId, proof, userBalancePCT), ).to.be.not.reverted; + // the underlying token must actually move, and by the scaled amount + const expectedRaw = + tokenDecimals >= DECIMALS + ? withdrawAmount * 10n ** BigInt(tokenDecimals - DECIMALS) + : withdrawAmount / 10n ** BigInt(DECIMALS - tokenDecimals); + expect(expectedRaw).to.be.greaterThan(0n); + expect(await token.balanceOf(user.signer.address)).to.equal( + erc20BalanceBefore + expectedRaw, + ); + validProof = { proof, userBalancePCT }; }); diff --git a/test/EncryptedERC-HistoryGas.ts b/test/EncryptedERC-HistoryGas.ts new file mode 100644 index 0000000..188669e --- /dev/null +++ b/test/EncryptedERC-HistoryGas.ts @@ -0,0 +1,164 @@ +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; +import { expect } from "chai"; +import { ethers, zkit } from "hardhat"; +import type { RegistrationCircuit } from "../generated-types/zkit"; +import { processPoseidonEncryption } from "../src"; +import type { EncryptedERCHarness } from "../typechain-types/contracts/mocks/EncryptedERCHarness"; +import type { Registrar } from "../typechain-types/contracts/Registrar"; +import type { SimpleERC20 } from "../typechain-types/contracts/tokens/SimpleERC20"; +import { Registrar__factory } from "../typechain-types/factories/contracts"; +import { EncryptedERCHarness__factory } from "../typechain-types/factories/contracts/mocks/EncryptedERCHarness__factory"; +import { SimpleERC20__factory } from "../typechain-types/factories/contracts/tokens"; +import { deployLibrary, deployVerifiers, withdraw } from "./helpers"; +import { User } from "./user"; + +const EERC_DECIMALS = 10; +const MAX_PENDING_AMOUNT_PCTS = 300n; +const C_CHAIN_BLOCK_GAS_LIMIT = 15_000_000n; + +describe("EncryptedERC withdrawal at the pending-history cap", () => { + let owner: SignerWithAddress; + let victimSigner: SignerWithAddress; + let registrar: Registrar; + let encryptedERC: EncryptedERCHarness; + let token: SimpleERC20; + let victim: User; + let auditor: User; + + before(async () => { + [owner, victimSigner] = await ethers.getSigners(); + victim = new User(victimSigner); + auditor = new User(owner); + + const { + registrationVerifier, + mintVerifier, + withdrawVerifier, + transferVerifier, + burnVerifier, + } = await deployVerifiers(owner, false); + const babyJubJub = await deployLibrary(owner); + + registrar = await new Registrar__factory(owner).deploy( + registrationVerifier, + ); + await registrar.waitForDeployment(); + + encryptedERC = await new EncryptedERCHarness__factory( + { "contracts/libraries/BabyJubJub.sol:BabyJubJub": babyJubJub }, + owner, + ).deploy({ + registrar: registrar.target, + isConverter: true, + name: "", + symbol: "", + decimals: EERC_DECIMALS, + mintVerifier, + withdrawVerifier, + transferVerifier, + burnVerifier, + }); + await encryptedERC.waitForDeployment(); + + token = await new SimpleERC20__factory(owner).deploy( + "Test", + "TEST", + EERC_DECIMALS, + ); + await token.waitForDeployment(); + + const registrationCircuit = (await zkit.getCircuit( + "RegistrationCircuit", + )) as unknown as RegistrationCircuit; + const chainId = (await ethers.provider.getNetwork()).chainId; + + for (const user of [victim, auditor]) { + const proof = await registrationCircuit.generateProof({ + SenderPrivateKey: user.formattedPrivateKey, + SenderPublicKey: user.publicKey, + SenderAddress: BigInt(user.signer.address), + ChainID: chainId, + RegistrationHash: user.genRegistrationHash(chainId), + }); + const calldata = await registrationCircuit.generateCalldata(proof); + await registrar.connect(user.signer).register(calldata); + } + + await encryptedERC.connect(owner).setAuditorPublicKey(owner.address); + }); + + it("withdraws and clears 300 pending entries within the C-Chain block gas limit", async function () { + this.timeout(12000_000); + const depositAmount = 10_000n; + const withdrawalAmount = 1n; + const { ciphertext, nonce, authKey } = processPoseidonEncryption( + [depositAmount], + victim.publicKey, + ); + + await token.connect(owner).mint(victim.signer.address, depositAmount); + await token + .connect(victim.signer) + .approve(encryptedERC.target, depositAmount); + await encryptedERC + .connect(victim.signer) + [ + "deposit(uint256,address,uint256[7])" + ](depositAmount, token.target, [...ciphertext, ...authKey, nonce]); + + const tokenId = await encryptedERC.tokenIds(token.target); + const zeroValuePCT = processPoseidonEncryption([0n], victim.publicKey); + for (let seeded = 1n; seeded < MAX_PENDING_AMOUNT_PCTS; seeded += 50n) { + const count = + MAX_PENDING_AMOUNT_PCTS - seeded < 50n + ? MAX_PENDING_AMOUNT_PCTS - seeded + : 50n; + + + + const tx = await encryptedERC.seedPendingHistory( + victim.signer.address, + tokenId, + [ + ...zeroValuePCT.ciphertext, + ...zeroValuePCT.authKey, + zeroValuePCT.nonce, + ], + count, + 0, + ); + await tx.wait(); + } + + const balance = await encryptedERC.balanceOf( + victim.signer.address, + tokenId, + ); + expect(balance.amountPCTs).to.have.length(Number(MAX_PENDING_AMOUNT_PCTS)); + + const { proof, userBalancePCT } = await withdraw( + withdrawalAmount, + victim, + [...balance.eGCT.c1, ...balance.eGCT.c2], + depositAmount, + await encryptedERC.auditorPublicKey(), + ); + const tokenBalanceBefore = await token.balanceOf(victim.signer.address); + const tx = await encryptedERC + .connect(victim.signer) + [ + "withdraw(uint256,((uint256[2],uint256[2][2],uint256[2]),uint256[16]),uint256[7])" + ](tokenId, proof, userBalancePCT); + const receipt = await tx.wait(); + + expect(receipt?.gasUsed).to.be.lessThan(C_CHAIN_BLOCK_GAS_LIMIT); + expect(await token.balanceOf(victim.signer.address)).to.equal( + tokenBalanceBefore + withdrawalAmount, + ); + const balanceAfter = await encryptedERC.balanceOf( + victim.signer.address, + tokenId, + ); + expect(balanceAfter.amountPCTs).to.be.empty; + }); +}); diff --git a/test/EncryptedERC-Standalone.ts b/test/EncryptedERC-Standalone.ts index b586798..07efd2d 100644 --- a/test/EncryptedERC-Standalone.ts +++ b/test/EncryptedERC-Standalone.ts @@ -209,6 +209,30 @@ describe("EncryptedERC - Standalone", () => { ).to.be.revertedWithCustomError(registrar, "UserAlreadyRegistered"); }); + it("already registered user can not register again with a new key", async () => { + const alreadyRegisteredSigner = users[4].signer; + const rotated = new User(alreadyRegisteredSigner); + const chainId = await ethers.provider + .getNetwork() + .then((network) => network.chainId); + + const zkProof = await registrationCircuit.generateProof({ + SenderPrivateKey: rotated.formattedPrivateKey, + SenderPublicKey: rotated.publicKey, + SenderAddress: BigInt(alreadyRegisteredSigner.address), + ChainID: chainId, + RegistrationHash: rotated.genRegistrationHash(chainId), + }); + const calldata = await registrationCircuit.generateCalldata(zkProof); + + await expect( + registrar.connect(alreadyRegisteredSigner).register({ + proofPoints: calldata.proofPoints, + publicSignals: calldata.publicSignals, + } as RegisterProofStruct), + ).to.be.revertedWithCustomError(registrar, "UserAlreadyRegistered"); + }); + it("should revert if sender is not matching", async () => { // valid proof is for user[4] but we are using user[0] const sender = users[0]; diff --git a/test/EncryptedUserBalances.ts b/test/EncryptedUserBalances.ts new file mode 100644 index 0000000..c5e2519 --- /dev/null +++ b/test/EncryptedUserBalances.ts @@ -0,0 +1,56 @@ +import type { SignerWithAddress } from "@nomicfoundation/hardhat-ethers/signers"; +import { expect } from "chai"; +import { ethers } from "hardhat"; +import type { EncryptedUserBalancesHarness } from "../typechain-types/contracts/mocks/EncryptedUserBalancesHarness"; +import { EncryptedUserBalancesHarness__factory } from "../typechain-types/factories/contracts/mocks/EncryptedUserBalancesHarness__factory"; + +describe("EncryptedUserBalances pending history", () => { + let harness: EncryptedUserBalancesHarness; + let owner: SignerWithAddress; + let victim: SignerWithAddress; + + const seedHistory = async (tokenId: bigint, count: bigint) => { + const batchSize = 50n; + for (let seeded = 0n; seeded < count; seeded += batchSize) { + const batch = count - seeded < batchSize ? count - seeded : batchSize; + await harness.seedHistory(victim.address, tokenId, batch); + } + }; + + before(async () => { + [owner, victim] = await ethers.getSigners(); + const factory = new EncryptedUserBalancesHarness__factory(owner); + harness = await factory.deploy(); + await harness.waitForDeployment(); + }); + + it("rejects a credit once the pending-history cap is reached", async () => { + const maxPendingAmountPCTs = await harness.MAX_PENDING_AMOUNT_PCTS(); + await seedHistory(0n, maxPendingAmountPCTs - 1n); + await expect(harness.appendHistory(victim.address, 0)).to.not.be.reverted; + await expect( + harness.appendHistory(victim.address, 0), + ).to.be.revertedWithCustomError(harness, "PendingHistoryLimitReached"); + }); + + it("prunes a worst-case full history within the configured gas budget", async () => { + const tokenId = 1; + const maxPendingAmountPCTs = await harness.MAX_PENDING_AMOUNT_PCTS(); + await seedHistory(BigInt(tokenId), maxPendingAmountPCTs); + + const tx = await harness.pruneHistory( + victim.address, + tokenId, + maxPendingAmountPCTs - 1n, + ); + const receipt = await tx.wait(); + + // Avalanche C-Chain's documented block gas limit reference is 15M. This is + // intentionally only a benchmark guard: a full transfer/withdrawal must be + // measured separately because it also includes proof verification and payout work. + expect(receipt?.gasUsed).to.be.lessThan(12_000_000n); + expect( + await harness.pendingHistoryLength(victim.address, tokenId), + ).to.equal(0n); + }); +}); diff --git a/test/helpers.ts b/test/helpers.ts index d885d93..a1a69f9 100644 --- a/test/helpers.ts +++ b/test/helpers.ts @@ -45,7 +45,7 @@ import type { User } from "./user"; */ export const deployVerifiers = async ( signer: SignerWithAddress, - isProd?: boolean, + isProd: boolean, ) => { if (isProd) { const registrationVerifierFactory = new RegistrationVerifier__factory(