Skip to content

Commit

Permalink
feat: separate data attest contract from verifier (#521)
Browse files Browse the repository at this point in the history
  • Loading branch information
ethan-crypto authored Oct 5, 2023
1 parent fefa5a1 commit 3cbf7f8
Show file tree
Hide file tree
Showing 10 changed files with 257 additions and 549 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,13 @@
{
"inputs": [
{
"internalType": "uint256[]",
"name": "instances",
"type": "uint256[]"
"internalType": "address",
"name": "verifier",
"type": "address"
},
{
"internalType": "bytes",
"name": "proof",
"name": "encoded",
"type": "bytes"
}
],
Expand Down
105 changes: 0 additions & 105 deletions abis/Verifier.json

This file was deleted.

57 changes: 46 additions & 11 deletions contracts/AttestData.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
pragma solidity ^0.8.20;

// This contract serves as a Data Attestation Verifier for the EZKL model.
// It is designed to read and attest to instances of proofs generated from a specified circuit.
Expand All @@ -11,10 +11,10 @@ pragma solidity ^0.8.17;
// 3. Static Calls: Makes static calls to fetch data from other contracts. See the `staticCall` method.
// 4. Field Element Conversion: The fixed-point representation is then converted into a field element modulo P using the `toFieldElement` method.
// 5. Data Attestation: The `attestData` method validates that the public instances match the data fetched and processed by the contract.
// 6. Proof Verification: The `verifyWithDataAttestation` method has a stubbed assembly block to integrate proof verification.
// 6. Proof Verification: The `verifyWithDataAttestation` method parses the instances out of the encoded calldata and calls the `attestData` method to validate the public instances,
// then calls the `verifyProof` method to verify the proof on the verifier.


contract DataAttestationVerifier {
contract DataAttestation {
/**
* @notice Struct used to make view only calls to accounts to fetch the data that EZKL reads from.
* @param the address of the account to make calls to
Expand Down Expand Up @@ -225,7 +225,7 @@ contract DataAttestationVerifier {
* @dev Make the account calls to fetch the data that EZKL reads from and attest to the data.
* @param instances - The public instances to the proof (the data in the proof that publicly accessible to the verifier).
*/
function attestData(uint256[] calldata instances) internal view {
function attestData(uint256[] memory instances) internal view {
require(
instances.length >= INPUT_CALLS + OUTPUT_CALLS,
"Invalid public inputs length"
Expand Down Expand Up @@ -259,13 +259,48 @@ contract DataAttestationVerifier {
}

function verifyWithDataAttestation(
uint256[] calldata instances,
bytes calldata proof
address verifier,
bytes memory encoded
) public view returns (bool) {
bool success = true;
bytes32[] memory transcript;
require(verifier.code.length > 0,"Address: call to non-contract");
bytes4 fnSelector;
uint256[] memory instances;
bytes memory paramData = new bytes(encoded.length - 4);
assembly {
/*
4 (fun sig) +
32 (verifier address) +
32 (offset encoded) +
32 (length encoded) = 100 bytes = 0x64
*/
fnSelector := calldataload(0x64)

mstore(add(paramData, 0x20), sub(mload(add(encoded, 0x20)), 4))
for {
let i := 0
} lt(i, sub(mload(encoded), 4)) {
i := add(i, 0x20)
} {
mstore(add(paramData, add(0x20, i)), mload(add(encoded, add(0x24, i))))
}
}
if (fnSelector == 0xaf83a18d) {
// abi decode verifyProof(address,bytes,uint256[])
(,,instances) = abi.decode(paramData, (address, bytes, uint256[]));
} else {
// abi decode verifyProof(bytes,uint256[])
(,instances) = abi.decode(paramData, (bytes, uint256[]));
}
attestData(instances);
assembly { /* This is where the proof verification happens*/ }
return success;

// static call the verifier contract to verify the proof
(bool success, bytes memory returndata) = verifier.staticcall(encoded);

if (success) {
return abi.decode(returndata, (bool));
} else {
revert("low-level call to verifier failed");
}

}
}
26 changes: 0 additions & 26 deletions contracts/VerifierBase.sol

This file was deleted.

67 changes: 58 additions & 9 deletions examples/notebooks/data_attest.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -537,12 +537,57 @@
"print(\"verified\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now create and then deploy a vanilla evm verifier."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"abi_path = 'test.abi'\n",
"sol_code_path = 'test.sol'\n",
"\n",
"res = ezkl.create_evm_verifier(\n",
" vk_path,\n",
" srs_path,\n",
" settings_path,\n",
" sol_code_path,\n",
" abi_path,\n",
" )\n",
"assert res == True"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import json\n",
"\n",
"addr_path_verifier = \"addr_verifier.txt\"\n",
"\n",
"res = ezkl.deploy_evm(\n",
" addr_path_verifier,\n",
" sol_code_path,\n",
" 'http://127.0.0.1:3030'\n",
")\n",
"\n",
"assert res == True"
]
},
{
"attachments": {},
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now create an EVM / `.sol` verifier that can be deployed on chain to verify submitted proofs and attest to on-chain EZKL inputs using a view function. Make sure to pass the `input_path` instead of the `witness_path` as the former contains the on-chain data that we are attesting to."
"With the vanilla verifier deployed, we can now create the data attestation contract, which will read in the instances from the calldata to the verifier, attest to them, call the verifier and then return the result. "
]
},
{
Expand All @@ -556,7 +601,7 @@
"sol_code_path = 'test.sol'\n",
"input_path = 'input.json'\n",
"\n",
"res = ezkl.create_evm_data_attestation_verifier(\n",
"res = ezkl.create_evm_data_attestation(\n",
" vk_path,\n",
" srs_path,\n",
" settings_path,\n",
Expand All @@ -581,10 +626,10 @@
"metadata": {},
"outputs": [],
"source": [
"addr_path = \"addr.txt\"\n",
"addr_path_da = \"addr_da.txt\"\n",
"\n",
"res = ezkl.deploy_da_evm(\n",
" addr_path,\n",
" addr_path_da,\n",
" input_path,\n",
" settings_path,\n",
" sol_code_path,\n",
Expand All @@ -606,16 +651,20 @@
"metadata": {},
"outputs": [],
"source": [
"# read the address from addr_path\n",
"addr = None\n",
"with open(addr_path, 'r') as f:\n",
"# read the verifier address\n",
"addr_verifier = None\n",
"with open(addr_path_verifier, 'r') as f:\n",
" addr = f.read()\n",
"#read the data attestation address\n",
"addr_da = None\n",
"with open(addr_path_da, 'r') as f:\n",
" addr_da = f.read()\n",
"\n",
"res = ezkl.verify_evm(\n",
" proof_path,\n",
" addr,\n",
" RPC_URL,\n",
" True\n",
" addr_da,\n",
")"
]
}
Expand All @@ -636,7 +685,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.9.6"
"version": "3.9.15"
},
"orig_nbformat": 4
},
Expand Down
14 changes: 7 additions & 7 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,8 +478,8 @@ pub enum Commands {
},
#[cfg(not(target_arch = "wasm32"))]
/// Creates an EVM verifier that attests to on-chain inputs for a single proof
#[command(name = "create-evm-da-verifier", arg_required_else_help = true)]
CreateEVMDataAttestationVerifier {
#[command(name = "create-evm-da", arg_required_else_help = true)]
CreateEVMDataAttestation {
/// The path to load the desired srs file from
#[arg(long)]
srs_path: PathBuf,
Expand Down Expand Up @@ -573,8 +573,8 @@ pub enum Commands {
optimizer_runs: usize,
},
#[cfg(not(target_arch = "wasm32"))]
#[command(name = "deploy-evm-da-verifier", arg_required_else_help = true)]
DeployEvmDataAttestationVerifier {
#[command(name = "deploy-evm-da", arg_required_else_help = true)]
DeployEvmDataAttestation {
/// The path to the .json data file, which should include both the network input (possibly private) and the network output (public input to the proof)
#[arg(short = 'D', long)]
data: PathBuf,
Expand Down Expand Up @@ -603,13 +603,13 @@ pub enum Commands {
proof_path: PathBuf,
/// The path to verfier contract's address
#[arg(long)]
addr: H160,
addr_verifier: H160,
/// RPC URL for an Ethereum node, if None will use Anvil but WON'T persist state
#[arg(short = 'U', long)]
rpc_url: Option<String>,
/// does the verifier use data attestation ?
#[arg(long, default_value = "false")]
data_attestation: bool,
#[arg(long)]
addr_da: Option<H160>,
},

/// Print the proof in hexadecimal
Expand Down
Loading

0 comments on commit 3cbf7f8

Please sign in to comment.