Skip to content

Commit

Permalink
feat(protocol): decouple proof(s) verification from core protocol (#1…
Browse files Browse the repository at this point in the history
…4221)

Co-authored-by: adaki2004 <adaki2004@users.noreply.github.com>
Co-authored-by: Daniel Wang <99078276+dantaik@users.noreply.github.com>
Co-authored-by: Daniel Wang <dong77@gmail.com>
  • Loading branch information
4 people authored Jul 29, 2023
1 parent 570ae10 commit 4b23d14
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 80 deletions.
10 changes: 5 additions & 5 deletions .github/workflows/protocol.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ jobs:
- name: protocol - Generate contract documentation
run: pnpm -F protocol export:docs

- name: protocol - Commit contract documentation
uses: stefanzweifel/git-auto-commit-action@v4
with:
commit_message: Add auto-generated contract documentation
file_pattern: "**/*.md"
# - name: protocol - Commit contract documentation
# uses: stefanzweifel/git-auto-commit-action@v4
# with:
# commit_message: Add auto-generated contract documentation
# file_pattern: "**/*.md"
24 changes: 24 additions & 0 deletions packages/protocol/contracts/L1/IProofVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: MIT
// _____ _ _ _ _
// |_ _|_ _(_) |_____ | | __ _| |__ ___
// | |/ _` | | / / _ \ | |__/ _` | '_ (_-<
// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/

pragma solidity ^0.8.20;

interface IProofVerifier {
/**
* Verifying proof via the ProofVerifier contract. This function must throw
* if verificaiton fails.
*
* @param blockId BlockId
* @param blockProofs Raw bytes of proof(s)
* @param instance Hashed evidence & config data
*/
function verifyProofs(
uint256 blockId,
bytes calldata blockProofs,
bytes32 instance
)
external;
}
69 changes: 69 additions & 0 deletions packages/protocol/contracts/L1/ProofVerifier.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// SPDX-License-Identifier: MIT
// _____ _ _ _ _
// |_ _|_ _(_) |_____ | | __ _| |__ ___
// | |/ _` | | / / _ \ | |__/ _` | '_ (_-<
// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/

pragma solidity ^0.8.20;

import { AddressResolver } from "../common/AddressResolver.sol";
import { EssentialContract } from "../common/EssentialContract.sol";
import { Proxied } from "../common/Proxied.sol";
import { LibVerifyZKP } from "./libs/proofTypes/LibVerifyZKP.sol";
import { IProofVerifier } from "./IProofVerifier.sol";
import { LibBytesUtils } from "../thirdparty/LibBytesUtils.sol";

/// @custom:security-contact hello@taiko.xyz
contract ProofVerifier is EssentialContract, IProofVerifier {
uint256[50] private __gap;

error L1_INVALID_PROOF();

function init(address _addressManager) external initializer {
EssentialContract._init(_addressManager);
}

/**
* Verifying proofs
*
* @param blockProofs Raw bytes of proof(s)
*/
function verifyProofs(
uint256, //Can be used later when supporting different types of proofs
bytes calldata blockProofs,
bytes32 instance
)
external
view
{
// Not checked if oracle/system prover
if (instance == 0) return;

if (
!LibBytesUtils.equal(
LibBytesUtils.slice(blockProofs, 2, 32),
bytes.concat(bytes16(0), bytes16(instance))
)
) {
revert L1_INVALID_PROOF();
}

if (
!LibBytesUtils.equal(
LibBytesUtils.slice(blockProofs, 34, 32),
bytes.concat(bytes16(0), bytes16(uint128(uint256(instance))))
)
) {
revert L1_INVALID_PROOF();
}

uint16 verifierId = uint16(bytes2(blockProofs[0:2]));

// Verify ZK proof
LibVerifyZKP.verifyProof(
AddressResolver(address(this)), blockProofs[2:], verifierId
);
}
}

contract ProxiedProofVerifier is Proxied, ProofVerifier { }
3 changes: 1 addition & 2 deletions packages/protocol/contracts/L1/TaikoData.sol
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ library TaikoData {
address prover;
uint32 parentGasUsed;
uint32 gasUsed;
uint16 verifierId;
bytes proof;
bytes proofs;
}

// 4 slots
Expand Down
109 changes: 39 additions & 70 deletions packages/protocol/contracts/L1/libs/LibProving.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { AddressResolver } from "../../common/AddressResolver.sol";
import { IProverPool } from "../ProverPool.sol";
import { LibMath } from "../../libs/LibMath.sol";
import { LibUtils } from "./LibUtils.sol";
import { IProofVerifier } from "../IProofVerifier.sol";
import { TaikoData } from "../../L1/TaikoData.sol";
import { LibBytesUtils } from "../../thirdparty/LibBytesUtils.sol";

library LibProving {
using LibMath for uint256;
Expand Down Expand Up @@ -142,85 +142,54 @@ library LibProving {
);
}

