forked from jancarlsson/snarkfront
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAlg.hpp
270 lines (223 loc) · 6.84 KB
/
Alg.hpp
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
#ifndef _SNARKFRONT_ALG_HPP_
#define _SNARKFRONT_ALG_HPP_
#include <cassert>
#include <cstdint>
#include <sstream>
#include <string>
#include <vector>
#include "AST.hpp"
#include <BigInt.hpp> // snarklib
#include "EnumOps.hpp"
#include "EvalAST.hpp"
#include "PowersOf2.hpp"
#include <Rank1DSL.hpp> // snarklib
#include "R1C.hpp"
#include "TLsingleton.hpp"
namespace snarkfront {
////////////////////////////////////////////////////////////////////////////////
// Parameters for specializing the AST templates to primitive types
//
// - Alg_bool for predicate
// - Alg_BigInt for scalar field of GMP big numbers
// - Alg_uint32 for 32-bit words
// - Alg_uint64 for 64-bit words
//
template <typename VAL,
typename FR,
typename OP,
typename CMP> class Alg;
template <typename FR> using
Alg_bool = Alg<bool,
FR,
LogicalOps,
EqualityCmp>;
template <typename FR> using
Alg_BigInt = Alg<snarklib::BigInt<2>, // 128 bits on x86-64
FR,
ScalarOps,
ScalarCmp>;
template <typename FR> using
Alg_uint32 = Alg<std::uint32_t,
FR,
BitwiseOps,
EqualityCmp>;
template <typename FR> using
Alg_uint64 = Alg<std::uint64_t,
FR,
BitwiseOps,
EqualityCmp>;
////////////////////////////////////////////////////////////////////////////////
// algebra parameter
//
template <typename VAL, // value for application code
typename FR, // finite field witness (elliptic curve Fr)
typename OP, // logical and arithmetic operators
typename CMP> // comparison operators
class Alg
{
public:
typedef VAL ValueType;
typedef FR FrType;
typedef OP OpType;
typedef CMP CmpType;
typedef snarklib::R1Term<FR> R1T;
typedef snarklib::R1Variable<FR> R1V;
Alg() = default;
// circuit input
template <typename T>
void bless(const T& a) {
// object is not already initialized
#ifdef USE_ASSERT
assert(m_splitBits.empty());
assert(m_r1Terms.empty());
#endif
m_value = VAL(a);
m_witness = FR(valueToString(VAL(a)));
m_splitBits = valueBits(VAL(a));
initTerms(true);
}
// circuit input from demarshalled witness
void bless(const R1Cowitness<FR>& input) {
bless(valueFromWitness(input));
}
// used by AST_Const and AST_Var constructors (bit representation)
template <typename T>
Alg(const T& a, const bool blessed)
: m_value(a),
m_witness(valueToString(VAL(a))),
m_splitBits(valueBits(VAL(a)))
{
initTerms(blessed);
}
// used by AST_Const and AST_Var constructors from demarshalled witness
Alg(const R1Cowitness<FR>& input)
: Alg{valueFromWitness(input), true}
{}
// used by operator evaluation and conversion blessing
Alg(const VAL& a,
const FR& b,
const std::vector<int>& c,
const std::vector<R1T>& d)
: m_value(a),
m_witness(b),
m_splitBits(c),
m_r1Terms(d)
{}
explicit operator bool() const {
return bool(m_value);
}
// application value
const VAL& value() const {
return m_value;
}
// finite field witness
const FR& witness() const {
return m_witness;
}
// bits for witness split
const std::vector<int>& splitBits() const {
return m_splitBits;
}
// return constraint terms for bit representation
const std::vector<R1T>& r1Terms() const {
return m_r1Terms;
}
// field constructors accept strings
static std::string valueToString(const VAL& a) {
std::stringstream ss;
ss << a;
return ss.str();
}
// called from AST Variable overloaded assignment operator
static Alg
assignEval(const AST_Var<Alg>& lhs, const AST_Node<Alg>& rhs) {
EvalAST<Alg> E;
rhs.accept(E);
return E.result();
}
static Alg
assignEval(const AST_Var<Alg>& lhs, const VAL& rhs) {
return assignEval(lhs, AST_Const<Alg>(rhs));
}
// called from AST Foreign node constructor
static Alg_bool<FR>
compareOp(const CMP op, const AST_Node<Alg>& a, const AST_Node<Alg>& b)
{
// evaluate left and right hand side nodes
EvalAST<Alg> A, B;
a.accept(A);
b.accept(B);
// push left and right hand side results on stack
EvalAST<Alg> C;
C.push(A.result());
C.push(B.result());
// evaluate comparison operation
C.compareOp(op);
// convert comparison result of foreign algebraic type to predicate
const bool result = bool(C.result());
return Alg_bool<FR>(result,
boolTo<FR>(result),
valueBits(result),
C.result().r1Terms());
}
// type conversion to and between 32-bit and 64-bit words
template <typename U>
static U xwordOp(const AST_Node<Alg>& src, const U& dummy)
{
// evaluate source node
EvalAST<Alg> E;
src.accept(E);
const auto x = TL<R1C<FR>>::singleton()->argBits(E.result());
typename U::ValueType uvalue;
if (1 == x.size()) {
// source is bool, replicate bit to word
uvalue = E.result().value()
? -1 // all bits set
: 0; // all bits clear
} else {
// source is 32-bit or 64-bit word
uvalue = E.result().value();
}
// convert result of foreign algebraic source type to target type
return U(uvalue,
valueToString(uvalue),
valueBits(uvalue),
rank1_xword(x, sizeBits(uvalue)));
}
private:
VAL valueFromWitness(const R1Cowitness<FR>& input) const {
const std::size_t peekID = TL<R1C<FR>>::singleton()->counterID();
#ifdef USE_ASSERT
assert(peekID <= input.sizeSTR());
#endif
std::stringstream ss(input[peekID]);
VAL value;
ss >> value;
#ifdef USE_ASSERT
assert(!!ss);
#endif
return value;
}
void initTerms(const bool blessed) {
auto& RS = TL<R1C<FR>>::singleton();
// create terms for bits, may be constant or variable
m_r1Terms.reserve(sizeBits(m_value));
for (const auto& b : m_splitBits) {
m_r1Terms.emplace_back(
RS->createTerm(boolTo<FR>(b), blessed));
}
if (blessed) {
// associate bits with variable value
RS->witnessTerms(m_r1Terms, m_value);
// input consistency on bits
for (const auto& b : m_r1Terms)
RS->addBooleanity(b);
}
}
VAL m_value;
FR m_witness;
std::vector<int> m_splitBits;
std::vector<R1T> m_r1Terms;
};
} // namespace snarkfront
#endif