Skip to content

Commit 5c36b12

Browse files
Brechtpddong77
authored andcommitted
[Protocol3] Batched proof verification (#283)
* [Protocol3] Added batched proof verification (of the same circuit) * [Protocol3] Batched proof testing + improvements to BlockVerifier * [Protocol3] Test fixes for BlockVerifier changes * [Protocol3] Fixed tests * [Protocol3] Added basic BlockVerifier tests * [Protocol3] Added more tests for proof verification in BlockVerifier * Update .soliumignore * [Protocol3] Make BatchVerifier return true/false instead of throwing * [Protocol3] Removed unused solium exceptions * [Protocol3] Added some verifyBlocks tests + some docs fixes * [Protocol3] Rollback formatting changes * [Protocol3] More rollbacks of formatting changes * [Protocol3] Rolled back more formatting * Update .soliumignore * Update Exchange.sol * Update BlockVerifier.sol
1 parent 833a2ba commit 5c36b12

17 files changed

+1823
-348
lines changed

packages/loopring_v3/.soliumignore

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
node_modules
22
contracts/Migrations.sol
3-
contracts/thirdparty/MiMC.sol
4-
contracts/thirdparty/MerkleTree.sol
5-
contracts/thirdparty/Proxy.sol
3+
contracts/thirdparty
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
[{"constant":false,"inputs":[{"name":"blockType","type":"uint8"},{"name":"onchainDataAvailability","type":"bool"},{"name":"blockSize","type":"uint16"},{"name":"blockVersion","type":"uint8"},{"name":"vk","type":"uint256[18]"}],"name":"setVerifyingKey","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"blockType","type":"uint8"},{"name":"onchainDataAvailability","type":"bool"},{"name":"blockSize","type":"uint16"},{"name":"blockVersion","type":"uint8"},{"name":"publicDataHash","type":"bytes32"},{"name":"proof","type":"uint256[8]"}],"name":"verifyProof","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"blockType","type":"uint8"},{"name":"onchainDataAvailability","type":"bool"},{"name":"blockSize","type":"uint16"},{"name":"blockVersion","type":"uint8"}],"name":"canVerify","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"}]
1+
[{"constant":true,"inputs":[{"name":"blockType","type":"uint8"},{"name":"onchainDataAvailability","type":"bool"},{"name":"blockSize","type":"uint16"},{"name":"blockVersion","type":"uint8"},{"name":"publicInputs","type":"uint256[]"},{"name":"proofs","type":"uint256[]"}],"name":"verifyProofs","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"blockType","type":"uint8"},{"name":"onchainDataAvailability","type":"bool"},{"name":"blockSize","type":"uint16"},{"name":"blockVersion","type":"uint8"}],"name":"isCircuitEnabled","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"blockType","type":"uint8"},{"name":"onchainDataAvailability","type":"bool"},{"name":"blockSize","type":"uint16"},{"name":"blockVersion","type":"uint8"}],"name":"isCircuitRegistered","outputs":[{"name":"","type":"bool"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"blockType","type":"uint8"},{"name":"onchainDataAvailability","type":"bool"},{"name":"blockSize","type":"uint16"},{"name":"blockVersion","type":"uint8"},{"name":"vk","type":"uint256[18]"}],"name":"registerCircuit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"blockType","type":"uint8"},{"name":"onchainDataAvailability","type":"bool"},{"name":"blockSize","type":"uint16"},{"name":"blockVersion","type":"uint8"}],"name":"disableCircuit","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"blockType","type":"uint8"},{"indexed":false,"name":"onchainDataAvailability","type":"bool"},{"indexed":false,"name":"blockSize","type":"uint16"},{"indexed":false,"name":"blockVersion","type":"uint8"}],"name":"CircuitRegistered","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"blockType","type":"uint8"},{"indexed":false,"name":"onchainDataAvailability","type":"bool"},{"indexed":false,"name":"blockSize","type":"uint16"},{"indexed":false,"name":"blockVersion","type":"uint8"}],"name":"CircuitDisabled","type":"event"}]

packages/loopring_v3/ABI/version30/IExchange.abi

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

packages/loopring_v3/contracts/iface/IBlockVerifier.sol

