diff --git a/circuits/test/disclose.test.ts b/circuits/test/disclose.test.ts index b8d0e64ee..5741dd8ca 100644 --- a/circuits/test/disclose.test.ts +++ b/circuits/test/disclose.test.ts @@ -61,7 +61,7 @@ describe("start testing register.circom", function () { console.log("commitment", commitment); tree = new IMT(poseidon2, COMMITMENT_TREE_DEPTH, 0, 2); - tree.insert(commitment); + tree.insert(BigInt(commitment)); inputs = generateCircuitInputsDisclose( secret, @@ -71,7 +71,8 @@ describe("start testing register.circom", function () { majority, bitmap, scope, - user_identifier + user_identifier, + 16 ); console.log(JSON.stringify(inputs, null, 2)); @@ -95,7 +96,7 @@ describe("start testing register.circom", function () { try { const invalidInputs = { ...inputs, - current_date: ["4","4","0","5","1","0"] // 2044 + current_date: ["4", "4", "0", "5", "1", "0"] // 2044 } await circuit.calculateWitness(invalidInputs); expect.fail("Expected an error but none was thrown."); @@ -174,7 +175,7 @@ describe("start testing register.circom", function () { ...inputs, bitmap: bitmap.map(String), }); - + const revealedData_packed = await circuit.getOutput(w, ["revealedData_packed[3]"]) const reveal_unpacked = unpackReveal(revealedData_packed); @@ -194,7 +195,7 @@ describe("start testing register.circom", function () { majority: ["5", "0"].map(char => BigInt(char.charCodeAt(0)).toString()), bitmap: bitmap.map(String), }); - + const revealedData_packed = await circuit.getOutput(w, ["revealedData_packed[3]"]) const reveal_unpacked = unpackReveal(revealedData_packed); diff --git a/common/src/utils/generateInputs.ts b/common/src/utils/generateInputs.ts index a1e4e510d..205df4d1e 100644 --- a/common/src/utils/generateInputs.ts +++ b/common/src/utils/generateInputs.ts @@ -106,7 +106,8 @@ export function generateCircuitInputsDisclose( majority: string[], bitmap: string[], scope: string, - user_identifier: string + user_identifier: string, + nLevels: number ) { const pubkey_leaf = getLeaf({ signatureAlgorithm: passportData.signatureAlgorithm, @@ -124,15 +125,23 @@ export function generateCircuitInputsDisclose( mrz_bytes[1], mrz_bytes[2] ]).toString(); - console.log("commitment", commitment); + // console.log("commitment", commitment); const index = merkletree.indexOf(BigInt(commitment)); - console.log(`Index of commitment in the tree: ${index}`); + // console.log(`Index of commitment in the tree: ${index}`); if (index === -1) { throw new Error("This commitment was not found in the tree"); } const proof = merkletree.createProof(index); - console.log("verifyProof", merkletree.verifyProof(proof)); + // console.log("verifyProof", merkletree.verifyProof(proof)); + const real_path = proof.pathIndices.map(index => index.toString()); + while (real_path.length < nLevels) { + real_path.push("0"); + } + const real_siblings = proof.siblings.flat().map(index => index.toString()); + while (real_siblings.length < nLevels) { + real_siblings.push("0"); + } return { secret: secret, @@ -141,8 +150,8 @@ export function generateCircuitInputsDisclose( mrz: formattedMrz.map(byte => String(byte)), merkle_root: [merkletree.root.toString()], merkletree_size: BigInt(proof.pathIndices.length).toString(), - path: proof.pathIndices.map(index => index.toString()), - siblings: proof.siblings.flat().map(index => index.toString()), + path: real_path, + siblings: real_siblings, bitmap: bitmap, scope: scope, current_date: getCurrentDateYYMMDD().map(datePart => BigInt(datePart).toString()), diff --git a/contracts/contracts/Register.sol b/contracts/contracts/Register.sol index d1d4bb409..cf9111236 100644 --- a/contracts/contracts/Register.sol +++ b/contracts/contracts/Register.sol @@ -1,45 +1,47 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.3; -//import {Groth16Verifier} from "./Verifier.sol"; import {IRegister} from "./interfaces/IRegister.sol"; import {Registry} from "./Registry.sol"; import {Base64} from "./libraries/Base64.sol"; import {IVerifier} from "./IVerifier.sol"; - +import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol"; import "@openzeppelin/contracts/utils/Strings.sol"; import "@zk-kit/imt.sol/internal/InternalLeanIMT.sol"; -contract Register is IRegister { +contract Register is IRegister, Ownable { Registry public immutable registry; using Base64 for *; using Strings for uint256; - //LeanIMT for commitments using InternalLeanIMT for LeanIMTData; LeanIMTData internal imt; + mapping(uint256 => bool) public nullifiers; mapping(uint256 => bool) public merkleRootsCreated; - mapping(uint256 => address) public verifiers; constructor(Registry r) { registry = r; + transferOwnership(msg.sender); } function validateProof(RegisterProof calldata proof) external override { - if (!registry.checkRoot(bytes32(proof.merkle_root))) { revert Register__InvalidMerkleRoot(); } if (nullifiers[proof.nullifier]) { revert Register__YouAreUsingTheSameNullifierTwice(); } + if (verifiers[proof.signature_algorithm] == address(0)) { + revert Register__InvalidSignatureAlgorithm(); + } if (!verifyProof(proof)) { revert Register__InvalidProof(); } nullifiers[proof.nullifier] = true; + _addCommitment(proof.commitment); emit ProofValidated( @@ -49,30 +51,35 @@ contract Register is IRegister { ); } - function verifyProof(RegisterProof calldata proof) public view override returns (bool) { - return IVerifier(verifiers[proof.signature_algorithm]).verifyProof( - proof.a, - proof.b, - proof.c, - [uint(proof.commitment),uint(proof.nullifier), uint(proof.merkle_root),uint(proof.signature_algorithm)] - ); + function verifyProof( + RegisterProof calldata proof + ) public view override returns (bool) { + return + IVerifier(verifiers[proof.signature_algorithm]).verifyProof( + proof.a, + proof.b, + proof.c, + [ + uint(proof.commitment), + uint(proof.nullifier), + uint(proof.merkle_root), + uint(proof.signature_algorithm) + ] + ); } function _addCommitment(uint256 commitment) internal { uint256 index = getMerkleTreeSize(); uint256 imt_root = imt._insert(commitment); merkleRootsCreated[imt_root] = true; - require(indexOf(commitment) == index, "Register__CommitmentNotInIMT"); emit AddCommitment(index, commitment, imt_root); - } function checkRoot(uint256 root) external view returns (bool) { return merkleRootsCreated[root]; } - function getMerkleTreeSize( - ) public view returns (uint256) { + function getMerkleTreeSize() public view returns (uint256) { return imt.size; } @@ -84,15 +91,23 @@ contract Register is IRegister { return imt._indexOf(commitment); } + function addSignatureAlgorithm( + uint256 signature_algorithm, + address verifier_address + ) external onlyOwner { + require( + verifier_address != address(0), + "Register__InvalidVerifierAddress" + ); + require( + verifiers[signature_algorithm] == address(0), + "Register__SignatureAlgorithmAlreadySet" + ); + verifiers[signature_algorithm] = verifier_address; + } + /*** DEV FUNCTIONS ***/ function dev_add_commitment(uint256 commitment) external { _addCommitment(commitment); } - - function dev_set_signature_algorithm(uint256 signature_algorithm, address verifier_address) external { - verifiers[signature_algorithm] = verifier_address; - } - - } - diff --git a/contracts/contracts/SBT.sol b/contracts/contracts/SBT.sol index 297ba7db5..97251626c 100644 --- a/contracts/contracts/SBT.sol +++ b/contracts/contracts/SBT.sol @@ -8,8 +8,8 @@ import {Verifier_disclose} from "./Verifier_disclose.sol"; import {Base64} from "./libraries/Base64.sol"; import {Formatter} from "./Formatter.sol"; import {Registry} from "./Registry.sol"; -import "hardhat/console.sol"; import {IRegister} from "./interfaces/IRegister.sol"; +import "hardhat/console.sol"; contract SBT is ERC721Enumerable, Ownable { using Strings for uint256; @@ -19,21 +19,21 @@ contract SBT is ERC721Enumerable, Ownable { Formatter public formatter; IRegister public register; - uint constant scope = 0; + uint constant scope = 5; mapping(uint256 => bool) public nullifiers; struct SBTProof { uint nullifier; uint[3] revealedData_packed; + uint attestation_id; uint merkle_root; uint scope; - uint user_identifier; uint[6] current_date; - uint attestation_id; - uint256[2] a; - uint256[2][2] b; - uint256[2] c; + uint user_identifier; + uint[2] a; + uint[2][2] b; + uint[2] c; } struct AttributePosition { @@ -76,42 +76,64 @@ contract SBT is ERC721Enumerable, Ownable { attributePositions.push(AttributePosition("older_than", 88, 89, 7)); } - function mint( - SBTProof calldata proof - ) public { - require(verifier.verifyProof(proof.a, proof.b, proof.c, [proof.nullifier, proof.revealedData_packed[0], proof.revealedData_packed[1], proof.revealedData_packed[2], proof.merkle_root, proof.scope, proof.user_identifier, proof.current_date[0], proof.current_date[1], proof.current_date[2], proof.current_date[3], proof.current_date[4], proof.current_date[5], proof.attestation_id]), "Invalid Proof"); - - // check that the nullifier has not been used before - // require(!nullifiers[inputs[3]], "Signature already nullified"); - - // require(registry.checkRoot(bytes32(proof.merkle_root)), "Invalid merkle root"); - require(register.checkRoot(proof.merkle_root), "Invalid merkle root"); + function mint(SBTProof calldata proof) public { + require( + register.checkRoot(uint(proof.merkle_root)), + "Invalid merkle root" + ); require(!nullifiers[proof.nullifier], "Signature already nullified"); - nullifiers[proof.nullifier] = true; // require that the current date is valid // Convert the last four parameters into a valid timestamp, adding 30 years to adjust for block.timestamp starting in 1970 uint[6] memory dateNum; for (uint i = 0; i < 6; i++) { - dateNum[i] = proof.revealedData_packed[6 + i]; + dateNum[i] = proof.current_date[i]; } uint currentTimestamp = getCurrentTimestamp(dateNum); // Check that the current date is within a +/- 1 day range require( - currentTimestamp >= block.timestamp - 1 days && currentTimestamp <= block.timestamp + 1 days, + currentTimestamp >= block.timestamp - 1 days && + currentTimestamp <= block.timestamp + 1 days, "Current date is not within the valid range" ); + require( + verifier.verifyProof( + proof.a, + proof.b, + proof.c, + [ + uint(proof.nullifier), + uint(proof.revealedData_packed[0]), + uint(proof.revealedData_packed[1]), + uint(proof.revealedData_packed[2]), + uint(proof.attestation_id), + uint(proof.merkle_root), + uint(proof.scope), + uint(proof.current_date[0]), + uint(proof.current_date[1]), + uint(proof.current_date[2]), + uint(proof.current_date[3]), + uint(proof.current_date[4]), + uint(proof.current_date[5]), + uint(proof.user_identifier) + ] + ), + "Invalid Proof" + ); + + nullifiers[proof.nullifier] = true; // Effects: Mint token address addr = address(uint160(proof.user_identifier)); uint256 newTokenId = totalSupply(); _mint(addr, newTokenId); - nullifiers[proof.nullifier] = true; // Set attributes - bytes memory charcodes = fieldElementsToBytes(proof.revealedData_packed); + bytes memory charcodes = fieldElementsToBytes( + proof.revealedData_packed + ); // console.logBytes1(charcodes[21]); Attributes storage attributes = tokenAttributes[newTokenId]; @@ -126,7 +148,7 @@ contract SBT is ERC721Enumerable, Ownable { } string memory attributeValue = string(attributeBytes); attributes.values[i] = attributeValue; - console.log(attribute.name, attributes.values[i]); + // console.log(attribute.name, attributes.values[i]); } } @@ -177,9 +199,7 @@ contract SBT is ERC721Enumerable, Ownable { if (isAttributeEmpty(date)) { return false; // this is disregarded anyway in the next steps } - uint256 expiryDate = formatter.dateToUnixTimestamp( - date - ); + uint256 expiryDate = formatter.dateToUnixTimestamp(date); return block.timestamp > expiryDate; } @@ -228,16 +248,22 @@ contract SBT is ERC721Enumerable, Ownable { return tokenAttributes[_tokenId].values[7]; } - function getCurrentTimestamp(uint256[6] memory dateNum) public view returns (uint256) { + function getCurrentTimestamp( + uint256[6] memory dateNum + ) public view returns (uint256) { string memory date = ""; for (uint i = 0; i < 6; i++) { - date = string(abi.encodePacked(date, bytes1(uint8(48 + dateNum[i] % 10)))); + date = string( + abi.encodePacked(date, bytes1(uint8(48 + (dateNum[i] % 10)))) + ); } uint256 currentTimestamp = formatter.dateToUnixTimestamp(date); return currentTimestamp; } - function isAttributeEmpty(string memory attribute) private pure returns (bool) { + function isAttributeEmpty( + string memory attribute + ) private pure returns (bool) { for (uint i = 0; i < bytes(attribute).length; i++) { if (bytes(attribute)[i] != 0) { return false; @@ -246,22 +272,41 @@ contract SBT is ERC721Enumerable, Ownable { return true; } - function appendAttribute(bytes memory baseURI, string memory traitType, string memory value) private view returns (bytes memory) { + function appendAttribute( + bytes memory baseURI, + string memory traitType, + string memory value + ) private view returns (bytes memory) { if (!isAttributeEmpty(value)) { - baseURI = abi.encodePacked(baseURI, - '{"trait_type": "', traitType, '", "value": "', formatAttribute(traitType, value), '"},'); + baseURI = abi.encodePacked( + baseURI, + '{"trait_type": "', + traitType, + '", "value": "', + formatAttribute(traitType, value), + '"},' + ); } return baseURI; } - function formatAttribute(string memory traitType, string memory value) private view returns (string memory) { - if (isStringEqual(traitType, "Issuing State") || isStringEqual(traitType, "Nationality")) { + function formatAttribute( + string memory traitType, + string memory value + ) private view returns (string memory) { + if ( + isStringEqual(traitType, "Issuing State") || + isStringEqual(traitType, "Nationality") + ) { return formatter.formatCountryName(value); } else if (isStringEqual(traitType, "First Name")) { return formatter.formatName(value)[0]; } else if (isStringEqual(traitType, "Last Name")) { return formatter.formatName(value)[1]; - } else if (isStringEqual(traitType, "Date of birth") || isStringEqual(traitType, "Expiry date")) { + } else if ( + isStringEqual(traitType, "Date of birth") || + isStringEqual(traitType, "Expiry date") + ) { return formatter.formatDate(value); } else if (isStringEqual(traitType, "Older Than")) { return formatter.formatAge(value); @@ -272,20 +317,29 @@ contract SBT is ERC721Enumerable, Ownable { } } - function isStringEqual(string memory a, string memory b) public pure returns (bool) { + function isStringEqual( + string memory a, + string memory b + ) public pure returns (bool) { return keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b)); } - function substring(bytes memory str, uint startIndex, uint endIndex) public pure returns (bytes memory) { + function substring( + bytes memory str, + uint startIndex, + uint endIndex + ) public pure returns (bytes memory) { bytes memory strBytes = bytes(str); - bytes memory result = new bytes(endIndex-startIndex); - for(uint i = startIndex; i < endIndex; i++) { - result[i-startIndex] = strBytes[i]; + bytes memory result = new bytes(endIndex - startIndex); + for (uint i = startIndex; i < endIndex; i++) { + result[i - startIndex] = strBytes[i]; } return result; } - function tokenURI(uint256 _tokenId) public view override virtual returns (string memory) { + function tokenURI( + uint256 _tokenId + ) public view virtual override returns (string memory) { require( _exists(_tokenId), "ERC721Metadata: URI query for nonexistent token" @@ -294,19 +348,34 @@ contract SBT is ERC721Enumerable, Ownable { bytes memory baseURI = abi.encodePacked('{ "attributes": ['); - baseURI = appendAttribute(baseURI, "Issuing State", attributes.values[0]); + baseURI = appendAttribute( + baseURI, + "Issuing State", + attributes.values[0] + ); baseURI = appendAttribute(baseURI, "First Name", attributes.values[1]); baseURI = appendAttribute(baseURI, "Last Name", attributes.values[1]); - baseURI = appendAttribute(baseURI, "Passport Number", attributes.values[2]); + baseURI = appendAttribute( + baseURI, + "Passport Number", + attributes.values[2] + ); baseURI = appendAttribute(baseURI, "Nationality", attributes.values[3]); - baseURI = appendAttribute(baseURI, "Date of birth", attributes.values[4]); + baseURI = appendAttribute( + baseURI, + "Date of birth", + attributes.values[4] + ); baseURI = appendAttribute(baseURI, "Gender", attributes.values[5]); baseURI = appendAttribute(baseURI, "Expiry date", attributes.values[6]); baseURI = appendAttribute(baseURI, "Expired", attributes.values[6]); baseURI = appendAttribute(baseURI, "Older Than", attributes.values[7]); // Remove the trailing comma if baseURI has one - if (keccak256(abi.encodePacked(baseURI[baseURI.length - 1])) == keccak256(abi.encodePacked(','))) { + if ( + keccak256(abi.encodePacked(baseURI[baseURI.length - 1])) == + keccak256(abi.encodePacked(",")) + ) { baseURI = substring(baseURI, 0, bytes(baseURI).length - 1); } @@ -317,8 +386,12 @@ contract SBT is ERC721Enumerable, Ownable { '"}' ); - console.log(string(baseURI)); - - return string(abi.encodePacked("data:application/json;base64,", baseURI.encode())); + return + string( + abi.encodePacked( + "data:application/json;base64,", + baseURI.encode() + ) + ); } -} \ No newline at end of file +} diff --git a/contracts/contracts/Verifier.sol b/contracts/contracts/Verifier.sol deleted file mode 100644 index d13000e12..000000000 --- a/contracts/contracts/Verifier.sol +++ /dev/null @@ -1,191 +0,0 @@ -// 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 Groth16Verifier { - // 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 = 13718730262782944445181266816991478953330240478907880032762976644004368769095; - uint256 constant deltax2 = 7647651767722145750577189591717487950066620799757713802411559019371908183121; - uint256 constant deltay1 = 18010692145584587833144505345217015081328719391252797096374613328440473671203; - uint256 constant deltay2 = 13706681280646876136066673893856043326817428414046853828230867042603723549797; - - - uint256 constant IC0x = 2394933690274366268096991608149586771617971086637005980462219572107262376870; - uint256 constant IC0y = 20927027790259021399853252662654342078146798621788037849745258289666464636902; - - uint256 constant IC1x = 13876425163898693107635206634047444862664971380881780412439850273749661285967; - uint256 constant IC1y = 16777623889483121666624233379167123051090322578350587265904738964473689452703; - - uint256 constant IC2x = 5310688978221496060716496531464778504908883772123742197171973900066799783599; - uint256 constant IC2y = 17477652341271748409633673187342334217694853293766246040511432220721862839133; - - uint256 constant IC3x = 12762959695051053667359449806462934775904437068030106478730216400079759114404; - uint256 constant IC3y = 17098717629853905758017539864954036959564007100593843727379115113743695258998; - - uint256 constant IC4x = 13907753377762343563458660256001554781898388463873283253157116097107044008641; - uint256 constant IC4y = 12279848778142745019550123108319735218426905843417883245775305911902342481257; - - - // 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[4] calldata _pubSignals) public view returns (bool) { - assembly { - function checkField(v) { - if iszero(lt(v, q)) { - 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))) - - - // -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))) - - - // Validate all evaluations - let isValid := checkPairing(_pA, _pB, _pC, _pubSignals, pMem) - - mstore(0, isValid) - return(0, 0x20) - } - } - } diff --git a/contracts/contracts/Verifier_disclose.sol b/contracts/contracts/Verifier_disclose.sol index 9f6ec39fa..79bb4e8fc 100644 --- a/contracts/contracts/Verifier_disclose.sol +++ b/contracts/contracts/Verifier_disclose.sol @@ -37,10 +37,10 @@ contract Verifier_disclose { uint256 constant gammax2 = 10857046999023057135944570762232829481370756359578518086990519993285655852781; uint256 constant gammay1 = 4082367875863433681332203403145435568316851327593401208105741076214120093531; uint256 constant gammay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930; - uint256 constant deltax1 = 17964203062267680425566181660583943541947637208481475959958688928902147589334; - uint256 constant deltax2 = 4703880879057787472855911001112496635639625571400074136649492770399795331947; - uint256 constant deltay1 = 18236489850664721604774313999328441456662938819601658036904523287591827971893; - uint256 constant deltay2 = 1397258805162284232295605934313837281002081042886280729365558015643384589640; + uint256 constant deltax1 = 18352668350498946013376142639233190562055816821900458734963566785232162598770; + uint256 constant deltax2 = 18367680594141902451570057929008119216850205222638102873749275572896697474632; + uint256 constant deltay1 = 3872383130886637195026806064825755587038483267154360579879830513473307466380; + uint256 constant deltay2 = 1117064237318091261592711511028247477806046085012038802574915788004948015381; uint256 constant IC0x = 17431667882859443712107549401676812172237535348159352869485689705981327335962; diff --git a/contracts/contracts/interfaces/IRegister.sol b/contracts/contracts/interfaces/IRegister.sol index bc266f240..614e9f583 100644 --- a/contracts/contracts/interfaces/IRegister.sol +++ b/contracts/contracts/interfaces/IRegister.sol @@ -10,21 +10,19 @@ interface IRegister { error Register__YouAreUsingTheSameNullifierTwice(); /// @notice Error thrown when the proof provided is invalid error Register__InvalidProof(); + /// @notice Error thrown when the signature algorithm provided is invalid + error Register__InvalidSignatureAlgorithm(); + /// @notice Error thrown when the verifier address is invalid + error Register__InvalidVerifierAddress(); + /// @notice Error thrown when the signature algorithm is already set + error Register__SignatureAlgorithmAlreadySet(); /// @notice Event emitted when a proof is successfully validated /// @param merkle_root The Merkle root used in the proof /// @param nullifier The nullifier used in the proof /// @param commitment The commitment used in the proof - event ProofValidated( - uint merkle_root, - uint nullifier, - uint commitment - ); - event AddCommitment( - uint index, - uint commitment, - uint merkle_root - ); + event ProofValidated(uint merkle_root, uint nullifier, uint commitment); + event AddCommitment(uint index, uint commitment, uint merkle_root); /// @notice Struct to hold data for Register proofs /// @param merkle_root The Merkle root used in the proof @@ -50,8 +48,9 @@ interface IRegister { /// @notice Verifies a Register proof /// @param proof The Register proof to verify /// @return bool Returns true if the proof is valid, false otherwise - function verifyProof(RegisterProof calldata proof) external view returns (bool); - + function verifyProof( + RegisterProof calldata proof + ) external view returns (bool); /// @notice Checks if a given root is valid /// @param root The root to check @@ -62,8 +61,12 @@ interface IRegister { /// @return uint Returns the size of the Merkle tree function getMerkleTreeSize() external view returns (uint); + /// @notice Retrieves the current Merkle root of the tree + /// @return uint256 Returns the current Merkle root + function getMerkleRoot() external view returns (uint); + /// @notice Finds the index of a given commitment in the Merkle tree /// @param commitment The commitment to find /// @return uint Returns the index of the commitment function indexOf(uint commitment) external view returns (uint); -} \ No newline at end of file +} diff --git a/contracts/test/RegisterAndDisclose.ts b/contracts/test/RegisterAndDisclose.ts index e1d854f43..c9bfd64bc 100644 --- a/contracts/test/RegisterAndDisclose.ts +++ b/contracts/test/RegisterAndDisclose.ts @@ -13,12 +13,13 @@ import fs from 'fs'; import { IMT } from "@zk-kit/imt"; import { poseidon2 } from "poseidon-lite"; import { PassportData } from "../../common/src/utils/types"; +import { Signer } from "ethers"; describe("Proof of Passport - Contracts - Register & Disclose flow", function () { this.timeout(0); - let passportData: PassportData, proof, inputs: any, publicSignals, revealChars, pasrsedCallData: any[], formattedCallData: any; + let passportData: PassportData, proof, inputs: any, publicSignals, revealChars, parsedCallData_register: any[], formattedCallData_register: any; // Paths const path_register_wasm = "../circuits/build/register_sha256WithRSAEncryption_65537_js/register_sha256WithRSAEncryption_65537.wasm"; const path_register_zkey = "../circuits/build/register_sha256WithRSAEncryption_65537_final.zkey"; @@ -29,11 +30,17 @@ describe("Proof of Passport - Contracts - Register & Disclose flow", function () const path_disclose_vkey = "../circuits/build/disclose_vkey.json"; // Smart contracts let Verifier_register: any, verifier_register: any, Registry: any, registry: any, Formatter: any, formatter: any, Register: any, register: any, Verifier_disclose: any, verifier_disclose: any, SBT: any, sbt: any, PoseidonT3: any, poseidonT3: any; - let owner, otherAccount, thirdAccount: any[]; + let owner, otherAccount, thirdAccount: Signer; let imt: IMT; + let bitmap, scope, user_address, majority, user_identifier, current_date, input_disclose: any; + let proof_disclose, publicSignals_disclose, proof_result_disclose, vkey_disclose, verified_disclose: any, rawCallData_disclose, parsedCallData_disclose: any[], formattedCallData_disclose: any; + let secret: string = BigInt(0).toString(); + let attestation_id: string = BigInt(0).toString(); + before( async function generateProof() { + [owner, otherAccount, thirdAccount] = await ethers.getSigners() as any[]; // Log the current block timestamp const latestBlock = await ethers.provider.getBlock('latest'); // console.log(`Current block timestamp: ${latestBlock?.timestamp}`); @@ -50,19 +57,86 @@ describe("Proof of Passport - Contracts - Register & Disclose flow", function () passportData = mockPassportData_sha256WithRSAEncryption_65537; inputs = generateCircuitInputsRegister( - BigInt(0).toString(), BigInt(0).toString(), passportData, { developmentMode: true } + secret, attestation_id, passportData, { developmentMode: true } ); - /*** Groth16 saga ***/ + /*** Deploy contracts ***/ + await deployContracts(); + + /*** Initialize merkle tree ***/ + imt = new IMT(poseidon2, 2, 0, 2); + }); + async function deployContracts() { + Verifier_register = await ethers.getContractFactory("Verifier_register"); + verifier_register = await Verifier_register.deploy(); + await verifier_register.waitForDeployment(); + console.log('\x1b[34m%s\x1b[0m', `Verifier_register deployed to ${verifier_register.target}`); + + Formatter = await ethers.getContractFactory("Formatter"); + formatter = await Formatter.deploy(); + await formatter.waitForDeployment(); + await formatter.addCountryCodes(Object.entries(countryCodes)); + console.log('\x1b[34m%s\x1b[0m', `Formatter deployed to ${formatter.target}`); + + Registry = await ethers.getContractFactory("Registry"); + registry = await Registry.deploy(formatRoot(inputs.merkle_root)); + await registry.waitForDeployment(); + console.log('\x1b[34m%s\x1b[0m', `Registry deployed to ${registry.target}`); + + PoseidonT3 = await ethers.getContractFactory("PoseidonT3"); + poseidonT3 = await PoseidonT3.deploy(); + await poseidonT3.waitForDeployment(); + console.log('\x1b[34m%s\x1b[0m', `PoseidonT3 deployed to: ${poseidonT3.target}`); + + const poseidonT3Address = poseidonT3.target; + Register = await ethers.getContractFactory("Register", { + libraries: { + PoseidonT3: poseidonT3Address + } + }); + register = await Register.deploy(registry.target); + await register.waitForDeployment(); + console.log('\x1b[34m%s\x1b[0m', `Register deployed to ${register.target}`); + + Verifier_disclose = await ethers.getContractFactory("Verifier_disclose"); + verifier_disclose = await Verifier_disclose.deploy(); + await verifier_disclose.waitForDeployment(); + console.log('\x1b[34m%s\x1b[0m', `Verifier_disclose deployed to ${verifier_disclose.target}`); + + await register.addSignatureAlgorithm(0, verifier_register.target); // dev function - will not be deployed in production + + SBT = await ethers.getContractFactory("SBT"); + sbt = await SBT.deploy(verifier_disclose.target, formatter.target, register.target); + await sbt.waitForDeployment(); + console.log('\x1b[34m%s\x1b[0m', `SBT deployed to ${sbt.target}`); + } + + describe("Proof of Passport - Utils flow", function () { + it("Should convert ISO dates to unix timestamps correctly", async function () { + const unix_timestamp = await formatter.dateToUnixTimestamp("230512") // 2023 05 12 + console.log('unix_timestamp', unix_timestamp.toString()); + + var date = new Date(Number(unix_timestamp) * 1000); + console.log("date:", date.toUTCString()); + + expect(date.getUTCFullYear()).to.equal(2023); + expect(date.getUTCMonth()).to.equal(4); + expect(date.getUTCDate()).to.equal(12); + }) + }) + + /*** Register flow ***/ + describe("Proof of Passport - Register flow", function () { + before(async function () { + /*** Groth16 saga Register***/ // Generate the proof - console.log('\x1b[32m%s\x1b[0m', 'Generating proof...'); - console.log(inputs); + console.log('\x1b[32m%s\x1b[0m', 'Generating proof - Register...'); ({ proof, publicSignals } = await groth16.fullProve( inputs, path_register_wasm, path_register_zkey )) - console.log('\x1b[32m%s\x1b[0m', 'Proof generated'); + console.log('\x1b[32m%s\x1b[0m', 'Proof generated - Register'); // Verify the proof const vKey = JSON.parse(fs.readFileSync(path_register_vkey) as unknown as string); const verified = await groth16.verify( @@ -71,136 +145,238 @@ describe("Proof of Passport - Contracts - Register & Disclose flow", function () proof ) assert(verified == true, 'Should verify') - console.log('\x1b[32m%s\x1b[0m', 'Proof verified'); + console.log('\x1b[32m%s\x1b[0m', 'Proof verified - Register'); const rawCallData = await groth16.exportSolidityCallData(proof, publicSignals); - pasrsedCallData = JSON.parse(`[${rawCallData}]`); - formattedCallData = { - commitment: pasrsedCallData[3][0], - nullifier: pasrsedCallData[3][1], - merkle_root: pasrsedCallData[3][2], - signature_algorithm: pasrsedCallData[3][3], - a: pasrsedCallData[0], - b: [pasrsedCallData[1][0], pasrsedCallData[1][1]], - c: pasrsedCallData[2], + parsedCallData_register = JSON.parse(`[${rawCallData}]`); + formattedCallData_register = { + commitment: parsedCallData_register[3][0], + nullifier: parsedCallData_register[3][1], + merkle_root: parsedCallData_register[3][2], + signature_algorithm: parsedCallData_register[3][3], + a: parsedCallData_register[0], + b: [parsedCallData_register[1][0], parsedCallData_register[1][1]], + c: parsedCallData_register[2], }; - console.log('\x1b[34m%s\x1b[0m', 'formattedCallData:', formattedCallData); - /*** Deploy contracts ***/ - - [owner, otherAccount, thirdAccount] = await ethers.getSigners() as any[]; - - Verifier_register = await ethers.getContractFactory("Verifier_register"); - verifier_register = await Verifier_register.deploy(); - await verifier_register.waitForDeployment(); - console.log('\x1b[34m%s\x1b[0m', `Verifier_register deployed to ${verifier_register.target}`); - - Formatter = await ethers.getContractFactory("Formatter"); - formatter = await Formatter.deploy(); - await formatter.waitForDeployment(); - await formatter.addCountryCodes(Object.entries(countryCodes)); - console.log('\x1b[34m%s\x1b[0m', `Formatter deployed to ${formatter.target}`); - - Registry = await ethers.getContractFactory("Registry"); - registry = await Registry.deploy(formatRoot(inputs.merkle_root)); - await registry.waitForDeployment(); - console.log('\x1b[34m%s\x1b[0m', `Registry deployed to ${registry.target}`); - - PoseidonT3 = await ethers.getContractFactory("PoseidonT3"); - poseidonT3 = await PoseidonT3.deploy(); - await poseidonT3.waitForDeployment(); - console.log('\x1b[34m%s\x1b[0m', `PoseidonT3 deployed to: ${poseidonT3.target}`); - - const poseidonT3Address = poseidonT3.target; - Register = await ethers.getContractFactory("Register", { - libraries: { - PoseidonT3: poseidonT3Address - } - }); - register = await Register.deploy(registry.target); - await register.waitForDeployment(); - console.log('\x1b[34m%s\x1b[0m', `Register deployed to ${register.target}`); - - Verifier_disclose = await ethers.getContractFactory("Verifier_disclose"); - verifier_disclose = await Verifier_disclose.deploy(); - await verifier_disclose.waitForDeployment(); - console.log('\x1b[34m%s\x1b[0m', `Verifier_disclose deployed to ${verifier_disclose.target}`); - - SBT = await ethers.getContractFactory("SBT"); - sbt = await SBT.deploy(verifier_disclose.target, formatter.target, register.target); - await sbt.waitForDeployment(); - console.log('\x1b[34m%s\x1b[0m', `SBT deployed to ${sbt.target}`); - - /*** Initialize merkle tree ***/ - imt = new IMT(poseidon2, 16, 0, 2); + // Set fake commitments into the tree + const commitments = [1, 2, 3]; + for (const commitment of commitments) { + await register.dev_add_commitment(commitment); // this is a dev function and will not be deplyed in production + imt.insert(BigInt(commitment)); + } }); - describe("Proof of Passport - Register flow", function () { - - it("Verifier_register verifies a correct proof", async () => { + it("Verifier_register.sol verifies a correct proof - Register", async () => { expect( - await verifier_register.verifyProof(pasrsedCallData[0], pasrsedCallData[1], pasrsedCallData[2], pasrsedCallData[3]) + await verifier_register.verifyProof(parsedCallData_register[0], parsedCallData_register[1], parsedCallData_register[2], parsedCallData_register[3]) ).to.be.true; }); - it("Register should succeed", async function () { + it("Register with a wrong proof should fail - Register", async function () { + await expect(register + .validateProof({ ...formattedCallData_register, a: [0, 0] })) + .to.be.revertedWith("Register__InvalidProof()") + .catch(error => { + assert(error.message.includes("Register__InvalidProof()"), "Expected revert with Register__InvalidProof(), but got another error"); + }); + }); - const commitments = [1, 2, 3]; // Example array of commitments, all set to zero as per instructions - for (const commitment of commitments) { - await register.dev_add_commitment(commitment); - imt.insert(BigInt(commitment)); - } - //log merkle root - console.log('\x1b[34m%s\x1b[0m', `Merkle root: ${await register.getMerkleRoot()}`); + it("Register with a wrong signature algorithm should fail - Register", async function () { + await expect(register + .validateProof({ ...formattedCallData_register, signature_algorithm: 10 })) + .to.be.revertedWith("Register__InvalidSignatureAlgorithm()") + .catch(error => { + assert(error.message.includes("Register__InvalidSignatureAlgorithm()"), "Expected revert with Register__InvalidSignatureAlgorithm(), but got another error"); + }); + }); - await register.dev_set_signature_algorithm(0, verifier_register.target); + it("Register with a wrong merkle root should fail - Register", async function () { + await expect(register + .validateProof({ ...formattedCallData_register, merkle_root: 0 })) + .to.be.revertedWith("Register__InvalidMerkleRoot()") + .catch(error => { + assert(error.message.includes("Register__InvalidMerkleRoot()"), "Expected revert with Register__InvalidMerkleRoot(), but got another error"); + }); + }); + it("Register should succeed - Register", async function () { expect(await register - .connect(thirdAccount) // fine that it's not the same account as address is taken from the proof - .validateProof(formattedCallData)).not.to.be.reverted; + .validateProof(formattedCallData_register)).not.to.be.reverted; + imt.insert(BigInt(formattedCallData_register.commitment)); + /// check if the merkle root is equal to the one from the imt + // console.log('\x1b[34m%s\x1b[0m', `IMT Merkle root of TS Object - TS: ${imt.root}`); + // console.log('\x1b[34m%s\x1b[0m', `Merkle root of contract - TS: ${await register.getMerkleRoot()}`); + assert.equal(await register.getMerkleRoot(), imt.root); + console.log('\x1b[34m%s\x1b[0m', `Merkle roots from TS Object and Smart Contract are equal: ${imt.root}`); - imt.insert(BigInt(formattedCallData.commitment)); - console.log('\x1b[32m%s\x1b[0m', `Commitment: ${BigInt(formattedCallData.commitment)}`); - // const indexOfCommitment = await register.indexOf(formattedCallData.commitment); - // const merkleTreeSize = await register.getMerkleTreeSize(); + }); + it("Register with the same proof should fail - Register", async function () { + await expect(register + .validateProof(formattedCallData_register)) + .to.be.revertedWith("Register__YouAreUsingTheSameNullifierTwice()") + .catch(error => { + assert(error.message.includes("Register__YouAreUsingTheSameNullifierTwice()"), "Expected revert with Register__YouAreUsingTheSameNullifierTwice(), but got another error"); + }); }); }); + + + /*** Disclose flow ***/ describe("Proof of Passport - Disclose flow", function () { - it("SBT should succeed", async function () { - /*** Groth16 saga ***/ - // Generate the proof - const bitmap = Array(90).fill(1).map((_, i) => i.toString()); - const scope = BigInt(0).toString(); - const input_disclose = generateCircuitInputsDisclose( - inputs.secret, inputs.attestation_id, passportData, imt as any, ["1", "8"], bitmap, scope, thirdAccount + //before all + before(async function () { + /*** Groth16 saga - Disclose***/ + + // refactor in generate inputs function + bitmap = Array(90).fill("1"); + scope = BigInt(5).toString(); + user_address = await thirdAccount.getAddress(); + majority = ["1", "8"]; + input_disclose = generateCircuitInputsDisclose( + inputs.secret, inputs.attestation_id, passportData, imt as any, majority, bitmap, scope, BigInt(user_address.toString()).toString(), 16 ); - console.log('\x1b[32m%s\x1b[0m', 'Generating proof - SBT'); - console.log(input_disclose); - ({ proof, publicSignals } = await groth16.fullProve( - input_disclose, - path_disclose_wasm, - path_disclose_zkey - )) - // console.log('\x1b[32m%s\x1b[0m', 'Proof generated - SBT'); - // // Verify the proof - // const vKey = JSON.parse(fs.readFileSync(path_disclose_vkey) as unknown as string); - // const verified = await groth16.verify( - // vKey, - // publicSignals, - // proof - // ) - // assert(verified == true, 'Should verify') - // console.log('\x1b[32m%s\x1b[0m', 'Proof verified - SBT'); + // Generate the proof + console.log('\x1b[32m%s\x1b[0m', 'Generating proof - Disclose'); + try { + proof_result_disclose = await groth16.fullProve( + input_disclose, + path_disclose_wasm, + path_disclose_zkey + ); + } catch (error) { + console.error("Error generating proof:", error); + throw error; + } + proof_disclose = proof_result_disclose.proof; + publicSignals_disclose = proof_result_disclose.publicSignals; - // const rawCallData = await groth16.exportSolidityCallData(proof, publicSignals); - // pasrsedCallData = JSON.parse(`[${rawCallData}]`); - // console.log('\x1b[34m%s\x1b[0m', 'pasrsedCallData:', pasrsedCallData); + console.log('\x1b[32m%s\x1b[0m', 'Proof generated - Disclose'); + // Verify the proof + vkey_disclose = JSON.parse(fs.readFileSync(path_disclose_vkey) as unknown as string); + verified_disclose = await groth16.verify( + vkey_disclose, + publicSignals_disclose, + proof_disclose + ) + assert(verified_disclose == true, 'Should verify') + console.log('\x1b[32m%s\x1b[0m', 'Proof verified - Disclose'); + rawCallData_disclose = await groth16.exportSolidityCallData(proof_disclose, publicSignals_disclose); + parsedCallData_disclose = JSON.parse(`[${rawCallData_disclose}]`); + formattedCallData_disclose = { + nullifier: parsedCallData_disclose[3][0], + revealedData_packed: [parsedCallData_disclose[3][1], parsedCallData_disclose[3][2], parsedCallData_disclose[3][3]], + attestation_id: parsedCallData_disclose[3][4], + merkle_root: parsedCallData_disclose[3][5], + scope: parsedCallData_disclose[3][6], + current_date: [parsedCallData_disclose[3][7], parsedCallData_disclose[3][8], parsedCallData_disclose[3][9], parsedCallData_disclose[3][10], parsedCallData_disclose[3][11], parsedCallData_disclose[3][12]], + user_identifier: parsedCallData_disclose[3][13], + a: parsedCallData_disclose[0], + b: [parsedCallData_disclose[1][0], parsedCallData_disclose[1][1]], + c: parsedCallData_disclose[2], + }; + }) + it("SBT mint should fail with a wrong current date - SBT", async function () { + await expect(sbt.mint({ ...formattedCallData_disclose, current_date: [2, 4, 0, 1, 0, 1] })) + .to.be.revertedWith("Current date is not within the valid range") }); + it("SBT mint should fail with a wrong proof - SBT", async function () { + await expect(sbt.mint({ ...formattedCallData_disclose, nullifier: 0 })) + .to.be.revertedWith("Invalid Proof"); + }); + it("SBT mint should fail with a wrong merkle_root - SBT", async function () { + await expect(sbt.mint({ ...formattedCallData_disclose, merkle_root: 0 })) + .to.be.revertedWith("Invalid merkle root"); + }); + it("Verifier_disclose.sol verifies a correct proof - Disclose", async () => { + expect( + await verifier_disclose.verifyProof(parsedCallData_disclose[0], parsedCallData_disclose[1], parsedCallData_disclose[2], parsedCallData_disclose[3]) + ).to.be.true; + }); + it("SBT mint should succeed - SBT", async function () { + expect( + await sbt.mint(formattedCallData_disclose) + ).not.to.be.reverted; + }); + it("URI et Expiry saga - SBT", async function () { + const tokenURI = await sbt.tokenURI(0); + const decodedTokenURI = Buffer.from(tokenURI.split(',')[1], 'base64').toString(); + let parsedTokenURI; + try { + parsedTokenURI = JSON.parse(decodedTokenURI); + } catch (e) { + assert(false, 'TokenURI is not a valid JSON'); + } + // console.log('parsedTokenURI', parsedTokenURI); + const expired = parsedTokenURI.attributes.find((attribute: any) => attribute.trait_type === 'Expired'); + expect(expired.value).to.equal('No'); + await time.increaseTo(2240161656); // 2040 + const tokenURIAfter = await sbt.tokenURI(0); + const decodedTokenURIAfter = Buffer.from(tokenURIAfter.split(',')[1], 'base64').toString(); + const parsedTokenURIAfter = JSON.parse(decodedTokenURIAfter); + const expiredAfter = parsedTokenURIAfter.attributes.find((attribute: any) => attribute.trait_type === 'Expired'); + expect(expiredAfter.value).to.equal('Yes'); + }); + + it("SBT mint should fail with same proof twice - SBT", async function () { + await expect(sbt.mint(formattedCallData_disclose)) + .to.be.revertedWith("Signature already nullified"); + }); + + }); + // describe("Minting on mumbai", function () { + // it.skip("Should allow minting using a proof generated by ark-circom", async function () { + // const newCallDataFromArkCircom = [["0x089e5850e432d76f949cedc26527a7fb093194dd4026d5efb07c8ce6093fa977", "0x0154b01b5698e6249638be776d3641392cf89a5ad687beb2932c0ccf33f271d4"], [["0x2692dbce207361b048e6eff874fdc5d50433baa546fa754348a87373710044c0", "0x1db8ddab0dc204d41728efc05d2dae690bebb782b6088d92dda23a87b6bed0a2"], ["0x106be642690f0fe3562d139ed09498d979c8b35ecfb04e5a49422015cafa2705", "0x0b133e53cd0b4944ce2d34652488a16d1a020905dc1972ccc883d364dd3bb4ee"]], ["0x09eda5d551b150364ecb3efb432e4568b2be8f83c2db1dd1e1285c45a428b32b", "0x008ee9e870e5416849b3c94b8b9e4759580659f5a6535652d0a6634df23db2f5"], ["0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x0000000000000000000000000000000000000000000000000000000000000000", "0x000000000000000000000000000000006df9dd0914f215fafa1513e51ac9f1e2", "0x00000000000000000000000000000000000000000000093e703cd030e286890e", "0x0000000000000000000000000000000000000000000004770a914f3ae4e1288b", "0x000000000000000000000000000000000000000000000bf7e8ecb4e9609a489d", "0x00000000000000000000000000000000000000000000035762de41038bc2dcf1", "0x00000000000000000000000000000000000000000000050442c4055d62e9c4af", "0x0000000000000000000000000000000000000000000004db2bdc79a477a0fce0", "0x000000000000000000000000000000000000000000000acdbf649c76ec3df9ad", "0x000000000000000000000000000000000000000000000aaa0e6798ee3694f5ca", "0x000000000000000000000000000000000000000000000a1eaac37f80dd5e2879", "0x00000000000000000000000000000000000000000000033e063fba83c27efbce", "0x00000000000000000000000000000000000000000000045b9b05cab95025b000", "0x000000000000000000000000e6e4b6a802f2e0aee5676f6010e0af5c9cdd0a50"]]; + // // const callDataFromArkCircomGeneratedInTest = [ [ '0x07a378ec2b5bafc15a21fb9c549ba2554a4ef22cfca3d835f44d270f547d0913', '0x089bb81fb68200ef64652ada5edf71a98dcc8a931a54162b03b61647acbae1fe' ], [ [ '0x2127ae75494aed0c384567cc890639d7609040373d0a549e665a26a39b264449', '0x2f0ea6c99648171b7e166086108131c9402f9c5ac4a3759705a9c9217852e328' ], [ '0x04efcb825be258573ffe8c9149dd2b040ea3b8a9fa3dfa1c57a87b11c20c21ec', '0x2b500aece0e5a5a64a5c7262ec379efc1a23f4e46d968aebd42337642ea2bd3e' ] ], [ '0x1964dc2231bcd1e0de363c3d2a790346b7e634b5878498ce6e8db0ac972b8125', '0x0d94cd74a89b0ed777bb309ce960191acd23d5e9c5f418722d03f80944c5e3ed' ], [ '0x000000000000000000544e45524f4c4600000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x0000000000000000000000000000000000000000000000000000000000000000', '0x000000000000000000000000000000000df267467de87516584863641a75504b', '0x00000000000000000000000000000000000000000000084c754a8650038f4c82', '0x000000000000000000000000000000000000000000000d38447935bb72a5193c', '0x000000000000000000000000000000000000000000000cac133b01f78ab24970', '0x0000000000000000000000000000000000000000000006064295cda88310ce6e', '0x000000000000000000000000000000000000000000001026cd8776cbd52df4b0', '0x000000000000000000000000000000000000000000000d4748d254334ce92b36', '0x0000000000000000000000000000000000000000000005c1b0ba7159834b0bf1', '0x00000000000000000000000000000000000000000000029d91f03395b916792a', '0x000000000000000000000000000000000000000000000bcfbb30f8ea70a224df', '0x00000000000000000000000000000000000000000000003dcd943c93e565aa3e', '0x0000000000000000000000000000000000000000000009e8ce7916ab0fb0b000', '0x000000000000000000000000ede0fa5a7b196f512204f286666e5ec03e1005d2' ] ]; + + // const registerOnMumbaiAddress = '0x7D459347d092D35f043f73021f06c19f834f8c3E'; + // const registerOnMumbai = await ethers.getContractAt('Register', registerOnMumbaiAddress); + // try { + // const tx = await registerOnMumbai.mint(...newCallDataFromArkCircom as any); + // console.log('txHash', tx.hash); + // const receipt = await tx.wait(); + // console.log('receipt', receipt) + // expect(receipt?.status).to.equal(1); + // } catch (error) { + // console.error(error); + // expect(true).to.equal(false); + // } + // }); + + // it.skip("Should allow minting using lambda function", async function () { + // const registerOnMumbaiAddress = '0x0AAd39A080129763c8E1e2E9DC44E777DB0362a3'; + // const provider = new ethers.JsonRpcProvider('https://polygon-mumbai-bor.publicnode.com'); + // const registerOnMumbai = await ethers.getContractAt('Register', registerOnMumbaiAddress); + + // try { + // const transactionRequest = await registerOnMumbai + // .mint.populateTransaction(...callData); + + // console.log('transactionRequest', transactionRequest); + + // const apiEndpoint = process.env.AWS_ENDPOINT; + // if (!apiEndpoint) { + // throw new Error('AWS_ENDPOINT env variable is not set'); + // } + // const response = await axios.post(apiEndpoint, { + // chain: "mumbai", + // tx_data: transactionRequest + // }); + // console.log('response status', response.status) + // console.log('response data', response.data) + // const receipt = await provider.waitForTransaction(response.data.hash); + // console.log('receipt', receipt) + // } catch (err) { + // console.log('err', err); + // } + // }); + // }) + });