Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add circuits for KYC enforcement with anonymity #25

Merged
merged 12 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 55 additions & 22 deletions solidity/contracts/lib/registry.sol
Original file line number Diff line number Diff line change
Expand Up @@ -15,36 +15,69 @@
// 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 "hardhat/console.sol";

/// @title A sample on-chain implementation of an account mapping between Ethereum addresses and BabyJubjub public keys
uint256 constant MAX_SMT_DEPTH = 64;

/// @title A sample on-chain implementation of a KYC registry
/// @dev The registry uses a Sparse Merkle Tree to store the
/// Zeto accounts (Babyjubjub keys), so that transaction
/// submitters can generate proofs of membership for the
/// accounts in a privacy-preserving manner.
/// @author Kaleido, Inc.
contract Registry is Ownable {
mapping(address => uint256[2]) private publicKeys;
abstract contract Registry {
SmtLib.Data internal _publicKeysTree;
using SmtLib for SmtLib.Data;

event IdentityRegistered(uint256[2] publicKey);

error AlreadyRegistered(address addr);
error AlreadyRegistered(uint256[2]);

constructor() Ownable(msg.sender) {}
constructor() {
_publicKeysTree.initialize(MAX_SMT_DEPTH);
}

/// @dev Register a new public key for the calling Ethereum address
/// @param ethAddress The Ethereum address to register
/// @dev Register a new Zeto account
/// @param publicKey The public Babyjubjub key to register
function register(
address ethAddress,
uint256[2] memory publicKey
) public onlyOwner {
if (publicKeys[ethAddress][0] != 0 || publicKeys[ethAddress][1] != 0) {
revert AlreadyRegistered(ethAddress);
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);
}
publicKeys[ethAddress] = publicKey;
_publicKeysTree.addLeaf(nodeHash, nodeHash);
emit IdentityRegistered(publicKey);
}

/// @dev returns whether the given public key is registered
/// @param publicKey The Babyjubjub public key to check
/// @return bool whether the given public key is included in the registry
function isRegistered(
Copy link
Contributor

@Chengxuan Chengxuan Aug 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not sure where this gets used.

Copy link
Contributor

@Chengxuan Chengxuan Aug 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I answered my own question: it doesn't need to be used directly. as the circuit does the check with the identitiesRoot https://github.com/hyperledger-labs/zeto/pull/25/files#diff-9383275728425055b13bcbc860ce1ca0d4885b23049fa3ecf52fa71f1f144e65R105

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah it's a convenient method for client apps. not essential for the circuit verifier to work.

uint256[2] memory publicKey
) public view returns (bool) {
uint256 nodeKey = _getIdentitiesLeafNodeKey(publicKey);
SmtLib.Node memory node = _publicKeysTree.getNode(nodeKey);
return node.nodeType != SmtLib.NodeType.EMPTY;
}

/// @dev Query the public key for a given Ethereum address
/// @param addr The Ethereum address to query
/// @return publicKey The public key for the given address
function getPublicKey(
address addr
) public view returns (uint256[2] memory publicKey) {
return publicKeys[addr];
function getIdentitiesRoot() public view returns (uint256) {
return _publicKeysTree.getRoot();
}

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

function _getIdentitiesLeafNodeKey(
uint256[2] memory publicKey
) internal pure returns (uint256) {
uint256 nodeHash = PoseidonUnit2L.poseidon(publicKey);
uint256[3] memory params = [nodeHash, nodeHash, uint256(1)];
return PoseidonUnit3L.poseidon(params);
}
}
2 changes: 1 addition & 1 deletion solidity/contracts/lib/verifier_anon.sol
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ contract Groth16Verifier_Anon {
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, r)) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0, 0x20)
}
Expand Down
2 changes: 1 addition & 1 deletion solidity/contracts/lib/verifier_anon_enc.sol
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ contract Groth16Verifier_AnonEnc {
function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[7] calldata _pubSignals) public view returns (bool) {
assembly {
function checkField(v) {
if iszero(lt(v, r)) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0, 0x20)
}
Expand Down
22 changes: 11 additions & 11 deletions solidity/contracts/lib/verifier_anon_enc_nullifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ contract Groth16Verifier_AnonEncNullifier {
uint256 constant deltay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;


uint256 constant IC0x = 1132180179491441538738452273651946883461412832203743112811118844473379442028;
uint256 constant IC0y = 5390783026485963433523207720053244289587838204839623860596474298081543088585;
uint256 constant IC0x = 4568570755632788643394533153911199637393845847987729293464981238980340214701;
uint256 constant IC0y = 15128319276870423050909157626275409799208340368213199411576816383311184129195;

uint256 constant IC1x = 9479671548635182258434953602646699552143280379254562789430654117067623065154;
uint256 constant IC1y = 4513875910577591187417669244456597493215594361393034699197432847781635817944;
Expand All @@ -58,23 +58,23 @@ contract Groth16Verifier_AnonEncNullifier {
uint256 constant IC4x = 8045706817285648122335493621835686579889910526627484670178299244569350873337;
uint256 constant IC4y = 14703212748037329834343212171120394526601085625912333793516662767512116840031;

uint256 constant IC5x = 17557824284863559227631182945646272910505435334053056722808626217521393289128;
uint256 constant IC5y = 16307615047799173365519895850598694329138770383868524034358007080013608669085;
uint256 constant IC5x = 12289213637181054892282624823702301699573523320936692431552214952203040411410;
uint256 constant IC5y = 16455438753606683924006591564176938596063251993144033301210430323087499194482;

uint256 constant IC6x = 5415585987138244191813990034208825389253432804629600554497141813191469438492;
uint256 constant IC6y = 17755870055831490788712008393346742047905432267237159229825629073030204324527;
uint256 constant IC6x = 14303047076752096755721879884111868337074094864491631063458708071696569838284;
uint256 constant IC6y = 5911949370715042191384217137312039273992455050421022652157649670332806294542;

uint256 constant IC7x = 8677981225322796966854381897381189421248711504209293881165286829150524884164;
uint256 constant IC7y = 12816796872832476519349268616267285968398279397067849918595558738184610770874;
uint256 constant IC7x = 15841884851029529902011697322996410384031024289464678913047883869169350568208;
uint256 constant IC7y = 21520807340471527261351700326658280597567437458476043915147723227393128763810;

uint256 constant IC8x = 15740540576184573386354609430256689221677491143833514512062380094508866796269;
uint256 constant IC8y = 2340484610103666557078136629597674107756904443534921271417989072923691667449;

uint256 constant IC9x = 3726988392811514450533313378412430039053796082573590843909105394276411441536;
uint256 constant IC9y = 7347033125306979340056255923745117502907380131073815888051201665421460725544;

uint256 constant IC10x = 6619094542081504921297870625144079235409984730673107107299279901988791810356;
uint256 constant IC10y = 10549347737329626943980590291223696927409993218357923512265036708353601601743;
uint256 constant IC10x = 4371277742931522011055134703913097482787808225431324421232573076499659150767;
uint256 constant IC10y = 11516411764009653445050545510250621675398241508987088025760029722333645258716;


// Memory data
Expand All @@ -86,7 +86,7 @@ contract Groth16Verifier_AnonEncNullifier {
function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[10] calldata _pubSignals) public view returns (bool) {
assembly {
function checkField(v) {
if iszero(lt(v, r)) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0, 0x20)
}
Expand Down
18 changes: 9 additions & 9 deletions solidity/contracts/lib/verifier_anon_nullifier.sol
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,23 @@ contract Groth16Verifier_AnonNullifier {
uint256 constant deltay2 = 8495653923123431417604973247489272438418190587263600148770280649306958101930;


uint256 constant IC0x = 7831194482890201907912813708954693484499937202778946556314791150355497052838;
uint256 constant IC0y = 17214367048578530654688121231520081865319465732684236954806278278486355045687;
uint256 constant IC0x = 5484373638915608486871020804166539520782909040345505335019959652136228862082;
uint256 constant IC0y = 16138277411069907720477228076440687453311854575356818231417756272310801661588;

uint256 constant IC1x = 657611904883114148980717005767820105315776575523580933462233892133390721686;
uint256 constant IC1y = 3690011531716382218745803104163270083920150842903711282044842015835943598950;

uint256 constant IC2x = 13247301284400305330080530887135251465329343308345822132754291671475418335661;
uint256 constant IC2y = 6878027108417593313264947615215679812389458074470859941986417727720332868266;

uint256 constant IC3x = 4393308877038816112044751113703161046884042023529143670482606285253407357318;
uint256 constant IC3y = 10861402902194208967056892862272521752290820790123718158389295013478034329376;
uint256 constant IC3x = 12122806794972194128212202542170444918567562037253242662728390689220136089417;
uint256 constant IC3y = 9885901744875470674355026551458972605308247499314156850898233682886130241050;

uint256 constant IC4x = 20567726645522252344842011251254616164566067019107949894642154009522868698126;
uint256 constant IC4y = 13058332362792856027058697122630683468388748189437006630731046361022666962675;
uint256 constant IC4x = 14497189114754949587485834175427788983830001040470111882678218991459557006481;
uint256 constant IC4y = 20830021231156123029529082857782030827870844726616623033674403796120242993032;

uint256 constant IC5x = 11519149396981714918708162608439765519813165816162067214356117934500928163278;
uint256 constant IC5y = 4896357293383145162082835572689841388496488666220683242957098534343617845489;
uint256 constant IC5x = 15185920369074896375657194229340428184369591270326493422044278017722304487940;
uint256 constant IC5y = 19431411716277310851795675028059565579151437630225658811235304233499648067653;

uint256 constant IC6x = 13045447923950887968308059891638935794209679677588887793771333234932902547512;
uint256 constant IC6y = 1960124371120172285328335936511540489447355418368729402128803121783956301995;
Expand All @@ -77,7 +77,7 @@ contract Groth16Verifier_AnonNullifier {
function verifyProof(uint[2] calldata _pA, uint[2][2] calldata _pB, uint[2] calldata _pC, uint[7] calldata _pubSignals) public view returns (bool) {
assembly {
function checkField(v) {
if iszero(lt(v, r)) {
if iszero(lt(v, q)) {
mstore(0, 0)
return(0, 0x20)
}
Expand Down
Loading
Loading