Lines changed: 67 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,35 @@ pragma solidity 0.5.7;
2121
/// @author Brecht Devos - <[email protected]>
2222
contract IBlockVerifier
2323
{
24-
/// @dev Sets or updates the verifying key for the given block type
25-
/// and permutation.
24+
// -- Events --
25+
26+
event CircuitRegistered(
27+
uint8 blockType,
28+
bool onchainDataAvailability,
29+
uint16 blockSize,
30+
uint8 blockVersion
31+
);
32+
33+
event CircuitDisabled(
34+
uint8 blockType,
35+
bool onchainDataAvailability,
36+
uint16 blockSize,
37+
uint8 blockVersion
38+
);
39+
40+
// -- Public functions --
41+
42+
/// @dev Sets the verifying key for the specified circuit.
43+
/// Every block permutation needs its own circuit and thus its own set of
44+
/// verification keys. Only a limited number of block sizes per block
45+
/// type are supported.
2646
/// @param blockType The type of the block See @BlockType
2747
/// @param onchainDataAvailability True if the block expects onchain
2848
/// data availability data as public input, false otherwise
2949
/// @param blockSize The number of requests handled in the block
3050
/// @param blockVersion The block version (i.e. which circuit version needs to be used)
3151
/// @param vk The verification key
32-
function setVerifyingKey(
52+
function registerCircuit(
3353
uint8 blockType,
3454
bool onchainDataAvailability,
3555
uint16 blockSize,
@@ -38,47 +58,76 @@ contract IBlockVerifier
3858
)
3959
external;
4060

41-
/// @dev Checks if a block with the given parameters can be verified.
42-
/// Every block permutation needs its own circuit and thus its own set of
43-
/// verification keys. Only a limited number of blocks sizes per block
44-
/// type are supported.
61+
/// @dev Disables the use of the specified circuit.
62+
/// This will stop NEW blocks from using the given circuit, blocks that were already committed
63+
/// can still be verified.
4564
/// @param blockType The type of the block See @BlockType
4665
/// @param onchainDataAvailability True if the block expects onchain
4766
/// data availability data as public input, false otherwise
4867
/// @param blockSize The number of requests handled in the block
4968
/// @param blockVersion The block version (i.e. which circuit version needs to be used)
50-
/// @return True if the block can be verified, false otherwise
51-
function canVerify(
69+
function disableCircuit(
5270
uint8 blockType,
5371
bool onchainDataAvailability,
5472
uint16 blockSize,
5573
uint8 blockVersion
5674
)
57-
external
58-
view
59-
returns (bool);
75+
external;
6076

61-
/// @dev Verifies a block with the given public data and proof.
77+
/// @dev Verify blocks with the given public data and proofs.
6278
/// Verifying a block makes sure all requests handled in the block
6379
/// are correctly handled by the operator.
6480
/// @param blockType The type of block See @BlockType
6581
/// @param onchainDataAvailability True if the block expects onchain
6682
/// data availability data as public input, false otherwise
6783
/// @param blockSize The number of requests handled in the block
6884
/// @param blockVersion The block version (i.e. which circuit version needs to be used)
69-
/// @param publicDataHash The hash of all the public data
70-
/// @param proof The ZK proof that the block is correct
85+
/// @param publicInputs The hash of all the public data of the blocks
86+
/// @param proofs The ZK proofs proving that the blocks are correct
7187
/// @return True if the block is valid, false otherwise
72-
function verifyProof(
88+
function verifyProofs(
7389
uint8 blockType,
7490
bool onchainDataAvailability,
7591
uint16 blockSize,
7692
uint8 blockVersion,
77-
bytes32 publicDataHash,
78-
uint256[8] calldata proof
93+
uint256[] calldata publicInputs,
94+
uint256[] calldata proofs
7995
)
8096
external
8197
view
8298
returns (bool);
8399

100+
/// @dev Checks if a circuit with the specified parameters is registered.
101+
/// @param blockType The type of the block See @BlockType
102+
/// @param onchainDataAvailability True if the block expects onchain
103+
/// data availability data as public input, false otherwise
104+
/// @param blockSize The number of requests handled in the block
105+
/// @param blockVersion The block version (i.e. which circuit version needs to be used)
106+
/// @return True if the circuit is registered, false otherwise
107+
function isCircuitRegistered(
108+
uint8 blockType,
109+
bool onchainDataAvailability,
110+
uint16 blockSize,
111+
uint8 blockVersion
112+
)
113+
external
114+
view
115+
returns (bool);
116+
117+
/// @dev Checks if a circuit can still be used to commit new blocks.
118+
/// @param blockType The type of the block See @BlockType
119+
/// @param onchainDataAvailability True if the block expects onchain
120+
/// data availability data as public input, false otherwise
121+
/// @param blockSize The number of requests handled in the block
122+
/// @param blockVersion The block version (i.e. which circuit version needs to be used)
123+
/// @return True if the circuit is enabled, false otherwise
124+
function isCircuitEnabled(
125+
uint8 blockType,
126+
bool onchainDataAvailability,
127+
uint16 blockSize,
128+
uint8 blockVersion
129+
)
130+
external
131+
view
132+
returns (bool);
84133
}

packages/loopring_v3/contracts/iface/IExchange.sol

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -514,17 +514,20 @@ contract IExchange
514514
)
515515
external;
516516

517-
/// @dev Submit a ZK proof onchain to verify a previously committed block. Submitting an
517+
/// @dev Submits ZK proofs onchain to verify previously committed blocks. Submitting an
518518
/// invalid proof will not change the state of the exchange. Note that proofs can
519519
/// be submitted in a different order than the blocks themselves.
520520
///
521-
/// This method can be called by anyone with a valid proof.
521+
/// Multiple blocks can be verified at once (in any order) IF they use the same circuit.
522+
/// This function will throw if blocks using different circuits need to be verified.
522523
///
523-
/// @param blockIdx The 0-based index of the block to be verified with the given proof
524-
/// @param proof The ZK proof
525-
function verifyBlock(
526-
uint blockIdx,
527-
uint256[8] calldata proof
524+
/// This method can only be called by the operator.
525+
///
526+
/// @param blockIndices The 0-based index of the blocks to be verified with the given proofs
527+
/// @param proofs The ZK proof for all blockIndices (proofs.length % 8 == 0).
528+
function verifyBlocks(
529+
uint[] calldata blockIndices,
530+
uint256[] calldata proofs
528531
)
529532
external;
530533

packages/loopring_v3/contracts/impl/BlockVerifier.sol

Lines changed: 82 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,23 @@ import "../lib/Claimable.sol";
2323
import "../impl/libexchange/ExchangeData.sol";
2424

2525
import "../thirdparty/Verifier.sol";
26+
import "../thirdparty/BatchVerifier.sol";
2627

2728

2829
/// @title An Implementation of IBlockVerifier.
2930
/// @author Brecht Devos - <[email protected]>
3031
contract BlockVerifier is IBlockVerifier, Claimable
3132
{
32-
mapping (bool => mapping (uint8 => mapping (uint16 => mapping (uint8 => uint256[18])))) verificationKeys;
33+
struct Circuit
34+
{
35+
bool registered;
36+
bool enabled;
37+
uint256[18] verificationKey;
38+
}
39+
40+
mapping (bool => mapping (uint8 => mapping (uint16 => mapping (uint8 => Circuit)))) public circuits;
3341

34-
function setVerifyingKey(
42+
function registerCircuit(
3543
uint8 blockType,
3644
bool onchainDataAvailability,
3745
uint16 blockSize,
@@ -41,54 +49,110 @@ contract BlockVerifier is IBlockVerifier, Claimable
4149
external
4250
onlyOwner
4351
{
44-
// While vk[0] could be 0, we don't allow it so we can use this to easily check
45-
// if the verification key is set
46-
require(vk[0] != 0, "INVALID_DATA");
4752
bool dataAvailability = needsDataAvailability(blockType, onchainDataAvailability);
4853
require(dataAvailability == onchainDataAvailability, "NO_DATA_AVAILABILITY_NEEDED");
54+
Circuit storage circuit = circuits[onchainDataAvailability][blockType][blockSize][blockVersion];
55+
require(circuit.registered == false, "ALREADY_REGISTERED");
56+
4957
for (uint i = 0; i < 18; i++) {
50-
verificationKeys[onchainDataAvailability][blockType][blockSize][blockVersion][i] = vk[i];
58+
circuit.verificationKey[i] = vk[i];
5159
}
60+
circuit.registered = true;
61+
circuit.enabled = true;
62+
63+
emit CircuitRegistered(
64+
blockType,
65+
onchainDataAvailability,
66+
blockSize,
67+
blockVersion
68+
);
5269
}
5370

54-
function canVerify(
71+
function disableCircuit(
5572
uint8 blockType,
5673
bool onchainDataAvailability,
5774
uint16 blockSize,
5875
uint8 blockVersion
5976
)
6077
external
61-
view
62-
returns (bool)
78+
onlyOwner
6379
{
64-
bool dataAvailability = needsDataAvailability(blockType, onchainDataAvailability);
65-
return verificationKeys[dataAvailability][blockType][blockSize][blockVersion][0] != 0;
80+
Circuit storage circuit = circuits[onchainDataAvailability][blockType][blockSize][blockVersion];
81+
require(circuit.registered == true, "NOT_REGISTERED");
82+
require(circuit.enabled == true, "ALREADY_DISABLED");
83+
84+
circuit.enabled = false;
85+
86+
emit CircuitDisabled(
87+
blockType,
88+
onchainDataAvailability,
89+
blockSize,
90+
blockVersion
91+
);
6692
}
6793

68-
function verifyProof(
94+
function verifyProofs(
6995
uint8 blockType,
7096
bool onchainDataAvailability,
7197
uint16 blockSize,
7298
uint8 blockVersion,
73-
bytes32 publicDataHash,
74-
uint256[8] calldata proof
99+
uint256[] calldata publicInputs,
100+
uint256[] calldata proofs
75101
)
76102
external
77103
view
78104
returns (bool)
79105
{
80106
bool dataAvailability = needsDataAvailability(blockType, onchainDataAvailability);
81-
uint256[18] storage vk = verificationKeys[dataAvailability][blockType][blockSize][blockVersion];
107+
Circuit storage circuit = circuits[dataAvailability][blockType][blockSize][blockVersion];
108+
require(circuit.registered == true, "NOT_REGISTERED");
82109

110+
uint256[18] storage vk = circuit.verificationKey;
83111
uint256[14] memory _vk = [
84112
vk[0], vk[1], vk[2], vk[3], vk[4], vk[5], vk[6],
85113
vk[7], vk[8], vk[9], vk[10], vk[11], vk[12], vk[13]
86114
];
87115
uint256[4] memory _vk_gammaABC = [vk[14], vk[15], vk[16], vk[17]];
88-
// Maybe we should strip the highest bits of the hash so we don't have any overflow (uint256/prime field)
89-
uint256[1] memory publicInputs = [uint256(publicDataHash)];
90116

91-
return Verifier.Verify(_vk, _vk_gammaABC, proof, publicInputs);
117+
if (publicInputs.length == 1) {
118+
return Verifier.Verify(_vk, _vk_gammaABC, proofs, publicInputs);
119+
} else {
120+
return BatchVerifier.BatchVerify(
121+
_vk,
122+
_vk_gammaABC,
123+
proofs,
124+
publicInputs,
125+
publicInputs.length
126+
);
127+
}
128+
}
129+
130+
function isCircuitRegistered(
131+
uint8 blockType,
132+
bool onchainDataAvailability,
133+
uint16 blockSize,
134+
uint8 blockVersion
135+
)
136+
external
137+
view
138+
returns (bool)
139+
{
140+
bool dataAvailability = needsDataAvailability(blockType, onchainDataAvailability);
141+
return circuits[dataAvailability][blockType][blockSize][blockVersion].registered;
142+
}
143+
144+
function isCircuitEnabled(
145+
uint8 blockType,
146+
bool onchainDataAvailability,
147+
uint16 blockSize,
148+
uint8 blockVersion
149+
)
150+
external
151+
view
152+
returns (bool)
153+
{
154+
bool dataAvailability = needsDataAvailability(blockType, onchainDataAvailability);
155+
return circuits[dataAvailability][blockType][blockSize][blockVersion].enabled;
92156
}
93157

94158
function needsDataAvailability(

packages/loopring_v3/contracts/impl/Exchange.sol

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -430,15 +430,15 @@ contract Exchange is IExchange, Claimable, ReentrancyGuard
430430
state.commitBlock(blockType, blockSize, blockVersion, decompressed, offchainData);
431431
}
432432

433-
function verifyBlock(
434-
uint blockIdx,
435-
uint256[8] calldata proof
433+
function verifyBlocks(
434+
uint[] calldata blockIndices,
435+
uint[] calldata proofs
436436
)
437437
external
438438
nonReentrant
439439
onlyOperator
440440
{
441-
state.verifyBlock(blockIdx, proof);
441+
state.verifyBlocks(blockIndices, proofs);
442442
}
443443

444444
function revertBlock(

0 commit comments

Comments
 (0)