We're building a dApp based on identity registries that use STARKs (with Cairo) to verify some aspects of your identity.
Let's say you need to prove that you're 18+. KYC first to either an identity provider or a state. The identity provider then releases a registry of all people 18+. Private information are encrypted by the person involved. Then, when they need to prove to a company or anyone that they are 18+, they execute the Cairo program checking the registry and verifying that the person is actually well registered, proof is then sent to the prover while programs output will be sent to a smart contract. Based on the Cairo program hash and outputs, we can now compute a fact that can be verified by the prover.
If the prover confirms that the fact is actually one, then the person would have confirmed that they are 18+. Such process can be used for many other use cases and we're excited to showcase some of them in the dApp.
A user can then select a trip and select a fare based on his age or disability (if applicable).
Before completing the booking, we generate a proof using a Cairo program that the user belongs, for example, to the registry of people under 25.
That way, the user proves to the train company that they qualify for the right fare without having to reveal anything else.
- Install Golang
- Install Cairo:
pip3 install cairo-lang-0.1.0.zip - Create a .env file in the
cmdfolder with the following keys :
MONGODB_URI="MONGODB_SVR_LINK"
MONGODB_DB_NAME="MONGODB_DB_NAME"
ETH_NODE_URI="ROPSTEN_ETH_NODE_AS_WS"
ETH_NODE_URI_HTTP="ROPSTEN_ETH_NODE_AS_HTTP"
ETH_PRIVATE_KEY="SMARTCONTRACT_OWNERS_PRIVATE_KEY"
ETH_CONTRACT_ADDRESS="SMARTCONTRACT_ADDRESS"
PUSHER_SECRET="SECRET_FOR_THE_PUSHER_CONFIGURATION"
PUSHER_KEY="KEY_FOR_THE_PUSHER_CONFIGURATION"
PUSHER_ID="ID_FOR_THE_PUSHER_CONFIGURATION"
- Run
go build && ./cmd start-apito get the backend listening on port:8080
We first need to compile the registry program with
cairo-compile registryHash.cairo --output registryHash.json --simple. We will then be able to get it's hash withcairo-hash-program --program registryHash.json:0x505ae0c3821ab690edb0fe45a63615f3600e168f3e60da824af1f28df54ecb1.Then, we will need to compile the identities program with
cairo-compile main.cairo --output cairo.json --simple. We will then be able to get it's hash withcairo-hash-program --program cairo.json:0x7f481cf54b923941934abbc67454374eaff004f6fef703783c80d9ddb3fc3b5.
We need to deploy the contract on ropsten with the following arguments :
- _registriesProgramHash =
0x505ae0c3821ab690edb0fe45a63615f3600e168f3e60da824af1f28df54ecb1- _identitiesProgramHash =
0x7f481cf54b923941934abbc67454374eaff004f6fef703783c80d9ddb3fc3b5- cairoVerifier =
0x4Cd99A1FC780d874a34008fdC6da2961d540fE64The SmartContract is deployed here :
0x274889F6864Bc0493BfEe3CF292A2A0ba1A76951.There is 2 notable functions:
function updateRegistry(uint256 registryKey, uint256 oldRegistryHash, uint256 newRegistryHash) onlyOwner public returns (bytes32)This function will be used to update a specific registry, aka the list of addresses in it. Only the owner can update this list. We have one list per key.
function proveIdentity(uint256 registryKey, uint256 hash, uint256 registryHash) public returns (bytes32)This function will be used verify, directly on the smartcontract, that the output provided are valid, aka that the proof is valid.
In order to work with this cairo program, we will first need some identities with the following information :
ADDRESS (secret) ENCRYPTED_ADDRESS ENCRYPTION_KEY 0x02cEDd50ef234A2ee3CD3B87120e4367B37a3E610x6a3044f3172368c38bf9e73393275fd7e50a5e951ff8c09e4dd7b22d95a34f52090767800323713160073244179833574127522692487744840563401913844790603053040x9BfaDaa08AAf30EA4D6D00e86ed24EfB48554BD80x6ed120ae443c419aee7e3ee2c98575edef4612ad381fe88d817f04e9e5911ae4218164476426498544238972325271005974158994379111454065455578143488174998710x09f3e857E4b14B7EF4D8F1a023e23F18f5e7ACF80x138e341ac1472ad700053c6a0e0fcdf41e7e4851ba2917fa9075f5e31e5ee2e26719560923235534105928162355937921378841110173121758360530440496670319852520xE5fb37aAe298C435Cb30B50DB950522856b8603B0x755bf706ee73a22d3720569d0d3e4a7f9d28de4993a3b9c98014831c520a21017594916034491380676110996433940877341944091804707218483307413951663289859000x4600dFcd1e585BC39432CD1dceF973acA62255620x53465c95bcfb00da727a9ffd24c5bf324329de9fc27c57e53a86a23cfda104420234748835262195520935856734119876749313165747019631931920880795426655883360x0568E0779FD984bb3E38921c466c0a5F89752e000x84afc9b9cdd81df7574ff788449dc3b6c0d6b5cf8a8f8f7536332d28b0add93124938967293004376366233214170809276646139449441931607366050588873625446273The
ADDRESSis a secret. This is what we will be try to prove (that the address is in the registry). We are displaying it only for testing purpose.
TheENCRYPTED_ADDRESSmatcheshash(ADDRESS, ENCRYPTION_KEY). This is the data that will be displayed in the registry.
TheENCRYPTION_KEYis a hash of a randomly generated password associated to the user's account (Web3.utils.randomHex(31)) and the registryKey (here:123456) ->hash(randomHex(31), 132456).With theses information, we will produce the following JSON file :
{ "oldRegistry": [], "newRegistry": [ "0x6a3044f3172368c38bf9e73393275fd7e50a5e951ff8c09e4dd7b22d95a34f5", "0x6ed120ae443c419aee7e3ee2c98575edef4612ad381fe88d817f04e9e5911ae", "0x138e341ac1472ad700053c6a0e0fcdf41e7e4851ba2917fa9075f5e31e5ee2e", "0x755bf706ee73a22d3720569d0d3e4a7f9d28de4993a3b9c98014831c520a210", "0x53465c95bcfb00da727a9ffd24c5bf324329de9fc27c57e53a86a23cfda1044", "0x84afc9b9cdd81df7574ff788449dc3b6c0d6b5cf8a8f8f7536332d28b0add9" ] }This file will be used as our initial
registryHashInputfor the registry123456.
By running
cairo-run --program=registryHash.json --print_output --layout=small --program_input=registryHashInput.json, we will have the following output :Program output: 0 2672368424450419303116754025943367656383112088074817038016074650154564643Where
0is our old hash, and2672368424450419303116754025943367656383112088074817038016074650154564643the new one.Now, let's prove that this hash is legit for our Cairo program, using the Cairo Sharp prover :
cairo-sharp submit --program registryHash.json --program_input registryHashInput.json.Running... Submitting to SHARP... Job sent. Job key: e79ccff2-4376-4e9e-8b81-cc7e1fc86507 Fact: 0xc076e47e63f5f79c38cadfee3ef7fbe2eb70d45c22e0e7ae5d10344b5b32d392Here, we are telling to the Sharp Prover to compute our inputs with our program and to produce a
Factmatchinghash(programHash, programOutputs). Our smartcontract will be able to check if thisfactis valid with the prover's own smartContract, by calling theisValid(fact)function.
Our smartcontract will have to recompute the fact from the output, just to be sure.
We can usecairo-sharp status e79ccff2-4376-4e9e-8b81-cc7e1fc86507to check if the job has been processed (is live onChain).PROCESSEDNow we can submit our transaction to the smartContract in order to confirm the proof with the following tx:
updateRegistry( 123456, 0, 2672368424450419303116754025943367656383112088074817038016074650154564643 )
⚠️ If the number2672368424450419303116754025943367656383112088074817038016074650154564643is negative, we would have to convert it to it's positive countervalue by doing the following math :hex(MY_NEGATIVE_NUMBER + 2**251 + 17*2**192 + 1)in order to work with Cairo's Prime & pedersen hashes.The transaction can be found here. We now have some users in out registry.
Yeah new users.
ADDRESS (secret) ENCRYPTED_ADDRESS ENCRYPTION_KEY 0x9E63B020ae098E73cF201EE1357EDc72DFEaA5180x2c3dfa2e5c789f23006973dabc65c817704156344d2fb49aac7f237fb96c6ab32620168903161224964759659077543614782997442459750294261200535418828773199170xf51f06C26cA59954Ddce132E2a8EB026B01166580x3da30f7925ce33a7e93b186b8bd52ff7f64c52a42d79bebe891e132cb3d2b771953370059234117649198160759513056361430396932740856017941367296144751022849So updated JSON :
{ "oldRegistry": [ "0x6a3044f3172368c38bf9e73393275fd7e50a5e951ff8c09e4dd7b22d95a34f5", "0x6ed120ae443c419aee7e3ee2c98575edef4612ad381fe88d817f04e9e5911ae", "0x138e341ac1472ad700053c6a0e0fcdf41e7e4851ba2917fa9075f5e31e5ee2e", "0x755bf706ee73a22d3720569d0d3e4a7f9d28de4993a3b9c98014831c520a210", "0x53465c95bcfb00da727a9ffd24c5bf324329de9fc27c57e53a86a23cfda1044", "0x84afc9b9cdd81df7574ff788449dc3b6c0d6b5cf8a8f8f7536332d28b0add9" ], "newRegistry": [ "0x6a3044f3172368c38bf9e73393275fd7e50a5e951ff8c09e4dd7b22d95a34f5", "0x6ed120ae443c419aee7e3ee2c98575edef4612ad381fe88d817f04e9e5911ae", "0x138e341ac1472ad700053c6a0e0fcdf41e7e4851ba2917fa9075f5e31e5ee2e", "0x755bf706ee73a22d3720569d0d3e4a7f9d28de4993a3b9c98014831c520a210", "0x53465c95bcfb00da727a9ffd24c5bf324329de9fc27c57e53a86a23cfda1044", "0x84afc9b9cdd81df7574ff788449dc3b6c0d6b5cf8a8f8f7536332d28b0add9", "0x2c3dfa2e5c789f23006973dabc65c817704156344d2fb49aac7f237fb96c6ab", "0x3da30f7925ce33a7e93b186b8bd52ff7f64c52a42d79bebe891e132cb3d2b77" ] }So new output
Program output: 2672368424450419303116754025943367656383112088074817038016074650154564643 -727187437430369499786061208688114383190983125936168187665846498250270412883So new sharp
Running... Submitting to SHARP... Job sent. Job key: 3967b1f1-e994-426f-9872-485bb1eb612e Fact: 0xba3365415dd3f5d4e92c4055cfb48eb561d773fe3e58a603db07dc692aef6cf5So new TX (with the prime dark magic)
updateRegistry( 123456, 2672368424450419303116754025943367656383112088074817038016074650154564643, 2891315351235761713911261574406955722432124089395428512307245557885601607598 )And the TX is here, with a new hash in the smartContract for the registryKey
123456:2891315351235761713911261574406955722432124089395428512307245557885601607598
In order to prove that I am in this registry, we will use the second Cairo Program (the one with the following hash:
0x505ae0c3821ab690edb0fe45a63615f3600e168f3e60da824af1f28df54ecb1). The idea is to prove that from my address and my secret (I am the only one to know theses information), I can retrieve one of the entry on the registry.
In order to do that we will need a new input file with mysecret, myaddress, and the public registry of all the addresses registered.
Let's say my address is0x9E63B020ae098E73cF201EE1357EDc72DFEaA518. With the table above, we can retrieve my secret, aka3262016890316122496475965907754361478299744245975029426120053541882877319917. Obviously, theses information are here only for the purpose of this example.{ "secret": "3262016890316122496475965907754361478299744245975029426120053541882877319917", "address": "0x9E63B020ae098E73cF201EE1357EDc72DFEaA518", "registry": [ "0x6a3044f3172368c38bf9e73393275fd7e50a5e951ff8c09e4dd7b22d95a34f5", "0x6ed120ae443c419aee7e3ee2c98575edef4612ad381fe88d817f04e9e5911ae", "0x138e341ac1472ad700053c6a0e0fcdf41e7e4851ba2917fa9075f5e31e5ee2e", "0x755bf706ee73a22d3720569d0d3e4a7f9d28de4993a3b9c98014831c520a210", "0x53465c95bcfb00da727a9ffd24c5bf324329de9fc27c57e53a86a23cfda1044", "0x84afc9b9cdd81df7574ff788449dc3b6c0d6b5cf8a8f8f7536332d28b0add9", "0x2c3dfa2e5c789f23006973dabc65c817704156344d2fb49aac7f237fb96c6ab", "0x3da30f7925ce33a7e93b186b8bd52ff7f64c52a42d79bebe891e132cb3d2b77" ] }With this
input.jsonfile, I can run the following command to get the output bellow :cairo-run --program=cairo.json --print_output --layout=small --program_input=input.json.Program output: 829738850691260145934808358025321514871032962339753968951012900191018601261 -727187437430369499786061208688114383190983125936168187665846498250270412883This output contains 2 information needed to prove the information :
829738850691260145934808358025321514871032962339753968951012900191018601261is a specific hash corresponding to the element in the registry I match + my secret. In our case it'shash(0x2c3dfa2e5c789f23006973dabc65c817704156344d2fb49aac7f237fb96c6ab, 3262016890316122496475965907754361478299744245975029426120053541882877319917).-727187437430369499786061208688114383190983125936168187665846498250270412883is the registry hash.Just like we did for the registry update, we will prove this with the Sharp Prover with
cairo-sharp submit --program cairo.json --program_input input.jsonRunning... Submitting to SHARP... Job sent. Job key: 866a23ce-2320-4233-99cc-9dd06ad7c889 Fact: 0xabab4d2b54dd76e3b6095d6b9a1351aace18e8e9f07696e5f9d00c2a8d689bcaAnd then, we will submit a new transaction to prove our fact :
proveIdentity( 123456, 829738850691260145934808358025321514871032962339753968951012900191018601261, 2891315351235761713911261574406955722432124089395428512307245557885601607598 )And the transaction is proved. That's it.