2
2
3
3
use crate :: circuits:: { constraints:: ConstraintSystem , domains:: EvaluationDomains , wires:: * } ;
4
4
use ark_ff:: bytes:: ToBytes ;
5
- use ark_ff:: { FftField , Field } ;
5
+ use ark_ff:: { FftField , Field , One , Zero } ;
6
6
use ark_poly:: { Evaluations as E , Radix2EvaluationDomain as D } ;
7
7
use num_traits:: cast:: ToPrimitive ;
8
8
use o1_utils:: hasher:: CryptoDigest ;
9
9
use serde:: { Deserialize , Serialize } ;
10
10
use serde_with:: serde_as;
11
11
use std:: collections:: { hash_map:: Entry , HashMap , HashSet } ;
12
12
use std:: io:: { Result as IoResult , Write } ;
13
+ use std:: ops:: Mul ;
13
14
14
15
type Evaluations < Field > = E < Field , D < Field > > ;
15
16
@@ -68,40 +69,70 @@ pub struct SingleLookup<F> {
68
69
/// analogously using `joint_combiner`.
69
70
///
70
71
/// This function computes that combined value.
71
- pub fn combine_table_entry < ' a , F : Field , I : DoubleEndedIterator < Item = & ' a F > > (
72
- joint_combiner : F ,
73
- v : I ,
74
- ) -> F {
75
- v. rev ( ) . fold ( F :: zero ( ) , |acc, x| joint_combiner * acc + x)
72
+ pub fn combine_table_entry < ' a , F , I > ( joint_combiner : F , v : I ) -> F
73
+ where
74
+ F : ' a , // Any references in `F` must have a lifetime longer than `'a`.
75
+ F : Zero + One + Clone ,
76
+ I : DoubleEndedIterator < Item = & ' a F > ,
77
+ {
78
+ v. rev ( )
79
+ . fold ( F :: zero ( ) , |acc, x| joint_combiner. clone ( ) * acc + x. clone ( ) )
76
80
}
77
81
78
- impl < F : Field > SingleLookup < F > {
82
+ impl < F : Copy > SingleLookup < F > {
79
83
/// Evaluate the linear combination specifying the lookup value to a field element.
80
- pub fn evaluate < G : Fn ( LocalPosition ) -> F > ( & self , eval : G ) -> F {
84
+ pub fn evaluate < K , G : Fn ( LocalPosition ) -> K > ( & self , eval : G ) -> K
85
+ where
86
+ K : Zero ,
87
+ K : Mul < F , Output = K > ,
88
+ {
81
89
self . value
82
90
. iter ( )
83
- . fold ( F :: zero ( ) , |acc, ( c, p) | acc + * c * eval ( * p) )
91
+ . fold ( K :: zero ( ) , |acc, ( c, p) | acc + eval ( * p) * * c )
84
92
}
85
93
}
86
94
87
95
/// A spec for checking that the given vector belongs to a vector-valued lookup table.
88
96
#[ derive( Clone , Serialize , Deserialize ) ]
89
- pub struct JointLookup < F > {
90
- pub table_id : usize ,
91
- pub entry : Vec < SingleLookup < F > > ,
97
+ pub struct JointLookup < SingleLookup > {
98
+ pub table_id : i32 ,
99
+ pub entry : Vec < SingleLookup > ,
92
100
}
93
101
94
- impl < F : Field > JointLookup < F > {
102
+ /// A spec for checking that the given vector belongs to a vector-valued lookup table, where the
103
+ /// components of the vector are computed from a linear combination of locally-accessible cells.
104
+ pub type JointLookupSpec < F > = JointLookup < SingleLookup < F > > ;
105
+
106
+ impl < F : Zero + One + Clone > JointLookup < F > {
95
107
// TODO: Support multiple tables
96
108
/// Evaluate the combined value of a joint-lookup.
97
- pub fn evaluate < G : Fn ( LocalPosition ) -> F > ( & self , joint_combiner : F , eval : & G ) -> F {
98
- let mut res = F :: zero ( ) ;
99
- let mut c = F :: one ( ) ;
100
- for s in self . entry . iter ( ) {
101
- res += c * s. evaluate ( eval) ;
102
- c *= joint_combiner;
109
+ pub fn evaluate ( & self , joint_combiner : F ) -> F {
110
+ combine_table_entry ( joint_combiner, self . entry . iter ( ) )
111
+ }
112
+ }
113
+
114
+ impl < F : Copy > JointLookup < SingleLookup < F > > {
115
+ /// Reduce linear combinations in the lookup entries to a single value, resolving local
116
+ /// positions using the given function.
117
+ pub fn reduce < K , G : Fn ( LocalPosition ) -> K > ( & self , eval : & G ) -> JointLookup < K >
118
+ where
119
+ K : Zero ,
120
+ K : Mul < F , Output = K > ,
121
+ {
122
+ JointLookup {
123
+ table_id : self . table_id ,
124
+ entry : self . entry . iter ( ) . map ( |s| s. evaluate ( eval) ) . collect ( ) ,
103
125
}
104
- res
126
+ }
127
+
128
+ /// Evaluate the combined value of a joint-lookup, resolving local positions using the given
129
+ /// function.
130
+ pub fn evaluate < K , G : Fn ( LocalPosition ) -> K > ( & self , joint_combiner : K , eval : & G ) -> K
131
+ where
132
+ K : Zero + One + Clone ,
133
+ K : Mul < F , Output = K > ,
134
+ {
135
+ self . reduce ( eval) . evaluate ( joint_combiner)
105
136
}
106
137
}
107
138
@@ -158,7 +189,7 @@ pub enum GateType {
158
189
pub struct LookupInfo < F > {
159
190
/// A single lookup constraint is a vector of lookup constraints to be applied at a row.
160
191
/// This is a vector of all the kinds of lookup constraints in this configuration.
161
- pub kinds : Vec < Vec < JointLookup < F > > > ,
192
+ pub kinds : Vec < Vec < JointLookupSpec < F > > > ,
162
193
/// A map from the kind of gate (and whether it is the current row or next row) to the lookup
163
194
/// constraint (given as an index into `kinds`) that should be applied there, if any.
164
195
pub kinds_map : HashMap < ( GateType , CurrOrNext ) , usize > ,
@@ -170,10 +201,10 @@ pub struct LookupInfo<F> {
170
201
/// The maximum joint size of any joint lookup in a constraint in `kinds`. This can be computed from `kinds`.
171
202
pub max_joint_size : u32 ,
172
203
/// An empty vector.
173
- empty : Vec < JointLookup < F > > ,
204
+ empty : Vec < JointLookupSpec < F > > ,
174
205
}
175
206
176
- fn max_lookups_per_row < F > ( kinds : & [ Vec < JointLookup < F > > ] ) -> usize {
207
+ fn max_lookups_per_row < F > ( kinds : & [ Vec < JointLookupSpec < F > > ] ) -> usize {
177
208
kinds. iter ( ) . fold ( 0 , |acc, x| std:: cmp:: max ( x. len ( ) , acc) )
178
209
}
179
210
@@ -286,7 +317,7 @@ impl<F: FftField> LookupInfo<F> {
286
317
}
287
318
288
319
/// For each row in the circuit, which lookup-constraints should be enforced at that row.
289
- pub fn by_row < ' a > ( & ' a self , gates : & [ CircuitGate < F > ] ) -> Vec < & ' a Vec < JointLookup < F > > > {
320
+ pub fn by_row < ' a > ( & ' a self , gates : & [ CircuitGate < F > ] ) -> Vec < & ' a Vec < JointLookupSpec < F > > > {
290
321
let mut kinds = vec ! [ & self . empty; gates. len( ) + 1 ] ;
291
322
for i in 0 ..gates. len ( ) {
292
323
let typ = gates[ i] . typ ;
@@ -327,7 +358,7 @@ impl GateType {
327
358
///
328
359
/// See circuits/kimchi/src/polynomials/chacha.rs for an explanation of
329
360
/// how these work.
330
- pub fn lookup_kinds < F : Field > ( ) -> ( Vec < Vec < JointLookup < F > > > , Vec < GatesLookupSpec > ) {
361
+ pub fn lookup_kinds < F : Field > ( ) -> ( Vec < Vec < JointLookupSpec < F > > > , Vec < GatesLookupSpec > ) {
331
362
let curr_row = |column| LocalPosition {
332
363
row : CurrOrNext :: Curr ,
333
364
column,
0 commit comments