bytes32 instance;
if (evidence.prover != address(1)) {
bytes32 instance;
{
uint256[10] memory inputs;
uint256[10] memory inputs;

inputs[0] = uint256(
uint160(address(resolver.resolve("signal_service", false)))
);
inputs[1] = uint256(
uint160(
address(
resolver.resolve(
config.chainId, "signal_service", false
)
)
)
);
inputs[2] = uint256(
uint160(
address(
resolver.resolve(config.chainId, "taiko", false)
inputs[0] = uint256(
uint160(address(resolver.resolve("signal_service", false)))
);
inputs[1] = uint256(
uint160(
address(
resolver.resolve(
config.chainId, "signal_service", false
)
)
);

inputs[3] = uint256(evidence.metaHash);
inputs[4] = uint256(evidence.parentHash);
inputs[5] = uint256(evidence.blockHash);
inputs[6] = uint256(evidence.signalRoot);
inputs[7] = uint256(evidence.graffiti);
inputs[8] = (uint256(uint160(evidence.prover)) << 96)
| (uint256(evidence.parentGasUsed) << 64)
| (uint256(evidence.gasUsed) << 32);

// Also hash configs that will be used by circuits
inputs[9] = uint256(config.blockMaxGasLimit) << 192
| uint256(config.blockMaxTransactions) << 128
| uint256(config.blockMaxTxListBytes) << 64;

assembly {
instance := keccak256(inputs, mul(32, 10))
}
}

if (
!LibBytesUtils.equal(
LibBytesUtils.slice(evidence.proof, 0, 32),
bytes.concat(bytes16(0), bytes16(instance))
)
) {
revert L1_INVALID_PROOF();
}

if (
!LibBytesUtils.equal(
LibBytesUtils.slice(evidence.proof, 32, 32),
bytes.concat(
bytes16(0), bytes16(uint128(uint256(instance)))
)
);
inputs[2] = uint256(
uint160(
address(resolver.resolve(config.chainId, "taiko", false))
)
) {
revert L1_INVALID_PROOF();
}

(bool verified, bytes memory ret) = resolver.resolve(
LibUtils.getVerifierName(evidence.verifierId), false
).staticcall(evidence.proof);
);

if (
!verified
//
|| ret.length != 32
//
|| bytes32(ret) != keccak256("taiko")
) {
revert L1_INVALID_PROOF();
inputs[3] = uint256(evidence.metaHash);
inputs[4] = uint256(evidence.parentHash);
inputs[5] = uint256(evidence.blockHash);
inputs[6] = uint256(evidence.signalRoot);
inputs[7] = uint256(evidence.graffiti);
inputs[8] = (uint256(uint160(evidence.prover)) << 96)
| (uint256(evidence.parentGasUsed) << 64)
| (uint256(evidence.gasUsed) << 32);

// Also hash configs that will be used by circuits
inputs[9] = uint256(config.blockMaxGasLimit) << 192
| uint256(config.blockMaxTransactions) << 128
| uint256(config.blockMaxTxListBytes) << 64;

assembly {
instance := keccak256(inputs, mul(32, 10))
}
assert(instance != 0);
}

IProofVerifier(resolver.resolve("proof_verifier", false)).verifyProofs({
blockId: blockId,
blockProofs: evidence.proofs,
instance: instance
});

emit BlockProven({
blockId: blk.blockId,
parentHash: evidence.parentHash,
Expand Down
33 changes: 33 additions & 0 deletions packages/protocol/contracts/L1/libs/proofTypes/LibVerifyZKP.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// SPDX-License-Identifier: MIT
// _____ _ _ _ _
// |_ _|_ _(_) |_____ | | __ _| |__ ___
// | |/ _` | | / / _ \ | |__/ _` | '_ (_-<
// |_|\__,_|_|_\_\___/ |____\__,_|_.__/__/

pragma solidity ^0.8.20;

import { AddressResolver } from "../../../common/AddressResolver.sol";
import { LibUtils } from "../LibUtils.sol";
import { TaikoData } from "../../TaikoData.sol";

library LibVerifyZKP {
error L1_INVALID_PROOF();

function verifyProof(
AddressResolver resolver,
bytes memory proof,
uint16 verifierId
)
internal
view
{
(bool verified, bytes memory ret) = resolver.resolve(
LibUtils.getVerifierName(verifierId), false
).staticcall(bytes.concat(proof));

if (!verified || ret.length != 32 || bytes32(ret) != keccak256("taiko"))
{
revert L1_INVALID_PROOF();
}
}
}
13 changes: 10 additions & 3 deletions packages/protocol/test/TaikoL1TestBase.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { TaikoData } from "../contracts/L1/TaikoData.sol";
import { TaikoL1 } from "../contracts/L1/TaikoL1.sol";
import { TaikoToken } from "../contracts/L1/TaikoToken.sol";
import { IProverPool } from "../contracts/L1/IProverPool.sol";
import { ProofVerifier } from "../contracts/L1/ProofVerifier.sol";
import { SignalService } from "../contracts/signal/SignalService.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { AddressResolver } from "../contracts/common/AddressResolver.sol";
Expand Down Expand Up @@ -62,6 +63,7 @@ abstract contract TaikoL1TestBase is Test {
TaikoData.Config conf;
MockProverPool public proverPool;
uint256 internal logCount;
ProofVerifier public pv;

// Constants of the input - it is a workaround - most probably a
// forge/foundry issue. Issue link:
Expand Down Expand Up @@ -109,6 +111,10 @@ abstract contract TaikoL1TestBase is Test {
ss = new SignalService();
ss.init(address(addressManager));

pv = new ProofVerifier();
pv.init(address(addressManager));

registerAddress("proof_verifier", address(pv));
registerAddress("signal_service", address(ss));
registerAddress("ether_vault", address(L1EthVault));
registerAddress("prover_pool", address(proverPool));
Expand Down Expand Up @@ -212,13 +218,14 @@ abstract contract TaikoL1TestBase is Test {
prover: prover,
parentGasUsed: parentGasUsed,
gasUsed: gasUsed,
verifierId: 100,
proof: new bytes(100)
proofs: new bytes(102)
});

bytes32 instance = getInstance(conf, evidence);
uint16 verifierId = 100;

evidence.proof = bytes.concat(
evidence.proofs = bytes.concat(
bytes2(verifierId),
bytes16(0),
bytes16(instance),
bytes16(0),
Expand Down

0 comments on commit 4b23d14

Please sign in to comment.