Skip to content

Commit

Permalink
completed the sample circuit with KYC; solidity sample for Zeto fungi…
Browse files Browse the repository at this point in the history
…ble tokens with KYC

Signed-off-by: Jim Zhang <[email protected]>
  • Loading branch information
jimthematrix committed Aug 5, 2024
1 parent bd534cb commit e4c5c96
Show file tree
Hide file tree
Showing 24 changed files with 815 additions and 416 deletions.
34 changes: 8 additions & 26 deletions solidity/contracts/lib/registry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,9 @@
// limitations under the License.
pragma solidity ^0.8.20;

import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {SmtLib} from "@iden3/contracts/lib/SmtLib.sol";
import {PoseidonUnit2L, PoseidonUnit3L} from "@iden3/contracts/lib/Poseidon.sol";
import {Commonlib} from "./common.sol";
import {Groth16Verifier_CheckSmtProof} from "./verifier_check_smt_proof.sol";
import "hardhat/console.sol";

uint256 constant MAX_SMT_DEPTH = 64;
Expand All @@ -30,36 +28,20 @@ uint256 constant MAX_SMT_DEPTH = 64;
/// submitters can generate proofs of membership for the
/// accounts in a privacy-preserving manner.
/// @author Kaleido, Inc.
abstract contract Registry is Ownable {
abstract contract Registry {
SmtLib.Data internal _publicKeysTree;
using SmtLib for SmtLib.Data;

Groth16Verifier_CheckSmtProof private verifier;

error AlreadyRegistered(uint256[2]);

constructor(Groth16Verifier_CheckSmtProof _verifier) Ownable(msg.sender) {
verifier = _verifier;
constructor() {
_publicKeysTree.initialize(MAX_SMT_DEPTH);
}

modifier onlyRegistered(Commonlib.Proof calldata proof) {
uint256 root = _publicKeysTree.getRoot();
uint256[1] memory publicInputs;
publicInputs[0] = root;

// // Check the proof
require(
verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
"Identity not registered"
);
_;
}

/// @dev Register a new Zeto account
/// @param publicKey The public Babyjubjub key to register
function register(uint256[2] memory publicKey) public onlyOwner {
uint256 nodeHash = _getLeafNodeHash(publicKey);
function _register(uint256[2] memory publicKey) internal {
uint256 nodeHash = _getIdentitiesLeafNodeHash(publicKey);
SmtLib.Node memory node = _publicKeysTree.getNode(nodeHash);
if (node.nodeType != SmtLib.NodeType.EMPTY) {
revert AlreadyRegistered(publicKey);
Expand All @@ -73,22 +55,22 @@ abstract contract Registry is Ownable {
function isRegistered(
uint256[2] memory publicKey
) public view returns (bool) {
uint256 nodeKey = _getLeafNodeKey(publicKey);
uint256 nodeKey = _getIdentitiesLeafNodeKey(publicKey);
SmtLib.Node memory node = _publicKeysTree.getNode(nodeKey);
return node.nodeType != SmtLib.NodeType.EMPTY;
}

function getRoot() public view returns (uint256) {
function getIdentitiesRoot() public view returns (uint256) {
return _publicKeysTree.getRoot();
}

function _getLeafNodeHash(
function _getIdentitiesLeafNodeHash(
uint256[2] memory publicKey
) internal pure returns (uint256) {
return PoseidonUnit2L.poseidon(publicKey);
}

function _getLeafNodeKey(
function _getIdentitiesLeafNodeKey(
uint256[2] memory publicKey
) internal pure returns (uint256) {
uint256 nodeHash = PoseidonUnit2L.poseidon(publicKey);
Expand Down
31 changes: 0 additions & 31 deletions solidity/contracts/lib/test/MyContract.sol

This file was deleted.

38 changes: 19 additions & 19 deletions solidity/contracts/lib/verifier_anon_nullifier_kyc.sol
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

pragma solidity >=0.7.0 <0.9.0;

contract Groth16Verifier {
contract Groth16Verifier_AnonNullifierKyc {
// Scalar field size
uint256 constant r = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
// Base field size
Expand All @@ -43,32 +43,32 @@ contract Groth16Verifier {
uint256 constant deltay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;


uint256 constant IC0x = 15894451574377776512828899822631291668771577388294000086031636794401495745108;
uint256 constant IC0y = 20500448077471199298748085716990652313441855863081423369962236790299615428929;
uint256 constant IC0x = 17253658561769030408831319377386363377029954877756637156765324323979498651244;
uint256 constant IC0y = 19447845550620157940727879792806763383315811925512356155840550493755067053283;

uint256 constant IC1x = 20443159004875723874539838705410257721540879912284412356749567977659903444911;
uint256 constant IC1y = 6665486236079333380974192300286824838457364136917664093397672618694121088151;
uint256 constant IC1x = 17691860633635445596011992135113931036771678205360067089611644453475239338807;
uint256 constant IC1y = 18676805762762822944272364662845663235143437551624413350971351487210974119996;

uint256 constant IC2x = 10165991286665292508270439031111897031430740961452613000505237863420993798921;
uint256 constant IC2y = 9136420244822775537780456157556473424250276753802018153325130368437335488961;
uint256 constant IC2x = 9359246353884494795775060227629575241229353985866987187619420127010361508034;
uint256 constant IC2y = 8388517062694554522982567663342157522410417672271312375252102792907200482451;

uint256 constant IC3x = 20281597887882800919800535705908114405524156983380180098782819247741572489398;
uint256 constant IC3y = 21607785824705256552752191795973183116557074570496562616281978326295728837624;
uint256 constant IC3x = 773129062986033561443573333661563760243263395022680620040102397288742855800;
uint256 constant IC3y = 4437956675204159891915247122343933381491595698869654079918360565183613194228;

uint256 constant IC4x = 1650512345884490589024034798398413920131787599888143340099721452288283568309;
uint256 constant IC4y = 17762263572124004609952079441932587287950558256360373694997362504497823608435;
uint256 constant IC4x = 6645115745373935053727950422910462497885276404097879876376038787546991344584;
uint256 constant IC4y = 18654672726411052252597755716024854329414673812512280690182667130526523404234;

uint256 constant IC5x = 19386768506626830282628824919708052542859521671332220831107354474836133656316;
uint256 constant IC5y = 16910894476841255025828316106755038218889475958213840126357807581898033175271;
uint256 constant IC5x = 13059522435858163127674389635682821055318628019574081126949711242545685283515;
uint256 constant IC5y = 20429805133317088848505942320052564964645959038790135294034876010255265663903;

uint256 constant IC6x = 19307586423967294928893199260202402479766234412752252005480672310147892735668;
uint256 constant IC6y = 11588134326531324221543008937081841914768042290177169066420262408448462215432;
uint256 constant IC6x = 7081897646707329390732533302866159157927438661712338489301723634665420156232;
uint256 constant IC6y = 9720758558280938038606112340132128606630785889582047493375239320218563835995;

uint256 constant IC7x = 19139469296120924050387585927788723421260614491257547987007007022510688394863;
uint256 constant IC7y = 9288080661952604669905314745907900909227032270567060567695766882828890238075;
uint256 constant IC7x = 19097209714030584366164828474495137409508653808793261818839392529382542861874;
uint256 constant IC7y = 14963596465851021268645069274158420492995798424574621453984746766086070430557;

uint256 constant IC8x = 14398271946161621939632562577274465836963412570377151128691039469213756214983;
uint256 constant IC8y = 5789907474461302660775855537997949676969273270738559295681426193011863858424;
uint256 constant IC8x = 2286325282310659848988744116651496718877341703991542322837846213613080078754;
uint256 constant IC8y = 3467490857234869537116682593234908004499601628170260705267603367015758479824;


// Memory data
Expand Down
138 changes: 138 additions & 0 deletions solidity/contracts/zeto_anon_nullifier_kyc.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright © 2024 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
pragma solidity ^0.8.20;

import {Groth16Verifier_CheckHashesValue} from "./lib/verifier_check_hashes_value.sol";
import {Groth16Verifier_CheckNullifierValue} from "./lib/verifier_check_nullifier_value.sol";
import {Groth16Verifier_AnonNullifierKyc} from "./lib/verifier_anon_nullifier_kyc.sol";
import {ZetoNullifier} from "./lib/zeto_nullifier.sol";
import {ZetoFungibleWithdrawWithNullifiers} from "./lib/zeto_fungible_withdraw_nullifier.sol";
import {Registry} from "./lib/registry.sol";
import {Commonlib} from "./lib/common.sol";
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
import {SmtLib} from "@iden3/contracts/lib/SmtLib.sol";
import {PoseidonUnit3L} from "@iden3/contracts/lib/Poseidon.sol";
import "hardhat/console.sol";

uint256 constant MAX_SMT_DEPTH = 64;

/// @title A sample implementation of a Zeto based fungible token with anonymity and history masking
/// @author Kaleido, Inc.
/// @dev The proof has the following statements:
/// - each value in the output commitments must be a positive number in the range 0 ~ (2\*\*40 - 1)
/// - the sum of the nullified values match the sum of output values
/// - the hashes in the input and output match the hash(value, salt, owner public key) formula
/// - the sender possesses the private BabyJubjub key, whose public key is part of the pre-image of the input commitment hashes, which match the corresponding nullifiers
/// - the nullifiers represent input commitments that are included in a Sparse Merkle Tree represented by the root hash
contract Zeto_AnonNullifierKyc is
ZetoNullifier,
ZetoFungibleWithdrawWithNullifiers,
Registry
{
Groth16Verifier_AnonNullifierKyc verifier;

constructor(
Groth16Verifier_CheckHashesValue _depositVerifier,
Groth16Verifier_CheckNullifierValue _withdrawVerifier,
Groth16Verifier_AnonNullifierKyc _verifier
)
ZetoNullifier()
ZetoFungibleWithdrawWithNullifiers(_depositVerifier, _withdrawVerifier)
{
verifier = _verifier;
}

function register(uint256[2] memory publicKey) public onlyOwner {
_register(publicKey);
}

/**
* @dev the main function of the contract.
*
* @param nullifiers Array of nullifiers that are secretly bound to UTXOs to be spent by the transaction.
* @param outputs Array of new UTXOs to generate, for future transactions to spend.
* @param root The root hash of the Sparse Merkle Tree that contains the nullifiers.
* @param proof A zero knowledge proof that the submitter is authorized to spend the inputs, and
* that the outputs are valid in terms of obeying mass conservation rules.
*
* Emits a {UTXOTransfer} event.
*/
function transfer(
uint256[2] memory nullifiers,
uint256[2] memory outputs,
uint256 root,
Commonlib.Proof calldata proof
) public returns (bool) {
require(
validateTransactionProposal(nullifiers, outputs, root),
"Invalid transaction proposal"
);

// construct the public inputs
uint256[8] memory publicInputs;
publicInputs[0] = nullifiers[0];
publicInputs[1] = nullifiers[1];
publicInputs[2] = root;
publicInputs[3] = (nullifiers[0] == 0) ? 0 : 1; // if the first nullifier is empty, disable its MT proof verification
publicInputs[4] = (nullifiers[1] == 0) ? 0 : 1; // if the second nullifier is empty, disable its MT proof verification
publicInputs[5] = getIdentitiesRoot();
publicInputs[6] = outputs[0];
publicInputs[7] = outputs[1];

// // Check the proof
require(
verifier.verifyProof(proof.pA, proof.pB, proof.pC, publicInputs),
"Invalid proof"
);

processInputsAndOutputs(nullifiers, outputs);

uint256[] memory nullifierArray = new uint256[](nullifiers.length);
uint256[] memory outputArray = new uint256[](outputs.length);
for (uint256 i = 0; i < nullifiers.length; ++i) {
nullifierArray[i] = nullifiers[i];
outputArray[i] = outputs[i];
}
emit UTXOTransfer(nullifierArray, outputArray, msg.sender);
return true;
}

function deposit(
uint256 amount,
uint256 utxo,
Commonlib.Proof calldata proof
) public {
_deposit(amount, utxo, proof);
uint256[] memory utxos = new uint256[](1);
utxos[0] = utxo;
_mint(utxos);
}

function withdraw(
uint256 amount,
uint256[2] memory nullifiers,
uint256 output,
uint256 root,
Commonlib.Proof calldata proof
) public {
_withdrawWithNullifiers(amount, nullifiers, output, root, proof);
processInputsAndOutputs(nullifiers, [output, 0]);
}

function mint(uint256[] memory utxos) public onlyOwner {
_mint(utxos);
}
}
2 changes: 1 addition & 1 deletion solidity/ignition/modules/lib/deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export const SmtLibModule = buildModule("SmtLib", (m) => {
PoseidonUnit3L: poseidon3,
},
});
return { smtLib, poseidon3 };
return { smtLib, poseidon2, poseidon3 };
});

export const DepositVerifierModule = buildModule("Groth16Verifier_CheckHashesValue", (m) => {
Expand Down
42 changes: 42 additions & 0 deletions solidity/ignition/modules/zeto_anon_nullifier_kyc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright © 2024 Kaleido, Inc.
//
// SPDX-License-Identifier: Apache-2.0
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

import { buildModule } from "@nomicfoundation/hardhat-ignition/modules";
import { SmtLibModule, DepositVerifierModule, WithdrawNullifierVerifierModule } from "./lib/deps";

const VerifierModule = buildModule("Groth16Verifier_AnonNullifierKyc", (m) => {
const verifier = m.contract('Groth16Verifier_AnonNullifierKyc', []);
return { verifier };
});

export default buildModule("Zeto_AnonNullifierKyc", (m) => {
const { smtLib, poseidon2, poseidon3 } = m.useModule(SmtLibModule);
const { verifier } = m.useModule(VerifierModule);
const { verifier: depositVerifier } = m.useModule(DepositVerifierModule);
const { verifier: withdrawVerifier } = m.useModule(WithdrawNullifierVerifierModule);
const commonlib = m.library('Commonlib');

const zeto = m.contract('Zeto_AnonNullifierKyc', [depositVerifier, withdrawVerifier, verifier], {
libraries: {
SmtLib: smtLib,
PoseidonUnit2L: poseidon2,
PoseidonUnit3L: poseidon3,
Commonlib: commonlib,
},
});

return { zeto };
});
Loading

0 comments on commit e4c5c96

Please sign in to comment.