Skip to content

Commit 2d8d955

Browse files
Brechtpddong77
authored andcommitted
[Protocol3] Verifier fixes + snark field overflow checks (#310)
* [Protocol3] Verifier fixes + snark field overflow checks * [Protocol3] Improvements to snark field checks + tests * [Protocol3] Fixed some comments * [Protocol3] Added comment for the snark scalar field prime * [Protocol3] Fixed typo * Update ExchangeData.sol * Update ExchangeData.sol * Update BatchVerifier.sol
1 parent ab62fcb commit 2d8d955

File tree

13 files changed

+115
-304
lines changed

13 files changed

+115
-304
lines changed

packages/loopring_v3/contracts/impl/libexchange/ExchangeBlocks.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,9 @@ library ExchangeBlocks
122122
"PROOF_TOO_LATE"
123123
);
124124

125-
// Maybe we should strip the highest bits of the public input so we don't have any overflow (uint/prime field)
126-
publicInputs[i] = uint(specifiedBlock.publicDataHash);
125+
// Strip the 3 least significant bits of the public data hash
126+
// so we don't have any overflow in the snark field
127+
publicInputs[i] = uint(specifiedBlock.publicDataHash) >> 3;
127128
if (i == 0) {
128129
blockSize = specifiedBlock.blockSize;
129130
blockType = specifiedBlock.blockType;

packages/loopring_v3/contracts/impl/libexchange/ExchangeData.sol

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ library ExchangeData
164164
function GENESIS_MERKLE_ROOT() internal pure returns (bytes32) {
165165
return 0x2b4827daf74c0ab30deb68b1c337dec40579bb3ff45ce9478288e1a2b83a3a01;
166166
}
167+
168+
function SNARK_SCALAR_FIELD() internal pure returns (uint) {
169+
// This is the prime number that is used for the alt_bn128 elliptic curve, see EIP-196.
170+
return 21888242871839275222246405745257275088548364400416034343698204186575808495617;
171+
}
167172
function MAX_PROOF_GENERATION_TIME_IN_SECONDS() internal pure returns (uint32) { return 1 hours; }
168173
function MAX_GAP_BETWEEN_FINALIZED_AND_VERIFIED_BLOCKS() internal pure returns (uint32) { return 2500; }
169174
function MAX_OPEN_DEPOSIT_REQUESTS() internal pure returns (uint16) { return 1024; }

packages/loopring_v3/contracts/impl/libexchange/ExchangeDeposits.sol

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ library ExchangeDeposits
118118
feeETH
119119
);
120120

