Refactor contracts, create RegisterAndDisclose.ts

This commit is contained in:
turnoffthiscomputer
2024-05-11 15:45:20 +02:00
committed by 0xturboblitz
parent 25d801b1e9
commit 19904038b6
8 changed files with 489 additions and 403 deletions

View File

@@ -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);

View File

@@ -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()),

View File

@@ -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;
}
}

View File

@@ -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()
)
);
}
}
}

View File

@@ -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 <https://www.gnu.org/licenses/>.
*/
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)
}
}
}

View File

@@ -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;

View File

@@ -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);
}
}

View File

@@ -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);
// }
// });
// })
});