Skip to content

invocamanman/zksafeSpanishMafia

 
 

Repository files navigation

Team

Hi, we are Héctor, Jesus, Roger and Ignasi. We are experienced blockchain developers currently working in different zk fields.

Project description

This project is an in-depth exploration of account abstraction. The combination of Safe's ERC7579 interface and Noir's secp256r1 signature verification offers a promising opportunity to significantly enhance user experience, privacy, and security.

Multisignature setups present challenges. Not only can individuals be exposed during voting, but they may also face physical threats or theft, potentially compromising an entire DAO or even a Layer 2 network. This is not without precedent; the largest theft in history occurred due to a breach of a 5-out-of-9 multisig.

Our project ensures complete user privacy, as the actual owners of the Safe remain undisclosed.

Our project makes the user (safe signers/owners) completely private: no one sees the actual owners of the Safe.

The following application uses zkVerify to verify a proof generated by UltraPlonk verifier. The proof is done with zkSafe. zkSafe uses gnosis safe multisig wallet but with some additional features, it can hide who signed a particular transaction, but doesn't hide who are the Safe owners. With our approach we have implemented a feature to hide those owners.

How it's Made

There are three major components to the whole project: Noir, zkSafe module and zkVerify.

Noir

Noir is a Zero-Knowledge domain specific language that provides an easy Rust-like abstraction layer, interfaces natively with Aztec's Barretenberg backend, and provides a handy Solidity contract for proof verification. The Noir standard library contains a secp256r1 signature verification method, which happens to be a supported curve for a lot of elliptic curve cryptography around us. With it, we could not only make a succint proof that a provided public key can be recovered from a signature, but also keep all that information completely private!

zkSafe

zkSafe allows Safe owners to collectively sign transactions, without revealing who exactly signed it. The zkSafe module only ensures that there's a proof of: At least threshold number of valid transactions signatures That are pairwise disinct (i.e. you can't reach threshold by including the signature twice) Each of which is done by one of the Safe's owners. Once the module sees such a proof accompanying a Safe transaction, the module can safely execute it.

zkVerify

zkVerify is a blockchain designed to provide zero knowledge proof verifications for any project or dApp using zero knowledge proofs. A high performance, public, decentralized, reliable, and secure blockchain, zkVerify has dedicated proof verification methods written in Rust, and available to be used in a modular and composable way.

Project specs

zkVerify

Implementation noir files:

/circuits/zkSafe/src/main.nr
/circuits/verify_signers/src/lib.nr