121+
// Make sure the public key can be stored in the SNARK field
122+
require(account.pubKeyX < ExchangeData.SNARK_SCALAR_FIELD(), "INVALID_PUBKEY");
123+
require(account.pubKeyY < ExchangeData.SNARK_SCALAR_FIELD(), "INVALID_PUBKEY");
124+
121125
// Add the request to the deposit chain
122126
ExchangeData.Request storage prevRequest = S.depositChain[S.depositChain.length - 1];
123127
ExchangeData.Request memory request = ExchangeData.Request(

packages/loopring_v3/contracts/lib/Poseidon.sol

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,14 @@ library Poseidon
3434
pure
3535
returns (uint)
3636
{
37+
uint q = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
38+
// Make sure the inputs can be stored in the SNARK field
39+
require(t0 < q, "INVALID_INPUT");
40+
require(t1 < q, "INVALID_INPUT");
41+
require(t2 < q, "INVALID_INPUT");
42+
require(t3 < q, "INVALID_INPUT");
43+
require(t4 < q, "INVALID_INPUT");
44+
3745
assembly {
3846
function mix(t0, t1, t2, t3, t4, q) -> nt0, nt1, nt2, nt3, nt4 {
3947
nt0 := mulmod(t0, 4977258759536702998522229302103997878600602264560359702680165243908162277980, q)
@@ -95,8 +103,6 @@ library Poseidon
95103
nt := mulmod(t, nt, q)
96104
}
97105

98-
let q := 21888242871839275222246405745257275088548364400416034343698204186575808495617
99-
100106
// round 0
101107
t0, t1, t2, t3, t4 := ark(t0, t1, t2, t3, t4, q, 14397397413755236225575615486459253198602422701513067526754101844196324375522)
102108
t0, t1, t2, t3, t4 := sbox_full(t0, t1, t2, t3, t4, q)

packages/loopring_v3/contracts/thirdparty/BatchVerifier.sol

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ library BatchVerifier {
2727
)
2828
internal pure returns (uint256)
2929
{
30+
// Truncate the least significant 3 bits from the 256bit entropy so it fits the scalar field
3031
return uint256(
3132
keccak256(
3233
abi.encodePacked(
@@ -35,7 +36,7 @@ library BatchVerifier {
3536
proof_inputs[proofNumber]
3637
)
3738
)
38-
);
39+
) >> 3;
3940
}
4041

4142
function accumulate(
@@ -64,6 +65,7 @@ library BatchVerifier {
6465
// here multiplication by 1 is implied
6566
inputAccumulators[0] = addmod(inputAccumulators[0], entropy[proofNumber], q);
6667
for (uint256 i = 0; i < numPublicInputs; i++) {
68+
require(proof_inputs[proofNumber * numPublicInputs + i] < q, "INVALID_INPUT");
6769
// accumulate the exponent with extra entropy mod q
6870
inputAccumulators[i+1] = addmod(inputAccumulators[i+1], mulmod(entropy[proofNumber], proof_inputs[proofNumber * numPublicInputs + i], q), q);
6971
}
@@ -81,6 +83,7 @@ library BatchVerifier {
8183
proofsAandC[1] = in_proof[1];
8284

8385
for (uint256 proofNumber = 1; proofNumber < num_proofs; proofNumber++) {
86+
require(entropy[proofNumber] < q, "INVALID_INPUT");
8487
mul_input[0] = in_proof[proofNumber*8];
8588
mul_input[1] = in_proof[proofNumber*8 + 1];
8689
mul_input[2] = entropy[proofNumber];
@@ -269,4 +272,4 @@ library BatchVerifier {
269272
}
270273
return success && out[0] == 1;
271274
}
272-
}
275+
}

packages/loopring_v3/contracts/thirdparty/Pairing.sol

Lines changed: 0 additions & 192 deletions
This file was deleted.

packages/loopring_v3/contracts/thirdparty/Verifier.sol

Lines changed: 4 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,18 @@
1+
// This code is taken from https://github.com/HarryR/ethsnarks/blob/master/contracts/Verifier.sol
12
// this code is taken from https://github.com/JacobEberhardt/ZoKrates
23

34
pragma solidity 0.5.7;
45

5-
import "./Pairing.sol";
6-
76
library Verifier
87
{
9-
using Pairing for Pairing.G1Point;
10-
using Pairing for Pairing.G2Point;
11-
128
function ScalarField ()
13-
public
9+
internal
1410
pure
1511
returns (uint256)
1612
{
1713
return 21888242871839275222246405745257275088548364400416034343698204186575808495617;
1814
}
1915

20-
struct VerifyingKey
21-
{
22-
Pairing.G1Point alpha;
23-
Pairing.G2Point beta;
24-
Pairing.G2Point gamma;
25-
Pairing.G2Point delta;
26-
Pairing.G1Point[] gammaABC;
27-
}
28-
29-
struct Proof
30-
{
31-
Pairing.G1Point A;
32-
Pairing.G2Point B;
33-
Pairing.G1Point C;
34-
}
35-
36-
struct ProofWithInput
37-
{
38-
Proof proof;
39-
uint256[] input;
40-
}
41-
42-
4316
function NegateY( uint256 Y )
4417
internal pure returns (uint256)
4518
{
@@ -102,6 +75,7 @@ library Verifier
10275
view
10376
returns (bool)
10477
{
78+
uint256 snark_scalar_field = 21888242871839275222246405745257275088548364400416034343698204186575808495617;
10579
require(((vk_gammaABC.length / 2) - 1) == proof_inputs.length, "INVALID_VALUE");
10680

10781
// Compute the linear combination vk_x
@@ -116,6 +90,7 @@ library Verifier
11690

11791
// Performs a sum of gammaABC[0] + sum[ gammaABC[i+1]^proof_inputs[i] ]
11892
for (uint i = 0; i < proof_inputs.length; i++) {
93+
require(proof_inputs[i] < snark_scalar_field, "INVALID_INPUT");
11994
mul_input[0] = vk_gammaABC[m++];
12095
mul_input[1] = vk_gammaABC[m++];
12196
mul_input[2] = proof_inputs[i];
@@ -161,41 +136,4 @@ library Verifier
161136
}
162137
return success && out[0] != 0;
163138
}
164-
165-
166-
function Verify(
167-
VerifyingKey memory vk,
168-
ProofWithInput memory pwi
169-
)
170-
internal
171-
view
172-
returns (bool)
173-
{
174-
return Verify(vk, pwi.proof, pwi.input);
175-
}
176-
177-
178-
function Verify(
179-
VerifyingKey memory vk,
180-
Proof memory proof,
181-
uint256[] memory input
182-
)
183-
internal
184-
view
185-
returns (bool)
186-
{
187-
require(input.length + 1 == vk.gammaABC.length, "INVALID_VALUE");
188-
189-
// Compute the linear combination vk_x
190-
Pairing.G1Point memory vk_x = vk.gammaABC[0];
191-
for (uint i = 0; i < input.length; i++)
192-
vk_x = Pairing.pointAdd(vk_x, Pairing.pointMul(vk.gammaABC[i + 1], input[i]));
193-
194-
// Verify proof
195-
return Pairing.pairingProd4(
196-
proof.A, proof.B,
197-
vk_x.negate(), vk.gamma,
198-
proof.C.negate(), vk.delta,
199-
vk.alpha.negate(), vk.beta);
200-
}
201139
}

0 commit comments

Comments
 (0)