From ca3b5775388d77e611a3d674c099d4a2c9c71d5c Mon Sep 17 00:00:00 2001 From: motemotech Date: Wed, 15 Nov 2023 16:21:08 +0900 Subject: [PATCH] fix input size and corresponding files --- .../circom-circuit/src/merkleInclusion.circom | 0 .../circom-circuit/src/verify-gov-sig.circom | 6 +- packages/contracts/src/base/ZKMynaWallet.sol | 10 +- .../src/base/ZKMynaWalletFactory.sol | 1 - .../src/circom-verifier/govSigVerifier.sol | 8 +- packages/script/js/der_to_decimalArray.js | 9 +- packages/script/js/extract_tbs_certificate.js | 4 +- packages/script/js/generateProof.js | 26 +++ packages/script/js/pem_to_der.js | 8 +- packages/script/ts/verify_tbs_cert.ts | 188 +++++++++++++++++- 10 files changed, 239 insertions(+), 21 deletions(-) delete mode 100644 packages/circom-circuit/src/merkleInclusion.circom create mode 100644 packages/script/js/generateProof.js diff --git a/packages/circom-circuit/src/merkleInclusion.circom b/packages/circom-circuit/src/merkleInclusion.circom deleted file mode 100644 index e69de29..0000000 diff --git a/packages/circom-circuit/src/verify-gov-sig.circom b/packages/circom-circuit/src/verify-gov-sig.circom index b22c193..37ad575 100644 --- a/packages/circom-circuit/src/verify-gov-sig.circom +++ b/packages/circom-circuit/src/verify-gov-sig.circom @@ -23,7 +23,7 @@ template CalculateHash(k) { } template VerifyInclusion() { - signal input tbsCert[1586]; + signal input tbsCert[1600]; signal input modulus[17]; component num2Bits0[256]; @@ -65,7 +65,7 @@ template VerifyInclusion() { } template HashTbs() { - signal input tbsCert[1586]; + signal input tbsCert[1600]; signal output hashedTbsInNum[3]; component num2Bits[1306]; @@ -113,7 +113,7 @@ template MynaVerifyGovSig(n, k) { signal input modulus[k]; // rsa public key, verified with smart contract. split up into k parts of n bits each. signal input govModulus[k]; signal input govSignature[k]; - signal input tbsCert[1586]; + signal input tbsCert[1600]; var messageLength = (256 + n) \ n; diff --git a/packages/contracts/src/base/ZKMynaWallet.sol b/packages/contracts/src/base/ZKMynaWallet.sol index d72da24..fd488c1 100644 --- a/packages/contracts/src/base/ZKMynaWallet.sol +++ b/packages/contracts/src/base/ZKMynaWallet.sol @@ -144,19 +144,19 @@ contract ZKMynaWallet is // TODO: Check modulus preimage function validateGovSignature(bytes32[43] memory proof) public - returns (uint256 validationData) + onlySelf() { (uint256[2] memory _pA, uint256[2][2] memory _pB, uint256[2] memory _pC, uint256[SIGNALS_NUM_FOR_GOV_SIG] memory _pubSignals) = _splitToGovSigProof(proof); try govSigVerifier.verifyProof(_pA, _pB, _pC, _pubSignals) returns (bool valid) { - if (!valid) { - return 1; - } else { + if (valid) { _setVerified(); + } else { + revert(); } } catch { - return 1; + revert(); } } diff --git a/packages/contracts/src/base/ZKMynaWalletFactory.sol b/packages/contracts/src/base/ZKMynaWalletFactory.sol index 79df5b5..dd8fbd4 100644 --- a/packages/contracts/src/base/ZKMynaWalletFactory.sol +++ b/packages/contracts/src/base/ZKMynaWalletFactory.sol @@ -6,7 +6,6 @@ import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; import "@account-abstraction/contracts/interfaces/IEntryPoint.sol"; import {ZKMynaWallet} from "./ZKMynaWallet.sol"; import { IMynaGovSigVerifier, IMynaUserSigVerifier } from "@interfaces/IMynaWalletVerifier.sol"; - /** * Factory contract for MynaWallet. */ diff --git a/packages/contracts/src/circom-verifier/govSigVerifier.sol b/packages/contracts/src/circom-verifier/govSigVerifier.sol index 93e3e56..8d9f1ad 100644 --- a/packages/contracts/src/circom-verifier/govSigVerifier.sol +++ b/packages/contracts/src/circom-verifier/govSigVerifier.sol @@ -37,10 +37,10 @@ contract MynaGovSigVerifier { uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; - uint256 constant deltax1 = 18745487737772393836870720416445145076891177703175978585765325077723843873761; - uint256 constant deltax2 = 20915598045433281500794185594698103226112783390757459836770054758722353399857; - uint256 constant deltay1 = 16970825186035861852878242799632852954890426875552238417608877466851853966539; - uint256 constant deltay2 = 2430216772480925566948196712639305250098054570199333681223406250639853344691; + uint256 constant deltax1 = 13852857032342530930605263284505234428798439870600148209788340828000245353516; + uint256 constant deltax2 = 8599542926507262441875995612307797602874511416313171215604391079363790013704; + uint256 constant deltay1 = 4041894675951619254150017120139787509960291060047231188967935357150647832908; + uint256 constant deltay2 = 2375183444257265201186845007594212213218041674327526084247182307321215296492; uint256 constant IC0x = 7441607095611835814370721145253227673217654661770423448604533840761042303372; diff --git a/packages/script/js/der_to_decimalArray.js b/packages/script/js/der_to_decimalArray.js index 4bf55bf..3c9f4f7 100644 --- a/packages/script/js/der_to_decimalArray.js +++ b/packages/script/js/der_to_decimalArray.js @@ -29,8 +29,9 @@ while (outputLen < 1600) { outputArray.push(0); outputLen = outputArray.length; } +console.log(outputArray); -const data = JSON.stringify(outputArray); -fs.writeFile(OUTPUT_PATH, data, (err) => { - if (err) throw err; -}); \ No newline at end of file +// const data = JSON.stringify(outputArray); +// fs.writeFile(OUTPUT_PATH, data, (err) => { +// if (err) throw err; +// }); \ No newline at end of file diff --git a/packages/script/js/extract_tbs_certificate.js b/packages/script/js/extract_tbs_certificate.js index 23378d7..3d5ca5e 100644 --- a/packages/script/js/extract_tbs_certificate.js +++ b/packages/script/js/extract_tbs_certificate.js @@ -6,6 +6,7 @@ const PATH = join(__dirname, '../../certs/myna_cert.pem') // Read the PEM file const pem = readFileSync(PATH, 'utf8') +console.log(typeof(pem)); // Remove the '-----BEGIN CERTIFICATE-----' and '-----END CERTIFICATE-----' lines const base64String = pem @@ -14,6 +15,7 @@ const base64String = pem .replace(/\n/g, '') const der = Buffer.from(base64String, 'base64') +console.log(typeof(der)); // certificate consists of // - tbsCertificate 人によって長さが違う @@ -25,4 +27,4 @@ const newSize = der.length - cutSize // 先頭4バイトは SEQUENCE の長さ const tbsCertificate = der.slice(4, newSize) -console.log(tbsCertificate.toString('hex')) +// console.log(tbsCertificate.toString('hex')) diff --git a/packages/script/js/generateProof.js b/packages/script/js/generateProof.js new file mode 100644 index 0000000..f89871b --- /dev/null +++ b/packages/script/js/generateProof.js @@ -0,0 +1,26 @@ +const fs = require('fs'); +const { join } = require('path'); +const snarkjs = require('snarkjs'); + +const INPUT_PATH = join(__dirname, '../../circom-circuit/gov-sig-setup/input.json'); +const input = JSON.parse(fs.readFileSync(INPUT_PATH, 'utf8')); +const WASM_PATH = join(__dirname, "../../circom-circuit/gov-sig-build/verify-gov-sig_js/verify-gov-sig.wasm"); +const ZKEY_PATH = join(__dirname, "../../circom-circuit/gov-sig-setup/circuit_final.zkey"); + +async function main() { + const { proof, publicSignals } = await snarkjs.groth16.fullProve( + input, + WASM_PATH, + ZKEY_PATH); + console.log("publicSignals", publicSignals); + console.log("proof", proof); + + console.log("generating calldata"); + + const calldataBlob = await snarkjs.groth16.exportSolidityCallData(proof, publicSignals); + const calldata = calldataBlob.split(','); + + console.log(calldata); + +} +main().catch(console.error); \ No newline at end of file diff --git a/packages/script/js/pem_to_der.js b/packages/script/js/pem_to_der.js index 62fd95c..18e614b 100644 --- a/packages/script/js/pem_to_der.js +++ b/packages/script/js/pem_to_der.js @@ -15,9 +15,13 @@ const base64String = pem .replace(/\n/g, '') const der = Buffer.from(base64String, 'base64') - +console.log(der); +const input = "3082062e30820516a003020102020406bfc341300d06092a864886f70d01010b0500308182310b3009060355040613024a50310d300b060355040a0c044a504b4931253023060355040b0c1c4a504b4920666f7220757365722061757468656e7469636174696f6e313d303b060355040b0c344a6170616e204167656e637920666f72204c6f63616c20417574686f7269747920496e666f726d6174696f6e2053797374656d73301e170d3233303531393136333730395a170d3237313230373134353935395a302f310b3009060355040613024a503120301e06035504030c173431323539344537354a41434a4d31343130343030334130820122300d06092a864886f70d01010105000382010f003082010a0282010100a817baf8fa4e6e760868d1dbc56ee50099d22a67ad98328713f9fdf2055d9b73fc6cd9a6c0eb9ca24ff7c0e34ad268bf8b7eab96f270017f32739813d007c52c976322bc320049b3e68b9a1953dc915a75a2e85d7efa2005d4f2f3cc3abca234f11ae4edd8fe7d7f60f3ca31aaf4ddc520e1e3c925ee91fd08118316b4bb9b910cec74f878a4e3502c2b0d894064ea5c9b795c440cd3ee7de1daa10b319ef560a96828a1fa4c1c17f32391f334ec6817b953abae86258efbeae2b5b28bce63ac08a48072dcf635693fb4af7e7fc07ad3a2b78172304c18dab9f3d206581c4849b8d8f11d6db5efd42e2c8964719ea6966342ae43e6ff101b994ae845ae47cf1b0203010001a38202fc308202f8300e0603551d0f0101ff04040302078030130603551d25040c300a06082b0601050507030230490603551d200101ff043f303d303b060b2a83088c9b55080501031e302c302a06082b06010505070201161e687474703a2f2f7777772e6a706b692e676f2e6a702f6370732e68746d6c3081b70603551d120481af3081aca481a93081a6310b3009060355040613024a5031273025060355040a0c1ee585ace79a84e5808be4babae8aa8de8a8bce382b5e383bce38393e382b931393037060355040b0c30e585ace79a84e5808be4babae8aa8de8a8bce382b5e383bce38393e382b9e588a9e794a8e88085e8a8bce6988ee794a831333031060355040b0c2ae59cb0e696b9e585ace585b1e59ba3e4bd93e68385e5a0b1e382b7e382b9e38386e383a0e6a99fe6a78b3081bb0603551d1f0481b33081b03081ada081aaa081a7a481a43081a1310b3009060355040613024a50310d300b060355040a0c044a504b4931253023060355040b0c1c4a504b4920666f7220757365722061757468656e7469636174696f6e3120301e060355040b0c1743524c20446973747269627574696f6e20506f696e747331153013060355040b0c0c4b616e61676177612d6b656e3123302106035504030c1a596f6b6f68616d612d7368692d4e616b612d6b752043524c4450303a06082b06010505070101042e302c302a06082b06010505073001861e687474703a2f2f6f637370617574686e6f726d2e6a706b692e676f2e6a703081b20603551d230481aa3081a780148cd5586a891485e559379b7e29d410cfd28b3593a18188a48185308182310b3009060355040613024a50310d300b060355040a0c044a504b4931253023060355040b0c1c4a504b4920666f7220757365722061757468656e7469636174696f6e313d303b060355040b0c344a6170616e204167656e637920666f72204c6f63616c20417574686f7269747920496e666f726d6174696f6e2053797374656d7382040133c349301d0603551d0e04160414ca786123cdc58798c182fdde3eca05e2b18215a5300d06092a864886f70d01010b0500038201010046b35d93f0486d132aff57d64ff92c7952074b1f26bb5dc0ba0377cd3f2d37febc16b226a4659234ef69ca9818cbbeb465dde154948ac478460bda12a3c7a0e37ace1a5d82c082af0f186234c80df4ff326625f44ab8fc4669e7a698d878d26f538615b9b2ccbb846a7a9110a6028c4de9c49889e54e4084d9faa0ba79b5a97e82602b55c6bcc2afbcd77a9fcff7945a51204b76be6b77139a2e96fef85f0b0e376cd5ea4dead88a10623e1bb8eabce29834dde2ae842b0a3039976cbbfba6d78217439a8e840bb4f8a776c5b46e8c103d818a229fc570b200212e0aceed5d0e18ccc100430101005dbc6febe7b78009ab426cbe17d68402a8ab7c8baaec1ef8"; +const hello = Buffer.from(input); +console.log(hello); +console.log(typeof(hello)) // The modulus -console.log(`0x${der.toString('hex')}`); +// console.log(`0x${der.toString('hex')}`); fs.writeFile(OUTPUT_PATH, der.toString('hex'), (err) => { if (err) throw err; }); \ No newline at end of file diff --git a/packages/script/ts/verify_tbs_cert.ts b/packages/script/ts/verify_tbs_cert.ts index e54a74f..cc926a8 100644 --- a/packages/script/ts/verify_tbs_cert.ts +++ b/packages/script/ts/verify_tbs_cert.ts @@ -160,4 +160,190 @@ async function main() { main().catch(err => { console.error(err) process.exit(1) -}) \ No newline at end of file +}) + +// Helper functions +function createInitCode(identityCommitment: Hex, salt: bigint): Hex { + const initCode = concat([ + FACTORY_ADDRESS, + encodeFunctionData({ + abi: factoryABI, + functionName: 'createAccount', + args: [identityCommitment, salt] + }) + ]) + return initCode +} + +async function getAddress(initCode: Hex): Promise<[Address, boolean]> { + const senderAddress = await getSenderAddress(publicClient, { + initCode, + entryPoint: ENTRY_POINT_ADDRESS + }) + const code = await publicClient.getBytecode({ address: senderAddress }) + return [senderAddress, code === undefined] +} + +async function getUserOperationGasPrice(): Promise { + const userOperationGasPrice = await pimlicoBundlerClient.getUserOperationGasPrice() + return userOperationGasPrice +} + +async function getNonce(senderAddress: Address) { + const account = getContract({ + address: senderAddress, + abi: walletABI, + publicClient + }) + const nonce = await account.read.getNonce() + return nonce +} + +function generateDummyZKPSignature(): Hex { + return '0x198705050f6c5ec7ce8d0e3beacd67f2143019213cd285db697cb26ce1aff66716c8f21aa09f9dbada9c17d9ec83dd59e484f12c50689a2df48ef41adc9cde6c0e6da20c7b38c80c3f3cc16f8585cca37ddd80d909adcc32a0ae9a524afe195012083fe96e774eedf83bed1d379c40580426c381250d997e7e9dc9222f5e05d504df90947b055418cb10bf5a37eccdb804797dfc9ad53df220bbde205e7ad98006f65c9ff03b25169869a2f65e98f169eb4859c33cbb3f2e86da11572a21d2891f61fa72e55a56acee6cc98bb28be2274ee93e9d0be4d89a4af39ab37e60123b262fcfceeb87403f870fcec0900de2a1c2908b592ec1c98255fe2ecd2fbbf2bf1efdb9c5013a9706e0c16627c36de8dd60731bd96d5bf705bf3db1801267790a00000000000000000000000000000000014a92b6297dc8b5ffb107949f196baf00000000000000000000000000000000009e1187340bc4fd07167462a34b64310000000000000000000000000000000000ed7428f4493d8d819efa6bf71d77c90000000000000000000000000000000000b5d4ef1307ccccefcd331654707e7000000000000000000000000000000000016e2d82bcf9fc45163273840ea8832200000000000000000000000000000000003fb7da2955b7e1c2877da6184af1c800000000000000000000000000000000013876f6867269b091706adf9e6b1ec000000000000000000000000000000000015822b6a7a18159d530974b18a1bb530000000000000000000000000000000001a29c85d823645c5994c167b83090590000000000000000000000000000000001d43619afdf3f353529fdfa1b4f2152000000000000000000000000000000000189975eed5aa142beae1260bf663efd0000000000000000000000000000000001732fd6983070ea2046900a7c3adb430000000000000000000000000000000001564393bb317edbb1cb57cbfa8049ba0000000000000000000000000000000000ac9e95037ab029dae9f9cea8d81c97000000000000000000000000000000000186b47a64af8ea1b79a07d9a97b846b00000000000000000000000000000000007a42797379374010d310f32536bd9f000000000000000000000000000000000000458b290364b9b0bd1d68984c1896000000000000000000000000000000000154b3e7d909e2e281d716c1269b212d0000000000000000000000000000000000482dd4f9954d79b2b46c1e38767ef6000000000000000000000000000000000000000000000000000000000000375c' +} + +async function sponsorUserOperation( + userOperation: PartialBy +): Promise { + // 有効期限終了(0 で指定することで validAfter 以後有効となる) + const validUntil = 0 + // 有効期限開始 + const validAfter = Math.ceil(Date.now() / 1000) + // exchangeRate (現状利用しないため 0 ) + const exchangeRate = 0n + + // generate paymasterAndData with dummy signature + let paymasterAndData = concat([ + PAYMASTER_ADDRESS, + encodeAbiParameters( + [ + { name: 'validUntil', type: 'uint48' }, + { name: 'validAfter', type: 'uint48' }, + { name: 'address', type: 'address' }, + { name: 'exchangeRate', type: 'uint256' } + ], + [validUntil, validAfter, '0x0000000000000000000000000000000000000000', exchangeRate] + ), + // dummy signature + await paymasterAccount.signMessage({ message: '0xdeadbeef' }) + ]) + + // assign dummy paymasterAndData + userOperation.paymasterAndData = paymasterAndData + + const estimatedGas = await pimlicoBundlerClient.estimateUserOperationGas({ + userOperation, + entryPoint: ENTRY_POINT_ADDRESS + }) + + // assign estimated gas + // estimated gas で返される値が信頼できない場合がある + userOperation.callGasLimit = estimatedGas.callGasLimit + userOperation.preVerificationGas = estimatedGas.preVerificationGas + // 4倍しておく + userOperation.verificationGasLimit = + estimatedGas.verificationGasLimit * 4n < 500000n ? 500000n : estimatedGas.verificationGasLimit * 4n + + // calculate paymaster hash + const hash = (await publicClient.readContract({ + address: PAYMASTER_ADDRESS, + abi: paymasterABI, + functionName: 'getHash', + args: [userOperation, validUntil, validAfter, '0x0000000000000000000000000000000000000000', exchangeRate] + })) as Hex + + const signature = await paymasterAccount.signMessage({ + message: { raw: hash } + }) + + // sign paymaster hash + userOperation.paymasterAndData = concat([ + PAYMASTER_ADDRESS, + encodeAbiParameters( + [ + { name: 'validUntil', type: 'uint48' }, + { name: 'validAfter', type: 'uint48' }, + { name: 'address', type: 'address' }, + { name: 'exchangeRate', type: 'uint256' } + ], + [validUntil, validAfter, '0x0000000000000000000000000000000000000000', 0n] + ), + signature + ]) + + return userOperation as UserOperation +} + +function getTestRsaKey() { + return new NodeRSA(`-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEAj2BHBk9AD9L/gK1lacLP/COAeeLLGGSDBaWbnx84lzD5v5te +PkNviAZcBiQccYm6Q7atvl7HqXnUtC8qRQzRnoB15agXsEMooNFuv8trwJqWAgIX +r2IY83ZdvBKRMe3QBEcqtFkIvwLsNbfAROHJAPffF5/BnJSDWALljEMrxzzuVBSK +byTXMWzKGVeRyH4H6FsH+Atx3cFbmwU+bwJlqOgcJ8dUbeo4y7lRynHDhIkrgd8S +yMsERPngTSTQ0zI/qFcHW+JnRvS3MaGGpRzsJBUVl7nTHJ73jbg/J+8Nlz1NKi2K +kJPHEYv4YyJgOhfXgUoF9hUJY7cqJ19kWgmTGQIDAQABAoIBAHSqkyC/PBGkT+QV +NIBq1XMGMHT95uViZHsj1w4UCah9YbxYYMepeAfnpNoaaEq7F6Yh8B8IYM+3Iy27 +c1ncpHWlckn+DciP3W9+++91R6jiIU5hBYTg/gyeNIflU+Cc8reIcWdvS36ikjLj +4sAqObVf/Vjr1k/jST1EniUUQ3tLCKaaePcuHPJ3fcthrKX3doZ9ym2PNn+XYecz +QE6QR5txEowPN7MVyExaP8TaYZdRQGSE0cMruxdbCebhSKgw7PtrIOjq6LPhDzDy +gUG9kLI/lI4FlDkJYC4hOdezycZ+T13KLHYsGnw+dsC4PAqk4w/JVaqgut4jtUU6 +pe8XNQECgYEA807085nVLkV6cEJOHRxVtS5oblw8ZI27deg2mQpBBEaD8/H7IpR2 +R1nyNj5UV6Ba8UhBGG+9CLjMrm9yuefydPZN6ki+yxK0d1aF20OjllFKEolKJzG7 +ZyE+xulCU9cKHajvTJWra9tKvyheNd+ct1Ae5G47DB9pmzKX/uFJclUCgYEAltrd +OrufmMoNnc0N8uha4SM68s3+pz2tGbQ954Qqux3Co+JgQwsVL0OuUT198BG2wSYB +kTySLU3bKHx68Z8p4HMXVzLheJI3eob+2yJ/UIZKjoz3dO4MsFb2KseiWXYeV7Gp +uUE47KVGlfC6gNM32m2iKB361i1YJDo2oxn7ybUCgYEA3toz/Cerng0fP1FL8Nfy +HNhb6LFs04EJ8c32rCg7MupPlBHQv3SR/XqCInLml7gVdCiFDxfRYfq55w/HWkX7 +ymuLJArrTl9ckm3afuGuJVFhcibzl4CysJw/vrsJ+HbfGhmQzWnNMCYUiZA08k1V +YoXtNbdNOCZReUhW9apttl0CgYBxiHiVWl2r1O1YhNnppZu38xbLY+MypMVhIfix +BBRQzP4O7zF5Y57m+m338GqWwg4j4WGul8J/3CeDmePBcwNGS/gWBVIRtyGP0od+ +DsF4rgjwrgES/JGKKXiNC8AQykfdwfU1WnPoDh9Ie2sxx0Uy2+39eUqt5GSAp1s1 +dzm7PQKBgQDTWs2NKZuB4b6o0CEHte+SoINfHvVFDWbotJAZ//l+z1SmTlH7qb+/ +jsDhmF/uizOdlopee6fdDaIzYNxEOseI2dx3UjLk6QYqtPBCu9KJ1juSeCReMSjH +BWhALtiQk07pmfH+zFEYEwBhZ0OKaUAZuabat21qFr0cuX1VN8jtBQ== +-----END RSA PRIVATE KEY-----`) +} + +function bigint_to_array(n: number, k: number, x: bigint) { + let mod = 1n + for (let idx = 0; idx < n; idx++) { + mod = mod * 2n + } + + const ret: bigint[] = [] + let x_temp: bigint = x + for (let idx = 0; idx < k; idx++) { + ret.push(x_temp % mod) + x_temp = x_temp / mod + } + return ret +} + +async function verifyZKProof(callData: string): Promise { + const argv = callData + .replace(/["[\]\s]/g, '') + .split(',') + .map(x => BigInt(x).toString()) + + const a = [argv[0], argv[1]] + const b = [ + [argv[2], argv[3]], + [argv[4], argv[5]] + ] + const c = [argv[6], argv[7]] + const publicInputs = argv.slice(8) + + try { + const res = await publicClient.readContract({ + address: VERIFIER_ADDRESS, + abi: verifierABI, + functionName: 'verifyProof', + args: [a, b, c, publicInputs] + }) + return res as boolean + } catch (e) { + console.log(e) + return false + } +}