diff --git a/packages/contracts/foundry.toml b/packages/contracts/foundry.toml new file mode 100644 index 0000000..e210486 --- /dev/null +++ b/packages/contracts/foundry.toml @@ -0,0 +1,14 @@ +[profile.default] +src = "src" +out = "artifacts" +libs = ["../../node_modules", "lib"] +optimizer = true +optimizer-runs = 20_000 + +solc = "0.8.26" + +# See more config options https://github.com/foundry-rs/foundry/tree/master/config + +# OpenZeppelin +build_info = true +extra_output = ["storageLayout"] diff --git a/packages/contracts/package.json b/packages/contracts/package.json new file mode 100644 index 0000000..87d8004 --- /dev/null +++ b/packages/contracts/package.json @@ -0,0 +1,29 @@ +{ + "name": "@zk-jwt/zk-jwt-contracts", + "version": "0.0.1", + "license": "MIT", + "scripts": { + "build": "forge build --skip '*ZKSync*'", + "test": "forge test", + "lint": "solhint 'src/**/*.sol'" + }, + "dependencies": { + "@openzeppelin/contracts": "^5.0.0", + "@openzeppelin/contracts-upgradeable": "^5.0.0", + "@zk-email/contracts": "^6.1.5", + "solady": "^0.0.123", + "solidity-stringutils": "github:LayerZero-Labs/solidity-stringutils" + }, + "devDependencies": { + "ds-test": "https://github.com/dapphub/ds-test", + "forge-std": "https://github.com/foundry-rs/forge-std", + "solhint": "^3.6.1" + }, + "files": [ + "/src", + "foundry.toml", + "package.json", + "README.md", + "remappings.txt" + ] +} diff --git a/packages/contracts/remappings.txt b/packages/contracts/remappings.txt new file mode 100644 index 0000000..8191978 --- /dev/null +++ b/packages/contracts/remappings.txt @@ -0,0 +1,6 @@ +@openzeppelin/=../../node_modules/@openzeppelin +@openzeppelin/contracts-upgradeable/=../../node_modules/@openzeppelin/contracts-upgradeable +@zk-email/=../../node_modules/@zk-email +forge-std/=../../node_modules/forge-std/src +ds-test/=../../node_modules/ds-test/src +solidity-stringutils/=../../node_modules/solidity-stringutils/ \ No newline at end of file diff --git a/packages/contracts/src/interfaces/IJwtGroth16Verifier.sol b/packages/contracts/src/interfaces/IJwtGroth16Verifier.sol new file mode 100644 index 0000000..12bb3a5 --- /dev/null +++ b/packages/contracts/src/interfaces/IJwtGroth16Verifier.sol @@ -0,0 +1,11 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +interface IJwtGroth16Verifier { + function verifyProof( + uint[2] calldata _pA, + uint[2][2] calldata _pB, + uint[2] calldata _pC, + uint[29] calldata _pubSignals + ) external view returns (bool); +} diff --git a/packages/contracts/src/libraries/CommandUtils.sol b/packages/contracts/src/libraries/CommandUtils.sol new file mode 100644 index 0000000..71fba9d --- /dev/null +++ b/packages/contracts/src/libraries/CommandUtils.sol @@ -0,0 +1,169 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import "@openzeppelin/contracts/utils/Strings.sol"; +import "@openzeppelin/contracts/token/ERC20/ERC20.sol"; +import {Address} from "@openzeppelin/contracts/utils/Address.sol"; +import "./DecimalUtils.sol"; + +library CommandUtils { + bytes16 private constant LOWER_HEX_DIGITS = "0123456789abcdef"; + bytes16 private constant UPPER_HEX_DIGITS = "0123456789ABCDEF"; + string public constant STRING_MATCHER = "{string}"; + string public constant UINT_MATCHER = "{uint}"; + string public constant INT_MATCHER = "{int}"; + string public constant DECIMALS_MATCHER = "{decimals}"; + string public constant ETH_ADDR_MATCHER = "{ethAddr}"; + + function addressToHexString( + address addr, + uint stringCase + ) internal pure returns (string memory) { + if (stringCase == 0) { + return addressToChecksumHexString(addr); + } else if (stringCase == 1) { + return Strings.toHexString(addr); + } else if (stringCase == 2) { + return lowerToUpperCase(Strings.toHexString(addr)); + } else { + revert("invalid stringCase"); + } + } + + function addressToChecksumHexString( + address addr + ) internal pure returns (string memory) { + string memory lowerCaseAddrWithOx = Strings.toHexString(addr); + + bytes memory lowerCaseAddr = new bytes(40); // Remove 0x added by the OZ lib + for (uint8 i = 2; i < 42; i++) { + lowerCaseAddr[i - 2] = bytes(lowerCaseAddrWithOx)[i]; + } + + // Hash of lowercase addr + uint256 lowerCaseHash = uint256( + keccak256(abi.encodePacked(lowerCaseAddr)) + ); + + // Result hex = 42 chars with 0x prefix + bytes memory result = new bytes(42); + result[0] = "0"; + result[1] = "x"; + + // Shift 24 bytes (96 bits) to the right; as we only need first 20 bytes of the hash to compare + lowerCaseHash >>= 24 * 4; + + uint256 intAddr = uint256(uint160(addr)); + + for (uint8 i = 41; i > 1; --i) { + uint8 hashChar = uint8(lowerCaseHash & 0xf); // Get last char of the hex + uint8 addrChar = uint8(intAddr & 0xf); // Get last char of the address + + if (hashChar >= 8) { + result[i] = UPPER_HEX_DIGITS[addrChar]; + } else { + result[i] = LOWER_HEX_DIGITS[addrChar]; + } + + // Remove last char from both hash and addr + intAddr >>= 4; + lowerCaseHash >>= 4; + } + + return string(result); + } + + function lowerToUpperCase( + string memory hexStr + ) internal pure returns (string memory) { + bytes memory bytesStr = bytes(hexStr); + for (uint i = 0; i < bytesStr.length; i++) { + if (bytesStr[i] >= 0x61 && bytesStr[i] <= 0x66) { + bytesStr[i] = bytes1(uint8(bytesStr[i]) - 32); + } + } + return string(bytesStr); + } + + /// @notice Convert bytes to hex string without 0x prefix + /// @param data bytes to convert + function bytesToHexString( + bytes memory data + ) public pure returns (string memory) { + bytes memory hexChars = "0123456789abcdef"; + bytes memory hexString = new bytes(2 * data.length); + + for (uint256 i = 0; i < data.length; i++) { + uint256 value = uint256(uint8(data[i])); + hexString[2 * i] = hexChars[value >> 4]; + hexString[2 * i + 1] = hexChars[value & 0xf]; + } + + return string(hexString); + } + + /// @notice Calculate the expected command. + /// @param commandParams Params to be used in the command + /// @param template Template to be used for the command + /// @param stringCase Case of the ethereum address string to be used for the command - 0: checksum, 1: lowercase, 2: uppercase + function computeExpectedCommand( + bytes[] memory commandParams, + string[] memory template, + uint stringCase + ) public pure returns (string memory expectedCommand) { + // Construct an expectedCommand from template and the values of commandParams. + uint8 nextParamIndex = 0; + string memory stringParam; + bool isParamExist; + for (uint8 i = 0; i < template.length; i++) { + isParamExist = true; + if (Strings.equal(template[i], STRING_MATCHER)) { + string memory param = abi.decode( + commandParams[nextParamIndex], + (string) + ); + stringParam = param; + } else if (Strings.equal(template[i], UINT_MATCHER)) { + uint256 param = abi.decode( + commandParams[nextParamIndex], + (uint256) + ); + stringParam = Strings.toString(param); + } else if (Strings.equal(template[i], INT_MATCHER)) { + int256 param = abi.decode( + commandParams[nextParamIndex], + (int256) + ); + stringParam = Strings.toStringSigned(param); + } else if (Strings.equal(template[i], DECIMALS_MATCHER)) { + uint256 param = abi.decode( + commandParams[nextParamIndex], + (uint256) + ); + stringParam = DecimalUtils.uintToDecimalString(param); + } else if (Strings.equal(template[i], ETH_ADDR_MATCHER)) { + address param = abi.decode( + commandParams[nextParamIndex], + (address) + ); + stringParam = addressToHexString(param, stringCase); + } else { + isParamExist = false; + stringParam = template[i]; + } + + if (i > 0) { + expectedCommand = string( + abi.encodePacked(expectedCommand, " ") + ); + } + expectedCommand = string( + abi.encodePacked(expectedCommand, stringParam) + ); + if (isParamExist) { + nextParamIndex++; + } + } + return expectedCommand; + } +} diff --git a/packages/contracts/src/libraries/DecimalUtils.sol b/packages/contracts/src/libraries/DecimalUtils.sol new file mode 100644 index 0000000..2669bf7 --- /dev/null +++ b/packages/contracts/src/libraries/DecimalUtils.sol @@ -0,0 +1,84 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import "@openzeppelin/contracts/utils/Strings.sol"; + +/// @title DecimalUtils +/// @notice DecimalUtils library for converting uint256 to string with decimal places +library DecimalUtils { + /// @notice Convert uint256 to human readable string with decimal places + /// @param value uint256 value to convert + /// @return string representation of value with decimal places + function uintToDecimalString(uint256 value) public pure returns (string memory) { + return uintToDecimalString(value, 18); + } + + /// @notice Convert uint256 to human readable string with decimal places + /// @param value uint256 value to convert + /// @param decimal number of decimal places + /// @return string representation of value with decimal places + function uintToDecimalString(uint256 value, uint decimal) public pure returns (string memory) { + // Convert value to string in wei format (no decimals) + bytes memory valueBytes = bytes(Strings.toString(value)); + uint8 valueLength = uint8(valueBytes.length); + + // Create result array with max length + // If less than 18 decimals, then 2 extra for "0.", otherwise one extra for "." + bytes memory result = new bytes(valueLength > decimal ? valueLength + 1 : decimal + 2); + uint8 resultLength = uint8(result.length); + + // We will be populating result array by copying from value array from last to first index + // Difference between result and value array index when copying + // If more than 18, then 1 index diff for ".", otherwise actual diff in length + uint delta = valueLength > decimal ? 1 : resultLength - valueLength; + + // Boolean to indicate if we found a non-zero digit when scanning from last to first index + bool foundNonZeroDecimal; + + uint8 actualResultLen = 0; + + // In each iteration we fill one index of result array (starting from end) + for (uint8 i = resultLength - 1; i >= 0; i--) { + // Check if we have reached the index where we need to add decimal point + if (i == resultLength - decimal - 1) { + // No need to add "." if there was no value in decimal places + if (foundNonZeroDecimal) { + result[i] = "."; + actualResultLen++; + } + // Set delta to 0, as we have already added decimal point (only for valueLength > 18) + delta = 0; + } + // If valueLength < 18 and we have copied everything, fill zeros + else if (valueLength <= decimal && i < resultLength - valueLength) { + result[i] = "0"; + actualResultLen++; + } + // If non-zero decimal is found, or decimal point inserted (delta == 0), copy from value array + else if (foundNonZeroDecimal || delta == 0) { + result[i] = valueBytes[i - delta]; + actualResultLen++; + } + // If we find non-zero decumal for the first time (trailing zeros are skipped) + else if (valueBytes[i - delta] != "0") { + result[i] = valueBytes[i - delta]; + actualResultLen++; + foundNonZeroDecimal = true; + } + + // To prevent the last i-- underflow + if (i == 0) { + break; + } + } + + // Create final result array with correct length + bytes memory compactResult = new bytes(actualResultLen); + for (uint8 i = 0; i < actualResultLen; i++) { + compactResult[i] = result[i]; + } + + return string(compactResult); + } +} + diff --git a/packages/contracts/src/utils/JwtGroth16Verifier.sol b/packages/contracts/src/utils/JwtGroth16Verifier.sol new file mode 100644 index 0000000..f071aa4 --- /dev/null +++ b/packages/contracts/src/utils/JwtGroth16Verifier.sol @@ -0,0 +1,366 @@ +// SPDX-License-Identifier: GPL-3.0 +/* + Copyright 2021 0KIMS association. + + This file is generated with [snarkJS](https://github.com/iden3/snarkjs). + + snarkJS is a free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + snarkJS is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with snarkJS. If not, see . +*/ + +pragma solidity >=0.7.0 <0.9.0; + +contract JwtGroth16Verifier { + // Scalar field size + uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617; + // Base field size + uint256 constant q = 21888242871839275222246405745257275088696311157297823662689037894645226208583; + + // Verification Key data + uint256 constant alphax = 20491192805390485299153009773594534940189261866228447918068658471970481763042; + uint256 constant alphay = 9383485363053290200918347156157836566562967994039712273449902621266178545958; + uint256 constant betax1 = 4252822878758300859123897981450591353533073413197771768651442665752259397132; + uint256 constant betax2 = 6375614351688725206403948262868962793625744043794305715222011528459656738731; + uint256 constant betay1 = 21847035105528745403288232691147584728191162732299865338377159692350059136679; + uint256 constant betay2 = 10505242626370262277552901082094356697409835680220590971873171140371331206856; + uint256 constant gammax1 = 11559732032986387107991004021392285783925812861821192530917403151452391805634; + uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; + uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; + uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; + uint256 constant deltax1 = 10549777989399769958726389370849764963770472615831368230407664432103868982675; + uint256 constant deltax2 = 14502498257060744023211073684244073105466434668316660619882397771907239253228; + uint256 constant deltay1 = 15460511406384615559133697878851982197412588892070984182587282855147632409439; + uint256 constant deltay2 = 15706936609177006543020474039293130526375576223590942516970433270916529663361; + + + uint256 constant IC0x = 872606828030983860592300877698929270582888399564175612547068673523717109895; + uint256 constant IC0y = 16143353238358547725255411752605729649296628753837782656658542933778396820583; + + uint256 constant IC1x = 12265908708087654954032743238562936502151179798171151633045588165431814781180; + uint256 constant IC1y = 20317665727073110703491875492529167846517557655472268791286549375590586834011; + + uint256 constant IC2x = 13555038289040741270199070239156049732204714048225671298424430354385921312093; + uint256 constant IC2y = 18539222167856683655951674285330072710179543682951086969104261442525466224858; + + uint256 constant IC3x = 778495765860799448817576490931323546943978689713790021372064878419020150316; + uint256 constant IC3y = 494553016225160595577705461368517119685374103360884678008858848889200439064; + + uint256 constant IC4x = 12398343966874487415350396909198295847570025668003442383817332777601412219889; + uint256 constant IC4y = 16714352332752650123918217255861075985654897229322373298154673955416867933218; + + uint256 constant IC5x = 20058113596528792487079709288155949888401927523962014818284928778921150266014; + uint256 constant IC5y = 21332453060422800036059002226889090001149749843720594137048024105170372843905; + + uint256 constant IC6x = 8855582251881039453030124452784255483997420186795741415227250166780241788288; + uint256 constant IC6y = 15468312935411647124754419121313227360803528182577025376722361384771576792597; + + uint256 constant IC7x = 2079462284470952561077330148838559378276804012441503877401058554283817803801; + uint256 constant IC7y = 11056940595793292781403432345930717153138049622173232094082489064018377286041; + + uint256 constant IC8x = 12359566777632008687393557893922226564964238282511381687636166509778629553810; + uint256 constant IC8y = 13535066563726494994452555914165886943395915356905247578846064476230962653611; + + uint256 constant IC9x = 12163413325655334444679547295647907810060532057025890248240324529909445916715; + uint256 constant IC9y = 4338071106711357628319181403104692173120999800969585953325363233625163497378; + + uint256 constant IC10x = 21440733912063113684645321600087261009689201443963650698710232363987040828205; + uint256 constant IC10y = 13039061739615000188505424099132138777355284028631872894854764583980793395824; + + uint256 constant IC11x = 19787220108554346544268814765120452370266605206707914319337059031217135416469; + uint256 constant IC11y = 5597752880793288223814091166942773001663317295472390750958642344637104028920; + + uint256 constant IC12x = 14858146815035094200094281491646140482701820554036327258210557014243484514305; + uint256 constant IC12y = 5892541671495102482183807536696566072802300515560462587307550046825210873586; + + uint256 constant IC13x = 8221849920624416593872695506953240866480850640379330710913793615308136324818; + uint256 constant IC13y = 7745784026512692211241165911437749686430701650147778782437634989876571106983; + + uint256 constant IC14x = 17732322143027430212345955469649211088341821001767479930667911708469971167202; + uint256 constant IC14y = 19960092666542822742374166372236746415442298531714271546003660888711688587103; + + uint256 constant IC15x = 16402148893814537562759607389844318916910409271647458313059610097463481680930; + uint256 constant IC15y = 249648273105558663391245379487352565538865656524321081795915521092084807120; + + uint256 constant IC16x = 7988779306762924126313365403981356363536541596092425432570912165604859707105; + uint256 constant IC16y = 13925220901161078130802861697545632068418900326879106225092741184405951835528; + + uint256 constant IC17x = 725947777039477123028298538226504453206421848139386625704712857149719502614; + uint256 constant IC17y = 19363194562886607008835385215213876015529510742259848604367319864246400288753; + + uint256 constant IC18x = 13024863362326476504452743655782164875467871886576274249622182387213129519618; + uint256 constant IC18y = 17400959071561873122317992031530664128374438607625173844796765150102347187029; + + uint256 constant IC19x = 20829495189101340618285759318336917939300086636158800249683709177064184437124; + uint256 constant IC19y = 11764021894040816729882567419051957308954208213974822954783552658830042754115; + + uint256 constant IC20x = 19029438887117546008281965640537744497836433346842764388495665879920145129023; + uint256 constant IC20y = 231249257769735443031836178461428220211275670614776518364124268003767444707; + + uint256 constant IC21x = 17652439817140328466955839239603697195109758087455386443678778613024044139017; + uint256 constant IC21y = 11239780772121008173364749783927816127577868864487279447082268155801336450561; + + uint256 constant IC22x = 2565110039970180818767016133390668682923622378478033298258732840262413896219; + uint256 constant IC22y = 7467000071585930486040421387204561503626158518910340225795894354637295685889; + + uint256 constant IC23x = 21714241639304687288913620472305736692608993986519324757161879017312825627118; + uint256 constant IC23y = 2830575965824696341680224605948267820324810550159396460619767915398042832534; + + uint256 constant IC24x = 403119414448893587314787663875355242060508011977703696748226977119669177132; + uint256 constant IC24y = 18899030463724229387506986110772957429104571614140492361744850192305881995795; + + uint256 constant IC25x = 3302097018001317843455587405027622933208258795282906920194148100469477523065; + uint256 constant IC25y = 6244129777900445045320120857971061780485782433602979734156228911038790916687; + + uint256 constant IC26x = 8069966615364393574371924730938173379727114216975630144928950411352976588254; + uint256 constant IC26y = 11148667217462571338135939510045978964169817059675428310090023257941682851365; + + uint256 constant IC27x = 4280584513388817687800819992741413300509629450219203110461303899658366758908; + uint256 constant IC27y = 6377570450293890528389059875414063307025051226594147258022596703803353787295; + + uint256 constant IC28x = 1929892399375702318351689243746021783300189631002191311565897218693119891327; + uint256 constant IC28y = 4355045708884409659650985273147369689565071946103991480833476739475691036270; + + uint256 constant IC29x = 2145294001901703374921853511109413567576578310613203520667349284762655376110; + uint256 constant IC29y = 18561375458318728519666122108349456576334559552878246394841147883447979984777; + + + // Memory data + uint16 constant pVk = 0; + uint16 constant pPairing = 128; + + uint16 constant pLastMem = 896; + + function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[29] calldata _pubSignals) public view returns (bool) { + assembly { + function checkField(v) { + if iszero(lt(v, r)) { + mstore(0, 0) + return(0, 0x20) + } + } + + // G1 function to multiply a G1 value(x,y) to value in an address + function g1_mulAccC(pR, x, y, s) { + let success + let mIn := mload(0x40) + mstore(mIn, x) + mstore(add(mIn, 32), y) + mstore(add(mIn, 64), s) + + success := staticcall(sub(gas(), 2000), 7, mIn, 96, mIn, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + + mstore(add(mIn, 64), mload(pR)) + mstore(add(mIn, 96), mload(add(pR, 32))) + + success := staticcall(sub(gas(), 2000), 6, mIn, 128, pR, 64) + + if iszero(success) { + mstore(0, 0) + return(0, 0x20) + } + } + + function checkPairing(pA, pB, pC, pubSignals, pMem) -> isOk { + let _pPairing := add(pMem, pPairing) + let _pVk := add(pMem, pVk) + + mstore(_pVk, IC0x) + mstore(add(_pVk, 32), IC0y) + + // Compute the linear combination vk_x + + g1_mulAccC(_pVk, IC1x, IC1y, calldataload(add(pubSignals, 0))) + + g1_mulAccC(_pVk, IC2x, IC2y, calldataload(add(pubSignals, 32))) + + g1_mulAccC(_pVk, IC3x, IC3y, calldataload(add(pubSignals, 64))) + + g1_mulAccC(_pVk, IC4x, IC4y, calldataload(add(pubSignals, 96))) + + g1_mulAccC(_pVk, IC5x, IC5y, calldataload(add(pubSignals, 128))) + + g1_mulAccC(_pVk, IC6x, IC6y, calldataload(add(pubSignals, 160))) + + g1_mulAccC(_pVk, IC7x, IC7y, calldataload(add(pubSignals, 192))) + + g1_mulAccC(_pVk, IC8x, IC8y, calldataload(add(pubSignals, 224))) + + g1_mulAccC(_pVk, IC9x, IC9y, calldataload(add(pubSignals, 256))) + + g1_mulAccC(_pVk, IC10x, IC10y, calldataload(add(pubSignals, 288))) + + g1_mulAccC(_pVk, IC11x, IC11y, calldataload(add(pubSignals, 320))) + + g1_mulAccC(_pVk, IC12x, IC12y, calldataload(add(pubSignals, 352))) + + g1_mulAccC(_pVk, IC13x, IC13y, calldataload(add(pubSignals, 384))) + + g1_mulAccC(_pVk, IC14x, IC14y, calldataload(add(pubSignals, 416))) + + g1_mulAccC(_pVk, IC15x, IC15y, calldataload(add(pubSignals, 448))) + + g1_mulAccC(_pVk, IC16x, IC16y, calldataload(add(pubSignals, 480))) + + g1_mulAccC(_pVk, IC17x, IC17y, calldataload(add(pubSignals, 512))) + + g1_mulAccC(_pVk, IC18x, IC18y, calldataload(add(pubSignals, 544))) + + g1_mulAccC(_pVk, IC19x, IC19y, calldataload(add(pubSignals, 576))) + + g1_mulAccC(_pVk, IC20x, IC20y, calldataload(add(pubSignals, 608))) + + g1_mulAccC(_pVk, IC21x, IC21y, calldataload(add(pubSignals, 640))) + + g1_mulAccC(_pVk, IC22x, IC22y, calldataload(add(pubSignals, 672))) + + g1_mulAccC(_pVk, IC23x, IC23y, calldataload(add(pubSignals, 704))) + + g1_mulAccC(_pVk, IC24x, IC24y, calldataload(add(pubSignals, 736))) + + g1_mulAccC(_pVk, IC25x, IC25y, calldataload(add(pubSignals, 768))) + + g1_mulAccC(_pVk, IC26x, IC26y, calldataload(add(pubSignals, 800))) + + g1_mulAccC(_pVk, IC27x, IC27y, calldataload(add(pubSignals, 832))) + + g1_mulAccC(_pVk, IC28x, IC28y, calldataload(add(pubSignals, 864))) + + g1_mulAccC(_pVk, IC29x, IC29y, calldataload(add(pubSignals, 896))) + + + // -A + mstore(_pPairing, calldataload(pA)) + mstore(add(_pPairing, 32), mod(sub(q, calldataload(add(pA, 32))), q)) + + // B + mstore(add(_pPairing, 64), calldataload(pB)) + mstore(add(_pPairing, 96), calldataload(add(pB, 32))) + mstore(add(_pPairing, 128), calldataload(add(pB, 64))) + mstore(add(_pPairing, 160), calldataload(add(pB, 96))) + + // alpha1 + mstore(add(_pPairing, 192), alphax) + mstore(add(_pPairing, 224), alphay) + + // beta2 + mstore(add(_pPairing, 256), betax1) + mstore(add(_pPairing, 288), betax2) + mstore(add(_pPairing, 320), betay1) + mstore(add(_pPairing, 352), betay2) + + // vk_x + mstore(add(_pPairing, 384), mload(add(pMem, pVk))) + mstore(add(_pPairing, 416), mload(add(pMem, add(pVk, 32)))) + + + // gamma2 + mstore(add(_pPairing, 448), gammax1) + mstore(add(_pPairing, 480), gammax2) + mstore(add(_pPairing, 512), gammay1) + mstore(add(_pPairing, 544), gammay2) + + // C + mstore(add(_pPairing, 576), calldataload(pC)) + mstore(add(_pPairing, 608), calldataload(add(pC, 32))) + + // delta2 + mstore(add(_pPairing, 640), deltax1) + mstore(add(_pPairing, 672), deltax2) + mstore(add(_pPairing, 704), deltay1) + mstore(add(_pPairing, 736), deltay2) + + + let success := staticcall(sub(gas(), 2000), 8, _pPairing, 768, _pPairing, 0x20) + + isOk := and(success, mload(_pPairing)) + } + + let pMem := mload(0x40) + mstore(0x40, add(pMem, pLastMem)) + + // Validate that all evaluations ∈ F + + checkField(calldataload(add(_pubSignals, 0))) + + checkField(calldataload(add(_pubSignals, 32))) + + checkField(calldataload(add(_pubSignals, 64))) + + checkField(calldataload(add(_pubSignals, 96))) + + checkField(calldataload(add(_pubSignals, 128))) + + checkField(calldataload(add(_pubSignals, 160))) + + checkField(calldataload(add(_pubSignals, 192))) + + checkField(calldataload(add(_pubSignals, 224))) + + checkField(calldataload(add(_pubSignals, 256))) + + checkField(calldataload(add(_pubSignals, 288))) + + checkField(calldataload(add(_pubSignals, 320))) + + checkField(calldataload(add(_pubSignals, 352))) + + checkField(calldataload(add(_pubSignals, 384))) + + checkField(calldataload(add(_pubSignals, 416))) + + checkField(calldataload(add(_pubSignals, 448))) + + checkField(calldataload(add(_pubSignals, 480))) + + checkField(calldataload(add(_pubSignals, 512))) + + checkField(calldataload(add(_pubSignals, 544))) + + checkField(calldataload(add(_pubSignals, 576))) + + checkField(calldataload(add(_pubSignals, 608))) + + checkField(calldataload(add(_pubSignals, 640))) + + checkField(calldataload(add(_pubSignals, 672))) + + checkField(calldataload(add(_pubSignals, 704))) + + checkField(calldataload(add(_pubSignals, 736))) + + checkField(calldataload(add(_pubSignals, 768))) + + checkField(calldataload(add(_pubSignals, 800))) + + checkField(calldataload(add(_pubSignals, 832))) + + checkField(calldataload(add(_pubSignals, 864))) + + checkField(calldataload(add(_pubSignals, 896))) + + checkField(calldataload(add(_pubSignals, 928))) + + + // Validate all evaluations + let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem) + + mstore(0, isValid) + return(0, 0x20) + } + } + } diff --git a/packages/contracts/src/utils/JwtRegistry.sol b/packages/contracts/src/utils/JwtRegistry.sol new file mode 100644 index 0000000..0ed7d8f --- /dev/null +++ b/packages/contracts/src/utils/JwtRegistry.sol @@ -0,0 +1,103 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.12; + +import "@zk-email/contracts/DKIMRegistry.sol"; +import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; +import {MessageHashUtils} from "@openzeppelin/contracts/utils/cryptography/MessageHashUtils.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { strings } from "solidity-stringutils/src/strings.sol"; + +/// @title JWT Registry +/// @notice TODO +/// @dev TODO +contract JwtRegistry is IDKIMRegistry, Ownable { + + using strings for *; + + DKIMRegistry public dkimRegistry; + + // Check if azp is registered + mapping(string => bool) public whitelistedClients; + + constructor(address _owner) Ownable(_owner) { + dkimRegistry = new DKIMRegistry(address(this)); + } + + /// @notice Checks if a public key hash is valid and not revoked for a given kis and iss. + /// @param domainName The domain name contains kis, iss and azp fields. + /// @param publicKeyHash The public key hash to validate. + /// @return bool Returns true if the public key hash is valid and not revoked, false otherwise. + function isDKIMPublicKeyHashValid( + string memory domainName, + bytes32 publicKeyHash + ) public view returns (bool) { + string[] memory parts = this.stringToArray(domainName); + string memory kidAndIss = string(abi.encode(parts[0], "|", parts[1])); + return dkimRegistry.isDKIMPublicKeyHashValid(kidAndIss, publicKeyHash) + && whitelistedClients[parts[2]]; + } + + /// @notice Sets a public key hash for a `kis|iss` string after validating the provided signature. + /// @param domainName The domain name contains kis, iss and azp fields. + /// @param publicKeyHash The public key hash to set. + /// @dev This function requires that the public key hash is not already set or revoked. + function setDKIMPublicKeyHash( + string memory domainName, + bytes32 publicKeyHash + ) public { + require(bytes(domainName).length != 0, "Invalid domain name"); + require(publicKeyHash != bytes32(0), "Invalid public key hash"); + string[] memory parts = this.stringToArray(domainName); + string memory kidAndIss = string(abi.encode(parts[0], "|", parts[1])); + require( + isDKIMPublicKeyHashValid(domainName, publicKeyHash) == false, + "publicKeyHash is already set" + ); + require( + dkimRegistry.revokedDKIMPublicKeyHashes(publicKeyHash) == false, + "publicKeyHash is revoked" + ); + + dkimRegistry.setDKIMPublicKeyHash(kidAndIss, publicKeyHash); + // Register azp + whitelistedClients[parts[2]] = true; + } + + /// @notice Revokes a public key hash for `kis|iss` string after validating the provided signature. + /// @param domainName The domain name contains kis, iss and azp fields. + /// @param publicKeyHash The public key hash to revoke. + /// @dev This function requires that the public key hash is currently set and not already revoked. + function revokeDKIMPublicKeyHash( + string memory domainName, + bytes32 publicKeyHash + ) public { + require(bytes(domainName).length != 0, "Invalid domain name"); + require(publicKeyHash != bytes32(0), "Invalid public key hash"); + require( + isDKIMPublicKeyHashValid(domainName, publicKeyHash) == true, + "publicKeyHash is not set" + ); + require( + dkimRegistry.revokedDKIMPublicKeyHashes(publicKeyHash) == false, + "publicKeyHash is already revoked" + ); + + dkimRegistry.revokeDKIMPublicKeyHash(publicKeyHash); + // Disable azp + string[] memory parts = this.stringToArray(domainName); + whitelistedClients[parts[2]] = false; + } + + function stringToArray(string memory _strings) external pure returns (string[] memory) { + strings.slice memory slicee = _strings.toSlice(); + strings.slice memory delim = "|".toSlice(); + string[] memory parts = new string[](slicee.count(delim) + 1); + for (uint i = 0; i < parts.length; i++) { + parts[i] = slicee.split(delim).toString(); + } + require(parts.length == 3, "Invalid kid|iss|azp strings"); + return parts; + } +} diff --git a/packages/contracts/src/utils/JwtVerifier.sol b/packages/contracts/src/utils/JwtVerifier.sol new file mode 100644 index 0000000..2b2d3ce --- /dev/null +++ b/packages/contracts/src/utils/JwtVerifier.sol @@ -0,0 +1,158 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.9; + +import "../interfaces/IJwtGroth16Verifier.sol"; +import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import { strings } from "solidity-stringutils/src/strings.sol"; + +struct EmailProof { + string domainName; // Domain name of the sender's email + bytes32 publicKeyHash; // Hash of the DKIM public key used in email/proof + uint timestamp; // Timestamp of the email + string maskedCommand; // Masked command of the email + bytes32 emailNullifier; // Nullifier of the email to prevent its reuse. + bytes32 accountSalt; // Create2 salt of the account + bool isCodeExist; // Check if the account code is exist + bytes proof; // ZK Proof of Email +} + +contract JwtVerifier is OwnableUpgradeable, UUPSUpgradeable { + using strings for *; + + IJwtGroth16Verifier groth16Verifier; + + uint256 public constant ISS_FIELDS = 2; + uint256 public constant ISS_BYTES = 32; + uint256 public constant COMMAND_FIELDS = 20; + uint256 public constant COMMAND_BYTES = 605; + uint256 public constant AZP_FIELDS = 1; + uint256 public constant AZP_BYTES = 14; + + constructor() {} + + /// @notice Initialize the contract with the initial owner and deploy Groth16Verifier + /// @param _initialOwner The address of the initial owner + function initialize( + address _initialOwner, + address _groth16Verifier + ) public initializer { + __Ownable_init(_initialOwner); + groth16Verifier = IJwtGroth16Verifier(_groth16Verifier); + } + + function verifyEmailProof( + EmailProof memory proof + ) public view returns (bool) { + ( + uint256[2] memory pA, + uint256[2][2] memory pB, + uint256[2] memory pC + ) = abi.decode(proof.proof, (uint256[2], uint256[2][2], uint256[2])); + + uint256[ISS_FIELDS + COMMAND_FIELDS + AZP_FIELDS + 6] memory pubSignals; + + // string[] = [kid, iss, azp] + string[] memory parts = this.stringToArray(proof.domainName); + + // kid + pubSignals[0] = uint256(stringToBytes32(parts[0])); + + // iss + uint256[] memory stringFields; + stringFields = _packBytes2Fields(bytes(parts[1]), ISS_BYTES); + for (uint256 i = 0; i < ISS_FIELDS; i++) { + pubSignals[1 + i] = stringFields[i]; + } + // publicKeyHash; + pubSignals[1 + ISS_FIELDS] = uint256(proof.publicKeyHash); + // jwtNullifier; + pubSignals[1 + ISS_FIELDS + 1] = uint256(proof.emailNullifier); + // timestamp; + pubSignals[1 + ISS_FIELDS + 2] = uint256(proof.timestamp); + // maskedCommand[commandFieldLength]; + stringFields = _packBytes2Fields( + bytes(proof.maskedCommand), + COMMAND_BYTES + ); + for (uint256 i = 0; i < COMMAND_FIELDS; i++) { + pubSignals[1 + ISS_FIELDS + 3 + i] = stringFields[i]; + } + // accountSalt; + pubSignals[1 + ISS_FIELDS + 3 + COMMAND_FIELDS] = uint256( + proof.accountSalt + ); + // azp + stringFields = _packBytes2Fields( + bytes(parts[2]), + AZP_BYTES + ); + for (uint256 i = 0; i < AZP_FIELDS; i++) { + pubSignals[1 + ISS_FIELDS + 3 + COMMAND_FIELDS + 1 + i] = stringFields[i]; + } + // isCodeExist; + pubSignals[1 + ISS_FIELDS + 3 + COMMAND_FIELDS + 1 + AZP_FIELDS] = proof.isCodeExist + ? 1 + : 0; + + return groth16Verifier.verifyProof(pA, pB, pC, pubSignals); + } + + function _packBytes2Fields( + bytes memory _bytes, + uint256 _paddedSize + ) public pure returns (uint256[] memory) { + uint256 remain = _paddedSize % 31; + uint256 numFields = (_paddedSize - remain) / 31; + if (remain > 0) { + numFields += 1; + } + uint256[] memory fields = new uint[](numFields); + uint256 idx = 0; + uint256 byteVal = 0; + for (uint256 i = 0; i < numFields; i++) { + for (uint256 j = 0; j < 31; j++) { + idx = i * 31 + j; + if (idx >= _paddedSize) { + break; + } + if (idx >= _bytes.length) { + byteVal = 0; + } else { + byteVal = uint256(uint8(_bytes[idx])); + } + if (j == 0) { + fields[i] = byteVal; + } else { + fields[i] += (byteVal << (8 * j)); + } + } + } + return fields; + } + + /// @notice Upgrade the implementation of the proxy. + /// @param newImplementation Address of the new implementation. + function _authorizeUpgrade( + address newImplementation + ) internal override onlyOwner {} + + function getCommandBytes() external pure returns (uint256) { + return COMMAND_BYTES; + } + + function stringToArray(string memory _strings) external pure returns (string[] memory) { + strings.slice memory slicee = _strings.toSlice(); + strings.slice memory delim = "|".toSlice(); + string[] memory parts = new string[](slicee.count(delim) + 1); + for (uint i = 0; i < parts.length; i++) { + parts[i] = slicee.split(delim).toString(); + } + require(parts.length == 3, "Invalid kid|iss|azp strings"); + return parts; + } + + function stringToBytes32(string memory source) public pure returns (bytes32 result) { + return bytes32(abi.encodePacked(source)); + } +} diff --git a/packages/contracts/test/JwtRegistry/JwtRegistryBase.t.sol b/packages/contracts/test/JwtRegistry/JwtRegistryBase.t.sol new file mode 100644 index 0000000..b210d7e --- /dev/null +++ b/packages/contracts/test/JwtRegistry/JwtRegistryBase.t.sol @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.12; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; +import {JwtRegistry} from "../../src/utils/JwtRegistry.sol"; +import {JwtRegistryTestBase} from "./JwtRegistryBase.t.sol"; + +contract JwtRegistryTestBase is Test { + bytes32 publicKeyHash = + 0x0ea9c777dc7110e5a9e89b13f0cfc540e3845ba120b2b6dc24024d61488d4788; + string kidIssAzpString = "12345|https://example.com|client-id-12345"; + JwtRegistry jwtRegistry; + + address deployer = vm.addr(1); + + constructor() {} + + function setUp() public virtual { + // Create jwt dkim registry + jwtRegistry = new JwtRegistry(deployer); + jwtRegistry.setDKIMPublicKeyHash(kidIssAzpString, publicKeyHash); + } +} diff --git a/packages/contracts/test/JwtRegistry/JwtRegistry_isDKIMPublicKeyHashValid.t.sol b/packages/contracts/test/JwtRegistry/JwtRegistry_isDKIMPublicKeyHashValid.t.sol new file mode 100644 index 0000000..d832036 --- /dev/null +++ b/packages/contracts/test/JwtRegistry/JwtRegistry_isDKIMPublicKeyHashValid.t.sol @@ -0,0 +1,55 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.12; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; +// import {EmailAuth, EmailAuthMsg} from "../../../src/EmailAuth.sol"; +// import {RecoveryController} from "../../helpers/RecoveryController.sol"; +// import {StructHelper} from "../../helpers/StructHelper.sol"; +// import {SimpleWallet} from "../../helpers/SimpleWallet.sol"; +// import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {JwtRegistryTestBase} from "./JwtRegistryBase.t.sol"; + +contract JwtRegistryTest_isDKIMPublicKeyHashValid is JwtRegistryTestBase { + constructor() {} + + function setUp() public override { + super.setUp(); + } + + function testFail_isDKIMPublicKeyHashValid_invalidKid() public { + string memory domainName = "54321|https://example.com|client-id-12345"; + bool res = jwtRegistry.isDKIMPublicKeyHashValid( + domainName, + publicKeyHash + ); + assertEq(res, true); + } + + function testFail_isDKIMPublicKeyHashValid_invalidIss() public { + string memory domainName = "12345|https://example.xyz|client-id-12345"; + bool res = jwtRegistry.isDKIMPublicKeyHashValid( + domainName, + publicKeyHash + ); + assertEq(res, true); + } + + function testFail_isDKIMPublicKeyHashValid_invalidAzp() public { + string memory domainName = "12345|https://example.com|client-id-54321"; + bool res = jwtRegistry.isDKIMPublicKeyHashValid( + domainName, + publicKeyHash + ); + assertEq(res, true); + } + + function test_isDKIMPublicKeyHashValid() public { + string memory domainName = "12345|https://example.com|client-id-12345"; + bool res = jwtRegistry.isDKIMPublicKeyHashValid( + domainName, + publicKeyHash + ); + assertEq(res, true); + } +} diff --git a/packages/contracts/test/JwtRegistry/JwtRegistry_revokeDKIMPublicKeyHash.t.sol b/packages/contracts/test/JwtRegistry/JwtRegistry_revokeDKIMPublicKeyHash.t.sol new file mode 100644 index 0000000..8e3f74e --- /dev/null +++ b/packages/contracts/test/JwtRegistry/JwtRegistry_revokeDKIMPublicKeyHash.t.sol @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.12; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; +// import {EmailAuth, EmailAuthMsg} from "../../../src/EmailAuth.sol"; +// import {RecoveryController} from "../../helpers/RecoveryController.sol"; +// import {StructHelper} from "../../helpers/StructHelper.sol"; +// import {SimpleWallet} from "../../helpers/SimpleWallet.sol"; +// import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "@zk-email/contracts/DKIMRegistry.sol"; +import {JwtRegistryTestBase} from "./JwtRegistryBase.t.sol"; + +contract JwtRegistryTest_revokeDKIMPublicKeyHash is JwtRegistryTestBase { + constructor() {} + + function setUp() public override { + super.setUp(); + } + + function testRevert_revokeDKIMPublicKeyHash_invalidDomainName() public { + string memory domainName = ""; + vm.expectRevert(bytes("Invalid domain name")); + jwtRegistry.revokeDKIMPublicKeyHash(domainName, publicKeyHash); + } + + function testRevert_revokeDKIMPublicKeyHash_invalidPublicKeyHash() public { + string memory domainName = "12345|https://example.com|client-id-12345"; + vm.expectRevert(bytes("Invalid public key hash")); + jwtRegistry.revokeDKIMPublicKeyHash(domainName, bytes32(0)); + } + + function testRevert_revokeDKIMPublicKeyHash_publicKeyHashIsNotSet() public { + string memory domainName = "54321|https://example.com|client-id-12345"; + vm.expectRevert(bytes("publicKeyHash is not set")); + jwtRegistry.revokeDKIMPublicKeyHash(domainName, publicKeyHash); + } + + function test_revokeDKIMPublicKeyHash() public { + string memory domainName = "12345|https://example.com|client-id-12345"; + jwtRegistry.revokeDKIMPublicKeyHash(domainName, publicKeyHash); + assertEq(jwtRegistry.whitelistedClients("client-id-12345"), false); + } +} diff --git a/packages/contracts/test/JwtRegistry/JwtRegistry_setDKIMPublicKeyHash.t.sol b/packages/contracts/test/JwtRegistry/JwtRegistry_setDKIMPublicKeyHash.t.sol new file mode 100644 index 0000000..5926219 --- /dev/null +++ b/packages/contracts/test/JwtRegistry/JwtRegistry_setDKIMPublicKeyHash.t.sol @@ -0,0 +1,41 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.12; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; +// import {EmailAuth, EmailAuthMsg} from "../../../src/EmailAuth.sol"; +// import {RecoveryController} from "../../helpers/RecoveryController.sol"; +// import {StructHelper} from "../../helpers/StructHelper.sol"; +// import {SimpleWallet} from "../../helpers/SimpleWallet.sol"; +// import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import "@zk-email/contracts/DKIMRegistry.sol"; +import {JwtRegistryTestBase} from "./JwtRegistryBase.t.sol"; + +contract JwtRegistryTest_setDKIMPublicKeyHash is JwtRegistryTestBase { + constructor() {} + + function setUp() public override { + super.setUp(); + } + + function testRevert_setDKIMPublicKeyHash_publicKeyHashIsAlreadySet() + public + { + string memory domainName = "12345|https://example.com|client-id-12345"; + vm.expectRevert(bytes("publicKeyHash is already set")); + jwtRegistry.setDKIMPublicKeyHash(domainName, publicKeyHash); + } + + function testRevert_setDKIMPublicKeyHash_publicKeyHashIsRevoked() public { + string memory domainName = "12345|https://example.com|client-id-12345"; + jwtRegistry.revokeDKIMPublicKeyHash(domainName, publicKeyHash); + vm.expectRevert(bytes("publicKeyHash is revoked")); + jwtRegistry.setDKIMPublicKeyHash(domainName, publicKeyHash); + } + + function test_setDKIMPublicKeyHash() public { + string memory domainName = "12345|https://example.xyz|client-id-12345"; + jwtRegistry.setDKIMPublicKeyHash(domainName, publicKeyHash); + assertEq(jwtRegistry.whitelistedClients("client-id-12345"), true); + } +} diff --git a/packages/contracts/test/JwtRegistry/JwtRegistry_stringToArray.t.sol b/packages/contracts/test/JwtRegistry/JwtRegistry_stringToArray.t.sol new file mode 100644 index 0000000..ea94d22 --- /dev/null +++ b/packages/contracts/test/JwtRegistry/JwtRegistry_stringToArray.t.sol @@ -0,0 +1,26 @@ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.12; + +import "forge-std/Test.sol"; +import "forge-std/console.sol"; +// import {EmailAuth, EmailAuthMsg} from "../../../src/EmailAuth.sol"; +// import {RecoveryController} from "../../helpers/RecoveryController.sol"; +// import {StructHelper} from "../../helpers/StructHelper.sol"; +// import {SimpleWallet} from "../../helpers/SimpleWallet.sol"; +import {OwnableUpgradeable} from "@openzeppelin/contracts-upgradeable/access/OwnableUpgradeable.sol"; +import {JwtRegistryTestBase} from "./JwtRegistryBase.t.sol"; + +contract JwtRegistryTest_stringToArray is JwtRegistryTestBase { + constructor() {} + + function setUp() public override { + super.setUp(); + } + + function test_stringToArray() public { + string[] memory points = jwtRegistry.stringToArray("12345|https://example.com|client-id-12345"); + assertEq(points[0], "12345"); + assertEq(points[1], "https://example.com"); + assertEq(points[2], "client-id-12345"); + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 003e7d5..067ba24 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2375,6 +2375,22 @@ __metadata: languageName: node linkType: hard +"@openzeppelin/contracts-upgradeable@npm:^5.0.0": + version: 5.0.2 + resolution: "@openzeppelin/contracts-upgradeable@npm:5.0.2" + peerDependencies: + "@openzeppelin/contracts": 5.0.2 + checksum: 7d1dbd6bcb45fb6fccf2dc51253afd044b9f77b01d34e11f7cf4c3e17c860df31ddc2c831be7ac463e2955eaea9620cec1c38cdffed7fcf235eb1fdc7ceb3716 + languageName: node + linkType: hard + +"@openzeppelin/contracts@npm:^5.0.0": + version: 5.0.2 + resolution: "@openzeppelin/contracts@npm:5.0.2" + checksum: 0cce6fc284bd1d89e2a447027832a62f1356b44ee31088899453e10349a63a62df2f07da63d76e4c41aad9c86b96b650b2b6fc85439ef276850dda1170a047fd + languageName: node + linkType: hard + "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -2414,6 +2430,15 @@ __metadata: languageName: node linkType: hard +"@solidity-parser/parser@npm:^0.16.0": + version: 0.16.2 + resolution: "@solidity-parser/parser@npm:0.16.2" + dependencies: + antlr4ts: ^0.5.0-alpha.4 + checksum: 109f7bec5de943c63e444fdde179d9bba6a592c18c836f585753798f428424cfcca72c715e7a345e4b79b83d6548543c9e56cb4b263e9b1e8352af2efcfd224a + languageName: node + linkType: hard + "@solidity-parser/parser@npm:^0.18.0": version: 0.18.0 resolution: "@solidity-parser/parser@npm:0.18.0" @@ -2784,6 +2809,16 @@ __metadata: languageName: node linkType: hard +"@zk-email/contracts@npm:^6.1.5": + version: 6.1.5 + resolution: "@zk-email/contracts@npm:6.1.5" + dependencies: + "@openzeppelin/contracts": ^5.0.0 + dotenv: ^16.3.1 + checksum: db0d361f59d4b7a46f832999d9d8b4eec2918f7adc22a87f689220e6db2c9cb861b9ec686e32e9d2271a0c8f63d116326c0309804e7a433eeba2e62c04a1003e + languageName: node + linkType: hard + "@zk-email/ether-email-auth-circom@npm:^0.0.2-preview": version: 0.0.2-preview resolution: "@zk-email/ether-email-auth-circom@npm:0.0.2-preview" @@ -2902,6 +2937,21 @@ __metadata: languageName: unknown linkType: soft +"@zk-jwt/zk-jwt-contracts@workspace:packages/contracts": + version: 0.0.0-use.local + resolution: "@zk-jwt/zk-jwt-contracts@workspace:packages/contracts" + dependencies: + "@openzeppelin/contracts": ^5.0.0 + "@openzeppelin/contracts-upgradeable": ^5.0.0 + "@zk-email/contracts": ^6.1.5 + ds-test: "https://github.com/dapphub/ds-test" + forge-std: "https://github.com/foundry-rs/forge-std" + solady: ^0.0.123 + solhint: ^3.6.1 + solidity-stringutils: "github:LayerZero-Labs/solidity-stringutils" + languageName: unknown + linkType: soft + "@zk-jwt/zk-jwt@workspace:.": version: 0.0.0-use.local resolution: "@zk-jwt/zk-jwt@workspace:." @@ -3012,7 +3062,7 @@ __metadata: languageName: node linkType: hard -"ajv@npm:^6.12.4": +"ajv@npm:^6.12.4, ajv@npm:^6.12.6": version: 6.12.6 resolution: "ajv@npm:6.12.6" dependencies: @@ -3024,6 +3074,18 @@ __metadata: languageName: node linkType: hard +"ajv@npm:^8.0.1": + version: 8.17.1 + resolution: "ajv@npm:8.17.1" + dependencies: + fast-deep-equal: ^3.1.3 + fast-uri: ^3.0.1 + json-schema-traverse: ^1.0.0 + require-from-string: ^2.0.2 + checksum: 1797bf242cfffbaf3b870d13565bd1716b73f214bb7ada9a497063aada210200da36e3ed40237285f3255acc4feeae91b1fb183625331bad27da95973f7253d9 + languageName: node + linkType: hard + "ansi-colors@npm:^4.1.3": version: 4.1.3 resolution: "ansi-colors@npm:4.1.3" @@ -3086,6 +3148,22 @@ __metadata: languageName: node linkType: hard +"antlr4@npm:^4.11.0": + version: 4.13.2 + resolution: "antlr4@npm:4.13.2" + checksum: 3e42659f9b84af84c21f194e625d220bd958278a5481800bb4f5929149c603fad4d492f8b6d04f7c2ab87dd3df88e63ba097fbe7bfa92a060942da713d783e0a + languageName: node + linkType: hard + +"antlr4ts@npm:^0.5.0-alpha.4": + version: 0.5.0-dev + resolution: "antlr4ts@npm:0.5.0-dev" + dependencies: + source-map-support: ^0.5.16 + checksum: 640dae2229124372b0329315e9614ae983bb80b1af237d8c0b3e90a2d85fb534e851c51d65d1897c92b36d27851d041ad8d95aab44af19cf7355b3ad11a3ddbf + languageName: node + linkType: hard + "anymatch@npm:^3.0.3, anymatch@npm:~3.1.2": version: 3.1.3 resolution: "anymatch@npm:3.1.3" @@ -3230,6 +3308,20 @@ __metadata: languageName: node linkType: hard +"ast-parents@npm:^0.0.1": + version: 0.0.1 + resolution: "ast-parents@npm:0.0.1" + checksum: 51360afb9f7b939eb0330fdd0d5d855d0242f273f63478d30d9053069120492173719fb3c03ba372bccf1a7c1a9041c3c6bf2ab700de8c0f8c14792b045c3b23 + languageName: node + linkType: hard + +"astral-regex@npm:^2.0.0": + version: 2.0.0 + resolution: "astral-regex@npm:2.0.0" + checksum: 876231688c66400473ba505731df37ea436e574dd524520294cc3bbc54ea40334865e01fa0d074d74d036ee874ee7e62f486ea38bc421ee8e6a871c06f011766 + languageName: node + linkType: hard + "async@npm:^3.2.3": version: 3.2.6 resolution: "async@npm:3.2.6" @@ -3708,7 +3800,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1": +"chalk@npm:^4.0.0, chalk@npm:^4.0.2, chalk@npm:^4.1.0, chalk@npm:^4.1.1, chalk@npm:^4.1.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: @@ -3975,6 +4067,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^10.0.0": + version: 10.0.1 + resolution: "commander@npm:10.0.1" + checksum: 436901d64a818295803c1996cd856621a74f30b9f9e28a588e726b2b1670665bccd7c1a77007ebf328729f0139838a88a19265858a0fa7a8728c4656796db948 + languageName: node + linkType: hard + "commander@npm:^11.0.0": version: 11.1.0 resolution: "commander@npm:11.1.0" @@ -4033,6 +4132,23 @@ __metadata: languageName: node linkType: hard +"cosmiconfig@npm:^8.0.0": + version: 8.3.6 + resolution: "cosmiconfig@npm:8.3.6" + dependencies: + import-fresh: ^3.3.0 + js-yaml: ^4.1.0 + parse-json: ^5.2.0 + path-type: ^4.0.0 + peerDependencies: + typescript: ">=4.9.5" + peerDependenciesMeta: + typescript: + optional: true + checksum: dc339ebea427898c9e03bf01b56ba7afbac07fc7d2a2d5a15d6e9c14de98275a9565da949375aee1809591c152c0a3877bb86dbeaf74d5bd5aaa79955ad9e7a0 + languageName: node + linkType: hard + "create-jest@npm:^29.7.0": version: 29.7.0 resolution: "create-jest@npm:29.7.0" @@ -4286,6 +4402,20 @@ __metadata: languageName: node linkType: hard +"dotenv@npm:^16.3.1": + version: 16.4.5 + resolution: "dotenv@npm:16.4.5" + checksum: 301a12c3d44fd49888b74eb9ccf9f07a1f5df43f489e7fcb89647a2edcd84c42d6bc349dc8df099cd18f07c35c7b04685c1a4f3e6a6a9e6b30f8d48c15b7f49c + languageName: node + linkType: hard + +"ds-test@https://github.com/dapphub/ds-test": + version: 1.0.0 + resolution: "ds-test@https://github.com/dapphub/ds-test.git#commit=e282159d5170298eb2455a6c05280ab5a73a4ef0" + checksum: 8f36e20dde868d062841c790fc43c9dd18b93d6180995f378bedaee1f24444950838843c0f2ffa5ac3b8a21b4c29fd97a60725e29e8ff71c9cf28f837614d96f + languageName: node + linkType: hard + "eastasianwidth@npm:^0.2.0": version: 0.2.0 resolution: "eastasianwidth@npm:0.2.0" @@ -4913,6 +5043,13 @@ __metadata: languageName: node linkType: hard +"fast-diff@npm:^1.2.0": + version: 1.3.0 + resolution: "fast-diff@npm:1.3.0" + checksum: d22d371b994fdc8cce9ff510d7b8dc4da70ac327bcba20df607dd5b9cae9f908f4d1028f5fe467650f058d1e7270235ae0b8230809a262b4df587a3b3aa216c3 + languageName: node + linkType: hard + "fast-glob@npm:^3.2.9": version: 3.3.2 resolution: "fast-glob@npm:3.3.2" @@ -4940,6 +5077,13 @@ __metadata: languageName: node linkType: hard +"fast-uri@npm:^3.0.1": + version: 3.0.2 + resolution: "fast-uri@npm:3.0.2" + checksum: ca00aadc84e0ab93a8a1700c386bc7cbeb49f47d9801083c258444eed31221fdf864d68fb48ea8acd7c512bf046b53c09e3aafd6d4bdb9449ed21be29d8d6f75 + languageName: node + linkType: hard + "fastfile@npm:0.0.20": version: 0.0.20 resolution: "fastfile@npm:0.0.20" @@ -5117,6 +5261,13 @@ __metadata: languageName: node linkType: hard +"forge-std@https://github.com/foundry-rs/forge-std": + version: 1.9.3 + resolution: "forge-std@https://github.com/foundry-rs/forge-std.git#commit=ab6de56ed94bed75866c78c62cad882e8a046348" + checksum: 0be072a746d5cab4bf651cf13c36e24a87fe2aba1f9070edbbd7e795ebda0eb5ff87e044c7aa552a20a324f604d3428db01030bd69bcefcb4d81c4619a6d85cc + languageName: node + linkType: hard + "form-data@npm:^4.0.0": version: 4.0.0 resolution: "form-data@npm:4.0.0" @@ -5331,7 +5482,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^8.1.0": +"glob@npm:^8.0.3, glob@npm:^8.1.0": version: 8.1.0 resolution: "glob@npm:8.1.0" dependencies: @@ -5623,7 +5774,7 @@ __metadata: languageName: node linkType: hard -"ignore@npm:^5.2.0, ignore@npm:^5.3.1": +"ignore@npm:^5.2.0, ignore@npm:^5.2.4, ignore@npm:^5.3.1": version: 5.3.2 resolution: "ignore@npm:5.3.2" checksum: 2acfd32a573260ea522ea0bfeff880af426d68f6831f973129e2ba7363f422923cf53aab62f8369cbf4667c7b25b6f8a3761b34ecdb284ea18e87a5262a865be @@ -5637,7 +5788,7 @@ __metadata: languageName: node linkType: hard -"import-fresh@npm:^3.2.1": +"import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" dependencies: @@ -6638,6 +6789,13 @@ __metadata: languageName: node linkType: hard +"json-schema-traverse@npm:^1.0.0": + version: 1.0.0 + resolution: "json-schema-traverse@npm:1.0.0" + checksum: 02f2f466cdb0362558b2f1fd5e15cce82ef55d60cd7f8fa828cf35ba74330f8d767fcae5c5c2adb7851fa811766c694b9405810879bc4e1ddd78a7c0e03658ad + languageName: node + linkType: hard + "json-stable-stringify-without-jsonify@npm:^1.0.1": version: 1.0.1 resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" @@ -6897,6 +7055,13 @@ __metadata: languageName: node linkType: hard +"lodash.truncate@npm:^4.4.2": + version: 4.4.2 + resolution: "lodash.truncate@npm:4.4.2" + checksum: b463d8a382cfb5f0e71c504dcb6f807a7bd379ff1ea216669aa42c52fc28c54e404bfbd96791aa09e6df0de2c1d7b8f1b7f4b1a61f324d38fe98bc535aeee4f5 + languageName: node + linkType: hard + "lodash@npm:^4.17.21, lodash@npm:^4.17.4": version: 4.17.21 resolution: "lodash@npm:4.17.21" @@ -7820,6 +7985,13 @@ __metadata: languageName: node linkType: hard +"pluralize@npm:^8.0.0": + version: 8.0.0 + resolution: "pluralize@npm:8.0.0" + checksum: 08931d4a6a4a5561a7f94f67a31c17e6632cb21e459ab3ff4f6f629d9a822984cf8afef2311d2005fbea5d7ef26016ebb090db008e2d8bce39d0a9a9d218736e + languageName: node + linkType: hard + "possible-typed-array-names@npm:^1.0.0": version: 1.0.0 resolution: "possible-typed-array-names@npm:1.0.0" @@ -7853,6 +8025,15 @@ __metadata: languageName: node linkType: hard +"prettier@npm:^2.8.3": + version: 2.8.8 + resolution: "prettier@npm:2.8.8" + bin: + prettier: bin-prettier.js + checksum: b49e409431bf129dd89238d64299ba80717b57ff5a6d1c1a8b1a28b590d998a34e083fa13573bc732bb8d2305becb4c9a4407f8486c81fa7d55100eb08263cf8 + languageName: node + linkType: hard + "prettier@npm:^3.0.0": version: 3.3.3 resolution: "prettier@npm:3.3.3" @@ -8081,6 +8262,13 @@ __metadata: languageName: node linkType: hard +"require-from-string@npm:^2.0.2": + version: 2.0.2 + resolution: "require-from-string@npm:2.0.2" + checksum: a03ef6895445f33a4015300c426699bc66b2b044ba7b670aa238610381b56d3f07c686251740d575e22f4c87531ba662d06937508f0f3c0f1ddc04db3130560b + languageName: node + linkType: hard + "resolve-cwd@npm:^3.0.0": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0" @@ -8259,7 +8447,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3": +"semver@npm:^7.3.5, semver@npm:^7.5.2, semver@npm:^7.5.3, semver@npm:^7.5.4, semver@npm:^7.6.0, semver@npm:^7.6.3": version: 7.6.3 resolution: "semver@npm:7.6.3" bin: @@ -8389,6 +8577,17 @@ __metadata: languageName: node linkType: hard +"slice-ansi@npm:^4.0.0": + version: 4.0.0 + resolution: "slice-ansi@npm:4.0.0" + dependencies: + ansi-styles: ^4.0.0 + astral-regex: ^2.0.0 + is-fullwidth-code-point: ^3.0.0 + checksum: 4a82d7f085b0e1b070e004941ada3c40d3818563ac44766cca4ceadd2080427d337554f9f99a13aaeb3b4a94d9964d9466c807b3d7b7541d1ec37ee32d308756 + languageName: node + linkType: hard + "smart-buffer@npm:^4.2.0": version: 4.2.0 resolution: "smart-buffer@npm:4.2.0" @@ -8478,6 +8677,51 @@ __metadata: languageName: node linkType: hard +"solady@npm:^0.0.123": + version: 0.0.123 + resolution: "solady@npm:0.0.123" + checksum: c058d1c235b2d54b608ca9129e24664bdc699a6693c3f972495cbdeeb2f7b0ca513bef2a685da59ac051d7adc61e35d8f9c44ed276516ace000b17a8c2295207 + languageName: node + linkType: hard + +"solhint@npm:^3.6.1": + version: 3.6.2 + resolution: "solhint@npm:3.6.2" + dependencies: + "@solidity-parser/parser": ^0.16.0 + ajv: ^6.12.6 + antlr4: ^4.11.0 + ast-parents: ^0.0.1 + chalk: ^4.1.2 + commander: ^10.0.0 + cosmiconfig: ^8.0.0 + fast-diff: ^1.2.0 + glob: ^8.0.3 + ignore: ^5.2.4 + js-yaml: ^4.1.0 + lodash: ^4.17.21 + pluralize: ^8.0.0 + prettier: ^2.8.3 + semver: ^7.5.2 + strip-ansi: ^6.0.1 + table: ^6.8.1 + text-table: ^0.2.0 + dependenciesMeta: + prettier: + optional: true + bin: + solhint: solhint.js + checksum: 96c2ab3c1444624facb45b929682c65d83019f392c7331463a45e8ed61f08122e24b6709a721b6086ddfb0d5e3c3d4281f175f74eb308415072917556bdeba22 + languageName: node + linkType: hard + +"solidity-stringutils@github:LayerZero-Labs/solidity-stringutils": + version: 0.0.1 + resolution: "solidity-stringutils@https://github.com/LayerZero-Labs/solidity-stringutils.git#commit=eb21d6b502c2741145ab2a90f5f5b4fda9dfb218" + checksum: 0d87834c90aaf904d8b6f9705992a3e544a9fe6e5ebe86f80ab8ca3ee6b3ffd03dfffa85a982de4a34d3d0e7590e3bdd90bc6618167af1b523b41193686777ab + languageName: node + linkType: hard + "source-map-support@npm:0.5.13": version: 0.5.13 resolution: "source-map-support@npm:0.5.13" @@ -8488,6 +8732,16 @@ __metadata: languageName: node linkType: hard +"source-map-support@npm:^0.5.16": + version: 0.5.21 + resolution: "source-map-support@npm:0.5.21" + dependencies: + buffer-from: ^1.0.0 + source-map: ^0.6.0 + checksum: 43e98d700d79af1d36f859bdb7318e601dfc918c7ba2e98456118ebc4c4872b327773e5a1df09b0524e9e5063bb18f0934538eace60cca2710d1fa687645d137 + languageName: node + linkType: hard + "source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" @@ -8714,6 +8968,19 @@ __metadata: languageName: node linkType: hard +"table@npm:^6.8.1": + version: 6.8.2 + resolution: "table@npm:6.8.2" + dependencies: + ajv: ^8.0.1 + lodash.truncate: ^4.4.2 + slice-ansi: ^4.0.0 + string-width: ^4.2.3 + strip-ansi: ^6.0.1 + checksum: 61188652f53a980d1759ca460ca8dea5c5322aece3210457e7084882f053c2b6a870041295e08a82cb1d676e31b056406845d94b0abf3c79a4b104777bec413b + languageName: node + linkType: hard + "tar@npm:^6.1.11, tar@npm:^6.2.1": version: 6.2.1 resolution: "tar@npm:6.2.1"