-
Notifications
You must be signed in to change notification settings - Fork 18
/
Copy pathFriStatementContract.sol
142 lines (119 loc) · 5.52 KB
/
FriStatementContract.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
Copyright 2019-2022 StarkWare Industries Ltd.
Licensed under the Apache License, Version 2.0 (the "License").
You may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.starkware.co/open-source-license/
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions
and limitations under the License.
*/
// SPDX-License-Identifier: Apache-2.0.
pragma solidity ^0.6.12;
import "./components/FactRegistry.sol";
import "./FriLayer.sol";
contract FriStatementContract is FriLayer, FactRegistry {
/*
Compute a single FRI layer of size friStepSize at evaluationPoint starting from input
friQueue, and the extra witnesses in the "proof" channel. Also check that the input and
witnesses belong to a Merkle tree with root expectedRoot, again using witnesses from "proof".
After verification, register the FRI fact hash, which is:
keccak256(
evaluationPoint,
friStepSize,
keccak256(friQueue_input),
keccak256(friQueue_output), // The FRI queue after proccessing the FRI layer
expectedRoot
)
Note that this function is used as external, but declared public to avoid copying the arrays.
*/
function verifyFRI(
uint256[] memory proof,
uint256[] memory friQueue,
uint256 evaluationPoint,
uint256 friStepSize,
uint256 expectedRoot
) public {
require(friStepSize <= FRI_MAX_STEP_SIZE, "FRI step size too large");
// Verify evaluation point within valid range.
require(evaluationPoint < K_MODULUS, "INVALID_EVAL_POINT");
// Validate the FRI queue.
validateFriQueue(friQueue);
uint256 mmFriCtxSize = FRI_CTX_SIZE;
uint256 nQueries = friQueue.length / 3; // NOLINT: divide-before-multiply.
uint256 merkleQueuePtr;
uint256 friQueuePtr;
uint256 channelPtr;
uint256 friCtx;
uint256 dataToHash;
// Allocate memory queues: channelPtr, merkleQueue, friCtx, dataToHash.
assembly {
friQueuePtr := add(friQueue, 0x20)
channelPtr := mload(0x40) // Free pointer location.
mstore(channelPtr, add(proof, 0x20))
merkleQueuePtr := add(channelPtr, 0x20)
friCtx := add(merkleQueuePtr, mul(0x40, nQueries))
dataToHash := add(friCtx, mmFriCtxSize)
mstore(0x40, add(dataToHash, 0xa0)) // Advance free pointer.
mstore(dataToHash, evaluationPoint)
mstore(add(dataToHash, 0x20), friStepSize)
mstore(add(dataToHash, 0x80), expectedRoot)
// Hash FRI inputs and add to dataToHash.
mstore(add(dataToHash, 0x40), keccak256(friQueuePtr, mul(0x60, nQueries)))
}
initFriGroups(friCtx);
nQueries = computeNextLayer(
channelPtr,
friQueuePtr,
merkleQueuePtr,
nQueries,
friCtx,
evaluationPoint,
2**friStepSize /* friCosetSize = 2**friStepSize */
);
verifyMerkle(channelPtr, merkleQueuePtr, bytes32(expectedRoot), nQueries);
bytes32 factHash;
assembly {
// Hash FRI outputs and add to dataToHash.
mstore(add(dataToHash, 0x60), keccak256(friQueuePtr, mul(0x60, nQueries)))
factHash := keccak256(dataToHash, 0xa0)
}
registerFact(factHash);
}
/*
Validates the entries of the FRI queue.
The friQueue should have of 3*nQueries + 1 elements, beginning with nQueries triplets
of the form (query_index, FRI_value, FRI_inverse_point), and ending with a single buffer
cell set to 0, which is accessed and read during the computation of the FRI layer.
Queries need to be in the range [2**height .. 2**(height+1)-1] and strictly incrementing.
The FRI values and inverses need to be smaller than K_MODULUS.
*/
function validateFriQueue(uint256[] memory friQueue) private pure {
require(
friQueue.length % 3 == 1,
"FRI Queue must be composed of triplets plus one delimiter cell"
);
require(friQueue.length >= 4, "No query to process");
// Force delimiter cell to 0, this is cheaper then asserting it.
friQueue[friQueue.length - 1] = 0;
// We need to check that Qi+1 > Qi for each i,
// Given that the queries are sorted the height range requirement can be validated by
// checking that (Q1 ^ Qn) < Q1.
// This check affirms that all queries are within the same logarithmic step.
uint256 nQueries = friQueue.length / 3; // NOLINT: divide-before-multiply.
uint256 prevQuery = 0;
for (uint256 i = 0; i < nQueries; i++) {
// Verify that queries are strictly incrementing.
require(friQueue[3 * i] > prevQuery, "INVALID_QUERY_VALUE");
// Verify FRI value and inverse are within valid range.
require(friQueue[3 * i + 1] < K_MODULUS, "INVALID_FRI_VALUE");
require(friQueue[3 * i + 2] < K_MODULUS, "INVALID_FRI_INVERSE_POINT");
prevQuery = friQueue[3 * i];
}
// Verify all queries are on the same logarithmic step.
// NOLINTNEXTLINE: divide-before-multiply.
require((friQueue[0] ^ friQueue[3 * nQueries - 3]) < friQueue[0], "INVALID_QUERIES_RANGE");
}
}