1
- use std:: io:: Write ;
2
-
3
1
use gadgets:: util:: Expr ;
4
2
use halo2_ecc:: bigint:: CRTInteger ;
5
3
use halo2_proofs:: {
6
4
circuit:: { AssignedCell , Layouter , Region , Value } ,
7
5
halo2curves:: bn256:: Fr ,
8
- plonk:: { Advice , Column , ConstraintSystem , Error , Expression , SecondPhase , Selector } ,
6
+ plonk:: { Advice , Column , ConstraintSystem , Error , Expression , Fixed , SecondPhase , Selector } ,
9
7
poly:: Rotation ,
10
8
} ;
11
9
use itertools:: Itertools ;
12
10
use zkevm_circuits:: { table:: U8Table , util:: Challenges } ;
13
11
14
12
use crate :: {
15
- aggregation:: { decoder :: witgen :: init_zstd_encoder , rlc:: POWS_OF_256 } ,
16
- blob:: { BatchData , BLOB_WIDTH , N_BLOB_BYTES , N_DATA_BYTES_PER_COEFFICIENT } ,
13
+ aggregation:: rlc:: POWS_OF_256 ,
14
+ blob:: { BLOB_WIDTH , N_BLOB_BYTES , N_DATA_BYTES_PER_COEFFICIENT } ,
17
15
RlcConfig ,
18
16
} ;
19
17
@@ -30,7 +28,7 @@ use crate::{
30
28
#[ derive( Clone , Debug ) ]
31
29
pub struct BlobDataConfig < const N_SNARKS : usize > {
32
30
/// Selector to mark the first row in the layout, enabled at offset=0.
33
- q_first : Selector ,
31
+ q_first : Column < Fixed > ,
34
32
/// Whether the row is enabled or not. We need exactly N_BLOB_BYTES rows, enabled from offset=1
35
33
/// to offset=N_BLOB_BYTES.
36
34
q_enabled : Selector ,
@@ -47,8 +45,11 @@ pub struct BlobDataConfig<const N_SNARKS: usize> {
47
45
}
48
46
49
47
pub struct AssignedBlobDataExport {
48
+ pub enable_encoding_bool : bool ,
49
+ pub enable_encoding : AssignedCell < Fr , Fr > ,
50
50
pub bytes_rlc : AssignedCell < Fr , Fr > ,
51
51
pub bytes_len : AssignedCell < Fr , Fr > ,
52
+ pub cooked_len : AssignedCell < Fr , Fr > ,
52
53
}
53
54
54
55
impl < const N_SNARKS : usize > BlobDataConfig < N_SNARKS > {
@@ -58,8 +59,8 @@ impl<const N_SNARKS: usize> BlobDataConfig<N_SNARKS> {
58
59
u8_table : U8Table ,
59
60
) -> Self {
60
61
let config = Self {
62
+ q_first : meta. fixed_column ( ) ,
61
63
q_enabled : meta. selector ( ) ,
62
- q_first : meta. complex_selector ( ) ,
63
64
byte : meta. advice_column ( ) ,
64
65
is_padding : meta. advice_column ( ) ,
65
66
bytes_rlc : meta. advice_column_in ( SecondPhase ) ,
@@ -76,23 +77,30 @@ impl<const N_SNARKS: usize> BlobDataConfig<N_SNARKS> {
76
77
} ) ;
77
78
78
79
meta. create_gate ( "BlobDataConfig: first row" , |meta| {
79
- let is_first = meta. query_selector ( config. q_first ) ;
80
+ let is_first = meta. query_fixed ( config. q_first , Rotation :: cur ( ) ) ;
80
81
81
82
let byte = meta. query_advice ( config. byte , Rotation :: cur ( ) ) ;
82
83
let bytes_rlc = meta. query_advice ( config. bytes_rlc , Rotation :: cur ( ) ) ;
83
84
let bytes_len = meta. query_advice ( config. bytes_len , Rotation :: cur ( ) ) ;
84
85
let is_padding_next = meta. query_advice ( config. is_padding , Rotation :: next ( ) ) ;
85
86
87
+ let bytes_rlc_next = meta. query_advice ( config. bytes_rlc , Rotation :: next ( ) ) ;
88
+ let bytes_len_next = meta. query_advice ( config. bytes_len , Rotation :: next ( ) ) ;
89
+
86
90
vec ! [
87
91
is_first. expr( ) * byte,
88
92
is_first. expr( ) * bytes_rlc,
93
+ is_first. expr( ) * bytes_rlc_next,
89
94
is_first. expr( ) * bytes_len,
95
+ is_first. expr( ) * bytes_len_next,
90
96
is_first. expr( ) * is_padding_next,
91
97
]
92
98
} ) ;
93
99
94
100
meta. create_gate ( "BlobDataConfig: main gate" , |meta| {
95
101
let is_enabled = meta. query_selector ( config. q_enabled ) ;
102
+ let is_skip_rlc = meta. query_fixed ( config. q_first , Rotation :: prev ( ) ) ;
103
+ let trigger_rlc = 1 . expr ( ) - is_skip_rlc;
96
104
97
105
let is_padding_curr = meta. query_advice ( config. is_padding , Rotation :: cur ( ) ) ;
98
106
let is_padding_prev = meta. query_advice ( config. is_padding , Rotation :: prev ( ) ) ;
@@ -116,6 +124,7 @@ impl<const N_SNARKS: usize> BlobDataConfig<N_SNARKS> {
116
124
// bytes_rlc updates in the non-padded territory
117
125
is_enabled. expr( )
118
126
* ( 1 . expr( ) - is_padding_curr. expr( ) )
127
+ * trigger_rlc. expr( )
119
128
* ( bytes_rlc_prev. expr( ) * challenges. keccak_input( ) + byte. expr( )
120
129
- bytes_rlc_curr. expr( ) ) ,
121
130
// bytes_rlc remains unchanged in padded territory
@@ -125,6 +134,7 @@ impl<const N_SNARKS: usize> BlobDataConfig<N_SNARKS> {
125
134
// bytes_len increments in the non-padded territory
126
135
is_enabled. expr( )
127
136
* ( 1 . expr( ) - is_padding_curr. expr( ) )
137
+ * trigger_rlc. expr( )
128
138
* ( bytes_len_prev. expr( ) + 1 . expr( ) - bytes_len_curr. expr( ) ) ,
129
139
// bytes_len remains unchanged in padded territory
130
140
is_enabled. expr( )
@@ -143,15 +153,16 @@ impl<const N_SNARKS: usize> BlobDataConfig<N_SNARKS> {
143
153
layouter : & mut impl Layouter < Fr > ,
144
154
challenge_value : Challenges < Value < Fr > > ,
145
155
rlc_config : & RlcConfig ,
146
- batch_data : & BatchData < N_SNARKS > ,
156
+ blob_bytes : & [ u8 ] ,
147
157
barycentric_assignments : & [ CRTInteger < Fr > ] ,
148
158
) -> Result < AssignedBlobDataExport , Error > {
149
- let ( assigned_bytes, bytes_rlc, bytes_len) = layouter. assign_region (
159
+ let ( assigned_bytes, bytes_rlc, bytes_len, enable_encoding_bool ) = layouter. assign_region (
150
160
|| "BlobData bytes" ,
151
- |mut region| self . assign_rows ( & mut region, batch_data , & challenge_value) ,
161
+ |mut region| self . assign_rows ( & mut region, blob_bytes , & challenge_value) ,
152
162
) ?;
163
+ let enable_encoding = assigned_bytes[ 0 ] . clone ( ) ;
153
164
154
- let cooked_bytes_len = layouter. assign_region (
165
+ let cooked_len = layouter. assign_region (
155
166
|| "BlobData internal checks" ,
156
167
|mut region| {
157
168
self . assign_internal_checks (
@@ -165,41 +176,38 @@ impl<const N_SNARKS: usize> BlobDataConfig<N_SNARKS> {
165
176
) ?;
166
177
167
178
Ok ( AssignedBlobDataExport {
179
+ enable_encoding_bool,
180
+ enable_encoding,
168
181
bytes_rlc,
169
- bytes_len : cooked_bytes_len,
182
+ bytes_len,
183
+ cooked_len,
170
184
} )
171
185
}
172
186
173
187
#[ allow( clippy:: type_complexity) ]
174
188
pub fn assign_rows (
175
189
& self ,
176
190
region : & mut Region < Fr > ,
177
- batch_data : & BatchData < N_SNARKS > ,
191
+ blob_bytes : & [ u8 ] ,
178
192
challenges : & Challenges < Value < Fr > > ,
179
193
) -> Result <
180
194
(
181
195
Vec < AssignedCell < Fr , Fr > > ,
182
196
AssignedCell < Fr , Fr > ,
183
197
AssignedCell < Fr , Fr > ,
198
+ bool ,
184
199
) ,
185
200
Error ,
186
201
> {
187
- let batch_bytes = batch_data. get_batch_data_bytes ( ) ;
188
- let blob_bytes = {
189
- let mut encoder = init_zstd_encoder ( None ) ;
190
- encoder
191
- . set_pledged_src_size ( Some ( batch_bytes. len ( ) as u64 ) )
192
- . map_err ( |_| Error :: Synthesis ) ?;
193
- encoder
194
- . write_all ( & batch_bytes)
195
- . map_err ( |_| Error :: Synthesis ) ?;
196
- encoder. finish ( ) . map_err ( |_| Error :: Synthesis ) ?
197
- } ;
202
+ let enable_encoding = blob_bytes[ 0 ] . eq ( & 1 ) ;
203
+
198
204
assert ! ( blob_bytes. len( ) <= N_BLOB_BYTES , "too many blob bytes" ) ;
199
205
200
- self . q_first . enable ( region, 0 ) ?;
206
+ // Assign fixed column and selector.
207
+ region. assign_fixed ( || "q_first" , self . q_first , 0 , || Value :: known ( Fr :: one ( ) ) ) ?;
201
208
for i in 1 ..=N_BLOB_BYTES {
202
209
self . q_enabled . enable ( region, i) ?;
210
+ region. assign_fixed ( || "q_first" , self . q_first , i, || Value :: known ( Fr :: zero ( ) ) ) ?;
203
211
}
204
212
205
213
for col in [ self . byte , self . bytes_rlc , self . bytes_len , self . is_padding ] {
@@ -217,60 +225,69 @@ impl<const N_SNARKS: usize> BlobDataConfig<N_SNARKS> {
217
225
let mut last_bytes_len = None ;
218
226
for ( i, & byte) in blob_bytes. iter ( ) . enumerate ( ) {
219
227
let byte_value = Value :: known ( Fr :: from ( byte as u64 ) ) ;
220
- bytes_rlc = bytes_rlc * challenges. keccak_input ( ) + byte_value;
228
+ if i > 0 {
229
+ bytes_rlc = bytes_rlc * challenges. keccak_input ( ) + byte_value;
230
+ }
221
231
232
+ let offset = i + 1 ;
222
233
assigned_bytes. push ( region. assign_advice (
223
234
|| "byte" ,
224
235
self . byte ,
225
- i + 1 ,
236
+ offset ,
226
237
|| byte_value,
227
238
) ?) ;
228
239
region. assign_advice (
229
240
|| "is_padding" ,
230
241
self . is_padding ,
231
- i + 1 ,
242
+ offset ,
232
243
|| Value :: known ( Fr :: zero ( ) ) ,
233
244
) ?;
234
245
last_bytes_rlc =
235
- Some ( region. assign_advice ( || "bytes_rlc" , self . bytes_rlc , i + 1 , || bytes_rlc) ?) ;
246
+ Some ( region. assign_advice ( || "bytes_rlc" , self . bytes_rlc , offset , || bytes_rlc) ?) ;
236
247
last_bytes_len = Some ( region. assign_advice (
237
248
|| "bytes_len" ,
238
249
self . bytes_len ,
239
- i + 1 ,
240
- || Value :: known ( Fr :: from ( i as u64 + 1 ) ) ,
250
+ offset ,
251
+ || Value :: known ( Fr :: from ( i as u64 ) ) ,
241
252
) ?) ;
242
253
}
243
254
244
255
let mut last_bytes_rlc = last_bytes_rlc. expect ( "at least 1 byte guaranteed" ) ;
245
256
let mut last_bytes_len = last_bytes_len. expect ( "at least 1 byte guaranteed" ) ;
246
257
for i in blob_bytes. len ( ) ..N_BLOB_BYTES {
258
+ let offset = i + 1 ;
247
259
assigned_bytes. push ( region. assign_advice (
248
260
|| "byte" ,
249
261
self . byte ,
250
- i + 1 ,
262
+ offset ,
251
263
|| Value :: known ( Fr :: zero ( ) ) ,
252
264
) ?) ;
253
265
region. assign_advice (
254
266
|| "is_padding" ,
255
267
self . is_padding ,
256
- i + 1 ,
268
+ offset ,
257
269
|| Value :: known ( Fr :: one ( ) ) ,
258
270
) ?;
259
271
last_bytes_rlc = region. assign_advice (
260
272
|| "bytes_rlc" ,
261
273
self . bytes_rlc ,
262
- i + 1 ,
274
+ offset ,
263
275
|| last_bytes_rlc. value ( ) . cloned ( ) ,
264
276
) ?;
265
277
last_bytes_len = region. assign_advice (
266
278
|| "bytes_len" ,
267
279
self . bytes_len ,
268
- i + 1 ,
280
+ offset ,
269
281
|| last_bytes_len. value ( ) . cloned ( ) ,
270
282
) ?;
271
283
}
272
284
273
- Ok ( ( assigned_bytes, last_bytes_rlc, last_bytes_len) )
285
+ Ok ( (
286
+ assigned_bytes,
287
+ last_bytes_rlc,
288
+ last_bytes_len,
289
+ enable_encoding,
290
+ ) )
274
291
}
275
292
276
293
pub fn assign_internal_checks (
@@ -307,6 +324,10 @@ impl<const N_SNARKS: usize> BlobDataConfig<N_SNARKS> {
307
324
pows_of_256
308
325
} ;
309
326
327
+ // The first byte in the blob is a boolean indicating whether or not blob is an encoded
328
+ // form of the batch.
329
+ rlc_config. enforce_binary ( region, & assigned_bytes[ 0 ] , & mut rlc_config_offset) ?;
330
+
310
331
////////////////////////////////////////////////////////////////////////////////
311
332
//////////////////////////////////// LINKING ///////////////////////////////////
312
333
////////////////////////////////////////////////////////////////////////////////
0 commit comments