From those files, and noir libs we generated the proof. The proof can be found at `PROOF_PATH`` We run the following commands to generate the Proving artifacts:

cd circuits/zkSafe
noir-cli key --input ./contract/circuits/plonk_vk.sol --output ./target/vk.bin
noir-cli proof-data --input-json ./proof.json --output-proof ./target/proof.bin --output-pubs ./target/pubs.bin
noir-cli verify --key ./target/vk.bin --proof ./target/proof.bin --pubs ./target/pubs.bin

To make sure the proving artifacts are generated correctly, run:

noir-cli verify --key ./target/vk.bin --proof ./target/proof.bin --pubs ./target/pubs.bin

After having generated the proving artifacts we have forked and modified the zkverify-example-script to support the ultraPlonk verifier in this fork:

https://github.com/ignasirv/zkverify-example-typescript/tree/ultraplonk_verifier

After submitted the ultraPlonk proof to zkVerifier the results are the following:

generating the proof for ultraPlonk
index.ts:29
Sending ultraPlonk proof to zkVerify for verification...
index.ts:58
Valid ultraPlonk Transaction included in block 0x145757adfd3dba468be04535be156836fd33326ecfb39f995df143515b67834e (elapsed time: 3.485 seconds)
index.ts:51
Valid ultraPlonk Proof Verified:
  - Attestation Id: 6458
  - Proof Leaf: 0x988a140b9c0468d2147b7dd4db8f617db7a7b38bb0f6c15a37c1a29a9f61a7f5
index.ts:55
Waiting for Valid ultraPlonk transaction to finalize... (elapsed time: 8.492 seconds)
index.ts:175
Waiting for Valid ultraPlonk transaction to finalize... (elapsed time: 13.489 seconds)
index.ts:175
Waiting for Valid ultraPlonk transaction to finalize... (elapsed time: 18.49 seconds)
index.ts:175
Valid ultraPlonk Transaction finalized (elapsed time: 20.235 seconds)
index.ts:81
Waiting for NewAttestation event... (elapsed time: 35.236 seconds)
index.ts:64
Waiting for NewAttestation event... (elapsed time: 50.237 seconds)
index.ts:64
Waiting for NewAttestation event... (elapsed time: 65.238 seconds)
index.ts:64
Matched NewAttestation event with attestation ID: 6458
index.ts:79
	u64: 6458
index.ts:81
	H256: 0x78ccbf98e8b37d9f078ffd480da89655bbe1e57865f819a21b974de197d5d751
index.ts:81
Sent 1 proof, elapsed time: 68.95s, result: succeeded, attestationId: 6458

Finally we have verified the generated proof to zkVerify blockchain with ultraPlonk!!

Modify zkSafe to hide Safe owners and adding recursion

This project modifies the zkSafe circuits and contracts so that owners are also hidden. To achieve that, we have created a MerkleTree of owners with TREE_WIDTH=32. Then, only the merkle root (which is called owners_root) is stored in the smart contract and sent as public input of the circuit. Inside the circuit, it is enough to check that each of the signers is included in the merkle tree by verifying its siblings path.

To accomplish this, we have implemented in Noir a function to verify a merkle tree leaf. It can be found inside circuits/verify_signers/src/lib.nr. The merkle tree is built using Poseidon hash.

To fulfill the requirements, we have modified verify_signers circuits. Instead of sending an array of owners, we provide for each of the signers its merkle path and the leaf index (which are private inputs). We also provide the owners_root as a public input which is obtained from the smart contract.

We have been able to generate and verify a proof of the noir circuit via command line, and using the inputs inside circuit/verify_signers/Prover.toml. We have been unable to run the test in Typescript due to the size of the circuit (our circuit size is 2**20). This is a known issue AztecProtocol/aztec-packages#7554

Recursive Proving

Using the circuit described above, we have created the circuits to be able to verify recursively an arbitrary number of owners and signers via recursive proving.

Firstly, we have slightly modified the verify_signers circuit so that the threshold is not sent as a parameter anymore, and the circuit has one public output, which is the number of verified signatures. For each signature, the signer need to provide its leaf index and merkle path.

Then, we have added two recursive circuits.

  • Recursion: It adds a verify_signers proof with and proves a new set of signers. It then returns as a public output the total number of verified signers so far.

  • Nested Recursion: It adds a recursive proof and proves a new set of signers. It then returns as a public output the total number of verifier signers so far.

Notice that we have had to create two separate circuits since the proof size differs.

Finally, this public output is verified against the threshold in the Smart contract and also used to verify the last recursive proof.

We have been unable to finish the testing due to the issue mentioned above

Problems we faced

With the proof, we followed the the instructions at https://docs.zkverify.io/tutorials/submit-proofs/noir-ultraplonk-example We got stuck with an issue, when running noir-cli key --input ./contract/hello_world/plonk_vk.sol --output ./target/vk.bin I get error Error: CLI Error: Failed to parse Solidity file: CliError("Failed to parse verification key: InvalidCommitmentKey { offset: 20 }") ---> It seems it was a bug at ultraplonk_verifier repo, it was fixed at branch `fix/noir-cli-key``

When running nargo prove its taking a lot of time, we think is because the usage of keccak is generating too many constrains For the scope of this hackathon and with our laptop hardware has been impossible for us to generate the proof so we will use a simple proof got from noir's hello world to continue with the verification process of zkVerify and for the sake of simplicity. We added all the necessary files at /circuits/helloWorld

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • Solidity 79.9%
  • TypeScript 11.2%
  • Jupyter Notebook 5.7%
  • Roff 1.2%
  • CSS 1.1%
  • JavaScript 0.9%