Longfellow ZK 0290cb32
Loading...
Searching...
No Matches
decode.h
1// Copyright 2025 Google LLC.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15#ifndef PRIVACY_PROOFS_ZK_LIB_CIRCUITS_BASE64_DECODE_H_
16#define PRIVACY_PROOFS_ZK_LIB_CIRCUITS_BASE64_DECODE_H_
17
18#include <cstddef>
19#include <vector>
20
21#include "util/ceildiv.h"
22#include "util/panic.h"
23
24namespace proofs {
25
26// This class implements a circuit to assert a base64 url decoding.
27// A string in base64 consists of the characters A-Z a-z 0-9 - _ and =.
28// 0--25 are mapped to A-Z, 26--51 are mapped to a-z, 52--61 are mapped to 0-9,
29// and 62--63 are mapped to - and _ respectively.
30// The base64 encoding is padded with = to a multiple of 4.
31template <class LogicCircuit>
32class Base64Decoder {
33 using EltW = typename LogicCircuit::EltW;
34 using BitW = typename LogicCircuit::BitW;
35 using v8 = typename LogicCircuit::v8;
36 using v6 = typename LogicCircuit::template bitvec<6>;
37
38 public:
39 explicit Base64Decoder(const LogicCircuit& lc) : lc_(lc) {}
40
41 void base64_rawurl_decode(const v8 inputs[/*n*/],
42 v8 output[/* ceil(n*6/8) */], size_t n) const {
43 check(n < (1 << 28), "input too large"); // avoid overflows
44 v6 zero = lc_.template vbit<6>(0);
45
46 size_t max = ceildiv<size_t>(n * 6, 8);
47 size_t oc = 0;
48
49 for (size_t i = 0; i < n; i += 4, oc += 3) {
50 v6 quad[4] = {zero, zero, zero, zero};
51 for (size_t j = 0; j < 4 && i + j < n; ++j) {
52 decode(inputs[i + j], quad[j]);
53 }
54 // repack
55 for (size_t j = 0; j < 24 && (oc + j / 8) < max; ++j) {
56 output[oc + j / 8][7 - (j % 8)] = quad[j / 6][5 - (j % 6)];
57 }
58 }
59 }
60
61 template <size_t N>
62 void base64_rawurl_decode_len(
63 const v8 inputs[/*n*/], v8 output[/* ceil(n*6/8) */], size_t n,
64 typename LogicCircuit::template bitvec<N>& len) const {
65 check(n < (1 << 28), "input too large"); // avoid overflows
66 v6 zero = lc_.template vbit<6>(0);
67
68 size_t max = ceildiv<size_t>(n * 6, 8);
69 size_t oc = 0;
70
71 for (size_t i = 0; i < n; i += 4, oc += 3) {
72 v6 quad[4] = {zero, zero, zero, zero};
73 BitW invalid;
74 for (size_t j = 0; j < 4 && i + j < n; ++j) {
75 decode(inputs[i + j], quad[j], invalid);
76 auto range = lc_.vlt(i + j, len);
77 lc_.assert_implies(&range, lc_.lnot(invalid));
78 }
79 // repack
80 for (size_t j = 0; j < 24 && (oc + j / 8) < max; ++j) {
81 output[oc + j / 8][7 - (j % 8)] = quad[j / 6][5 - (j % 6)];
82 }
83 }
84 }
85
86 void decode(const v8 in, v6& out) const {
87 BitW invalid;
88 decode(in, out, invalid);
89 lc_.assert0(invalid);
90 }
91
92 void decode(const v8 in, v6& out, BitW& invalid) const {
93 v8 ni;
94 for (size_t i = 0; i < 8; ++i) {
95 ni[i] = lc_.lnot(in[i]);
96 }
97 std::vector<std::vector<BitW> > exp[] = {
98 {
99 // ['!v4', '!v3', '!v2', '!v1', '!v0']
100 {
101 ni[4],
102 ni[3],
103 ni[2],
104 ni[1],
105 ni[0],
106 },
107 // ['v4', 'v3', '!v2', 'v1', 'v0']
108 {
109 in[4],
110 in[3],
111 ni[2],
112 in[1],
113 in[0],
114 },
115 // ['v5', 'v4', 'v3', 'v1', 'v0']
116 {
117 in[5],
118 in[4],
119 in[3],
120 in[1],
121 in[0],
122 },
123 // ['!v6', 'v3', 'v2', '!v0']
124 {
125 ni[6],
126 in[3],
127 in[2],
128 ni[0],
129 },
130 // ['v4', 'v3', 'v2', '!v1']
131 {
132 in[4],
133 in[3],
134 in[2],
135 ni[1],
136 },
137 // ['v4', 'v3', 'v2', '!v0']
138 {
139 in[4],
140 in[3],
141 in[2],
142 ni[0],
143 },
144 // ['!v6', '!v4', '!v3']
145 {
146 ni[6],
147 ni[4],
148 ni[3],
149 },
150 // ['!v6', '!v4', '!v2']
151 {
152 ni[6],
153 ni[4],
154 ni[2],
155 },
156 // ['!v6', 'v3', 'v1']
157 {
158 ni[6],
159 in[3],
160 in[1],
161 },
162 // ['!v6', '!v5']
163 {
164 ni[6],
165 ni[5],
166 },
167 // ['v7']
168 {
169 in[7],
170 },
171 },
172 {
173 // ['v6', 'v5', 'v4', '!v3', '!v2']
174 {
175 in[6],
176 in[5],
177 in[4],
178 ni[3],
179 ni[2],
180 },
181 // ['v6', 'v5', 'v4', '!v3', '!v0']
182 {
183 in[6],
184 in[5],
185 in[4],
186 ni[3],
187 ni[0],
188 },
189 // ['v6', 'v5', 'v4', 'v2', '!v1']
190 {
191 in[6],
192 in[5],
193 in[4],
194 in[2],
195 ni[1],
196 },
197 // ['v5', 'v2', 'v1', 'v0']
198 {
199 in[5],
200 in[2],
201 in[1],
202 in[0],
203 },
204 // ['v4', 'v3', 'v1', 'v0']
205 {
206 in[4],
207 in[3],
208 in[1],
209 in[0],
210 },
211 // ['v5', 'v3']
212 {
213 in[5],
214 in[3],
215 },
216 // ['!v6', '!v2']
217 {
218 ni[6],
219 ni[2],
220 },
221 // ['!v6', 'v2']
222 {
223 ni[6],
224 in[2],
225 },
226 },
227 {
228 // ['v5', '!v4', '!v3', '!v1']
229 {
230 in[5],
231 ni[4],
232 ni[3],
233 ni[1],
234 },
235 // ['v5', '!v4', '!v3', '!v2']
236 {
237 in[5],
238 ni[4],
239 ni[3],
240 ni[2],
241 },
242 // ['!v5', 'v4', 'v1']
243 {
244 ni[5],
245 in[4],
246 in[1],
247 },
248 // ['v5', '!v4', '!v3', '!v0']
249 {
250 in[5],
251 ni[4],
252 ni[3],
253 ni[0],
254 },
255 // ['v4', 'v2', 'v1', 'v0']
256 {
257 in[4],
258 in[2],
259 in[1],
260 in[0],
261 },
262 // ['!v5', 'v4', 'v0']
263 {
264 ni[5],
265 in[4],
266 in[0],
267 },
268 // ['!v5', 'v4', 'v2']
269 {
270 ni[5],
271 in[4],
272 in[2],
273 },
274 // ['v4', 'v3']
275 {
276 in[4],
277 in[3],
278 },
279 // ['!v6', '!v2']
280 {
281 ni[6],
282 ni[2],
283 },
284 // ['!v6', 'v2']
285 {
286 ni[6],
287 in[2],
288 },
289 },
290 {
291 // ['v6', '!v3', '!v2', '!v1', '!v0']
292 {
293 in[6],
294 ni[3],
295 ni[2],
296 ni[1],
297 ni[0],
298 },
299 // ['v6', 'v5', 'v4', '!v3', '!v2']
300 {
301 in[6],
302 in[5],
303 in[4],
304 ni[3],
305 ni[2],
306 },
307 // ['v6', 'v5', 'v4', '!v3', '!v0']
308 {
309 in[6],
310 in[5],
311 in[4],
312 ni[3],
313 ni[0],
314 },
315 // ['v6', 'v5', 'v4', 'v2', '!v1']
316 {
317 in[6],
318 in[5],
319 in[4],
320 in[2],
321 ni[1],
322 },
323 // ['v5', '!v4', '!v3', '!v1']
324 {
325 in[5],
326 ni[4],
327 ni[3],
328 ni[1],
329 },
330 // ['v5', '!v4', '!v3', '!v2']
331 {
332 in[5],
333 ni[4],
334 ni[3],
335 ni[2],
336 },
337 // ['v5', '!v4', '!v3', '!v0']
338 {
339 in[5],
340 ni[4],
341 ni[3],
342 ni[0],
343 },
344 // ['!v5', 'v3', 'v1']
345 {
346 ni[5],
347 in[3],
348 in[1],
349 },
350 // ['v3', 'v2', 'v1', 'v0']
351 {
352 in[3],
353 in[2],
354 in[1],
355 in[0],
356 },
357 // ['!v5', 'v3', 'v0']
358 {
359 ni[5],
360 in[3],
361 in[0],
362 },
363 // ['!v5', 'v3', 'v2']
364 {
365 ni[5],
366 in[3],
367 in[2],
368 },
369 // ['!v6', 'v3']
370 {
371 ni[6],
372 in[3],
373 },
374 // ['!v6', 'v2']
375 {
376 ni[6],
377 in[2],
378 },
379 },
380 {
381 // ['v5', '!v4', 'v2', '!v1', 'v0']
382 {
383 in[5],
384 ni[4],
385 in[2],
386 ni[1],
387 in[0],
388 },
389 // ['v6', 'v5', 'v4', 'v2', '!v1']
390 {
391 in[6],
392 in[5],
393 in[4],
394 in[2],
395 ni[1],
396 },
397 // ['!v5', '!v2', '!v1', '!v0']
398 {
399 ni[5],
400 ni[2],
401 ni[1],
402 ni[0],
403 },
404 // ['v6', 'v5', 'v2', '!v0']
405 {
406 in[6],
407 in[5],
408 in[2],
409 ni[0],
410 },
411 // ['v5', '!v2', 'v1', 'v0']
412 {
413 in[5],
414 ni[2],
415 in[1],
416 in[0],
417 },
418 // ['!v5', 'v2', 'v0']
419 {
420 ni[5],
421 in[2],
422 in[0],
423 },
424 // ['!v5', 'v2', 'v1']
425 {
426 ni[5],
427 in[2],
428 in[1],
429 },
430 // ['!v6', '!v2']
431 {
432 ni[6],
433 ni[2],
434 },
435 },
436 {
437 // ['v5', '!v4', 'v2', '!v1', 'v0']
438 {
439 in[5],
440 ni[4],
441 in[2],
442 ni[1],
443 in[0],
444 },
445 // ['v6', 'v5', '!v1', 'v0']
446 {
447 in[6],
448 in[5],
449 ni[1],
450 in[0],
451 },
452 // ['!v5', '!v1', '!v0']
453 {
454 ni[5],
455 ni[1],
456 ni[0],
457 },
458 // ['!v5', 'v1', 'v0']
459 {
460 ni[5],
461 in[1],
462 in[0],
463 },
464 // ['v5', 'v1', '!v0']
465 {
466 in[5],
467 in[1],
468 ni[0],
469 },
470 // ['!v6', 'v1']
471 {
472 ni[6],
473 in[1],
474 },
475 },
476 {
477 // ['v4', 'v3', 'v1', 'v0']
478 {
479 in[4],
480 in[3],
481 in[1],
482 in[0],
483 },
484 // ['!v6', 'v4', 'v0']
485 {
486 ni[6],
487 in[4],
488 in[0],
489 },
490 // ['v6', '!v0']
491 {
492 in[6],
493 ni[0],
494 },
495 },
496 };
497 invalid = lc_.or_of_and(exp[0]);
498 for (size_t i = 0; i < 6; ++i) {
499 out[5 - i] = lc_.or_of_and(exp[i + 1]);
500 }
501 }
502
503 private:
504 const LogicCircuit& lc_;
505};
506} // namespace proofs
507
508#endif // PRIVACY_PROOFS_ZK_LIB_CIRCUITS_BASE64_DECODE_H_