Longfellow ZK 0290cb32
Loading...
Searching...
No Matches
cbor.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_CBOR_PARSER_CBOR_H_
16#define PRIVACY_PROOFS_ZK_LIB_CIRCUITS_CBOR_PARSER_CBOR_H_
17
18#include <stddef.h>
19#include <stdint.h>
20
21#include <array>
22#include <vector>
23
24#include "circuits/cbor_parser/cbor_constants.h"
25#include "circuits/cbor_parser/cbor_pluck.h"
26#include "circuits/cbor_parser/scan.h"
27#include "circuits/logic/bit_adder.h"
28#include "circuits/logic/memcmp.h"
29#include "circuits/logic/routing.h"
30#include "util/panic.h"
31
32namespace proofs {
33template <class Logic, size_t IndexBits = CborConstants::kIndexBits>
34class Cbor {
35 public:
36 using Field = typename Logic::Field;
37 using EltW = typename Logic::EltW;
38 using BitW = typename Logic::BitW;
39 using v8 = typename Logic::v8;
40 static constexpr size_t kIndexBits = IndexBits;
41 static constexpr size_t kNCounters = CborConstants::kNCounters;
42 using bv_counters = typename Logic::template bitvec<kNCounters>;
43
44 // a bitvector that contains an index into the input
45 // (byte) array.
46 using vindex = typename Logic::template bitvec<kIndexBits>;
47
48 // does not yet work in binary fields
49 static_assert(!Field::kCharacteristicTwo);
50
51 explicit Cbor(const Logic& l)
52 : l_(l), ba_count_(l), ba_byte_(l), ba_index_(l), bp_(l) {}
53
55 EltW invprod_decode; // inverse of a certain product, see assert_decode()
56 EltW cc0; // initial value of counter[0]
57 EltW invprod_parse; // inverse of a certain product, see assert_parse()
58 };
59
61 EltW encoded_sel_header;
62 };
63
64 //------------------------------------------------------------
65 // Decoder (lexer)
66 //------------------------------------------------------------
67 struct decode {
68 BitW arrayp;
69 BitW mapp;
70 BitW itemsp;
71 BitW stringp;
72 BitW tagp;
73 BitW specialp;
74 BitW simple_specialp; // One of false, true, null, or undefined.
75 BitW count0_23;
76 BitW count24;
77 BitW invalid;
78 BitW length_plus_next_v8;
79 BitW count_is_next_v8;
80 BitW header;
81 EltW length; // of this item
82 EltW as_field_element;
83 EltW count_as_field_element;
84 v8 as_bits;
85 };
86
87 // extract whatever we can from one v8
88 struct decode decode_one_v8(const v8& v) const {
89 const Logic& L = l_; // shorthand
90 struct decode s;
91 L.vassert_is_bit(v);
92
93 // v = type:3 count:5
94 auto count = L.template slice<0, 5>(v);
95 auto type = L.template slice<5, 8>(v);
96
97 s.itemsp = L.veqmask(type, /*mask*/ 0b110, /*val*/ 0b100);
98 s.stringp = L.veqmask(type, /*mask*/ 0b110, /*val*/ 0b010);
99
100 s.specialp = L.veq(type, 7);
101 s.tagp = L.veq(type, 6);
102 s.arrayp = L.land(&s.itemsp, L.lnot(type[0]));
103 s.mapp = L.land(&s.itemsp, type[0]);
104
105 // count0_23 = (0 <= count < 24) = ~(count == 11xxx)
106 s.count0_23 = L.lnot(L.veqmask(count, /*mask*/ 0b11000, /*val*/ 0b11000));
107
108 s.count24 = L.veq(count, 24);
109
110 BitW count20_23 = L.veqmask(count, /*mask*/ 0b11100, /*val*/ 0b10100);
111 s.simple_specialp = L.land(&s.specialp, count20_23);
112
113 // stringp && count24
114 s.length_plus_next_v8 =
115 L.veqmask(v, /*mask*/ 0b110'11111, /*val*/ 0b010'11000);
116
117 // itemsp && count24
118 s.count_is_next_v8 =
119 L.veqmask(v, /*mask*/ 0b110'11111, /*val*/ 0b100'11000);
120
121 // invalid = (specialp && !simple_specialp) || (!count24 && !count0_23)
122 auto lhs = L.land(&s.specialp, L.lnot(s.simple_specialp));
123 auto bad_count = L.lor_exclusive(&s.count24, s.count0_23);
124 s.invalid = L.lor(&lhs, L.lnot(bad_count));
125
126 s.count_as_field_element = ba_count_.as_field_element(count);
127
128 // Length is the length of the item, including the header.
129 //
130 // 1 for header
131 // +1 if (count24)
132 // +count if (stringp && count0_23);
133 s.length = L.konst(1);
134 s.length = L.add(&s.length, L.eval(s.count24));
135 auto str_23 = L.land(&s.stringp, s.count0_23);
136 auto e_str_23 = L.eval(str_23);
137 auto adjust_if_string = L.mul(&e_str_23, s.count_as_field_element);
138 s.length = L.add(&s.length, adjust_if_string);
139
140 s.as_field_element = ba_byte_.as_field_element(v);
141 s.as_bits = v;
142
143 s.header = L.bit(0); // for now
144 return s;
145 }
146
147 void assert_decode(size_t n, const decode ds[/*n*/],
148 const position_witness pw[/*n*/],
149 const global_witness& gw) const {
150 const Logic& L = l_; // shorthand
151 Scan<Logic> SC(l_);
152
153 // -------------------------------------------------------------
154 // Decoder didn't fail
155 for (size_t i = 0; i < n; ++i) {
156 L.assert_implies(&ds[i].header, L.lnot(ds[i].invalid));
157 }
158 // if LENGTH_PLUS_NEXT_V8 is TRUE in the last position,
159 // then the input is invalid.
160 L.assert_implies(&ds[n - 1].header, L.lnot(ds[n - 1].length_plus_next_v8));
161
162 // if COUNT_IS_NEXT_V8 is TRUE in the last position,
163 // then the input is invalid.
164 L.assert_implies(&ds[n - 1].header, L.lnot(ds[n - 1].count_is_next_v8));
165
166 // -------------------------------------------------------------
167 // Headers are where they are supposed to be.
168 // First, compute the segmented scan
169 // slen[i] = header[i] ? length[i] : (slen[i-1] + mone[i])
170 std::vector<EltW> mone(n);
171 std::vector<BitW> header(n);
172 std::vector<EltW> length(n);
173 std::vector<EltW> slen_next(n);
174
175 for (size_t i = 0; i + 1 < n; ++i) {
176 mone[i] = L.konst(L.mone());
177 header[i] = ds[i].header;
178 length[i] = ds[i].length;
179 if (i + 1 < n) {
180 auto len_i =
181 L.lmul(&ds[i].length_plus_next_v8, ds[i + 1].as_field_element);
182 length[i] = L.add(&length[i], len_i);
183 }
184 }
185
186 SC.add(n, slen_next.data(), header.data(), length.data(), mone.data());
187
188 // Now check the headers.
189 {
190 // "The first position is a header"
191 L.assert1(header[0]);
192 }
193
194 {
195 auto one = L.konst(1);
196 // "\A I : (SLEN_NEXT[I] == 1) IFF HEADER[I+1]"
197 {
198 // "\A I : HEADER[I+1] => (SLEN_NEXT[I] == 1)"
199 for (size_t i = 0; i + 1 < n; ++i) {
200 auto implies = L.lmul(&header[i + 1], L.sub(&slen_next[i], one));
201 L.assert0(implies);
202 }
203 }
204 {
205 // "\A I : (SLEN_NEXT[I] == 1) => HEADER[i+1] "
206 // Verify via the invertibility of
207 //
208 // PROD_{I, L} HEADER[I+1] ? 1 : (SLEN_NEXT[I] - 1)
209 //
210 auto f = [&](size_t i) {
211 return L.mux(&header[i + 1], &one, L.sub(&slen_next[i], one));
212 };
213 EltW prod = L.mul(0, n - 1, f);
214 auto want_one = L.mul(&prod, gw.invprod_decode);
215 L.assert_eq(&want_one, one);
216 }
217 }
218 }
219
220 //------------------------------------------------------------
221 // Parser
222 //------------------------------------------------------------
223 using counters = std::array<EltW, kNCounters>;
225 bv_counters sel;
226 counters c;
227 };
228
229 void parse(size_t n, parse_output ps[/*n*/], const decode ds[/*n*/],
230 const position_witness pw[/*n*/], const global_witness& gw) const {
231 std::vector<EltW> ddss(n);
232 std::vector<BitW> SS(n);
233 std::vector<EltW> AA(n);
234 std::vector<EltW> BB(n);
235
236 const Logic& L = l_; // shorthand
237 Scan<Logic> SC(l_);
238
239 for (size_t i = 0; i < n; ++i) {
240 ps[i].sel = bp_.pluckj(pw[i].encoded_sel_header);
241 }
242
243 auto mone = L.konst(L.mone());
244 for (size_t l = 0; l < kNCounters; ++l) {
245 for (size_t i = 0; i < n; ++i) {
246 // at the selected headers, decrement the level-L counter.
247 auto dp = L.land(&ds[i].header, ps[i].sel[l]);
248 ddss[i] = L.lmul(&dp, mone);
249 }
250
251 if (l == 0) {
252 // do level-0 as an unsegmented parallel prefix
253 // on DDSS starting at CC0.
254 // One can achieve the same effect by using the segmented prefix
255 // after initializing SS and AA as follows:
256 //
257 // SS[0] = L.bit(1);
258 // AA[0] = gw.cc0;
259 // for (size_t i = 1; i < n; ++i) {
260 // SS[i] = L.bit(0);
261 // AA[i] = L.konst(0);
262 // }
263 //
264 // The compiler is smart enough to constant-fold the segment
265 // SS[i] and produces the same circuit in both cases, but
266 // there is no point in wasting compiler time and the
267 // unsegmented prefix is more straightforward anyway.
268 //
269 // Note that AA, SS are uninitialized here. They will be initialized
270 // below for the next level.
271 ddss[0] = gw.cc0;
272 SC.add(n, BB.data(), ddss.data());
273 } else {
274 SC.add(n, BB.data(), SS.data(), AA.data(), ddss.data());
275 }
276
277 // output the result of the parallel prefix
278 for (size_t i = 0; i < n; ++i) {
279 ps[i].c[l] = BB[i];
280 }
281
282 // prepare SS, AA for the next level
283 for (size_t i = 0; i < n; ++i) {
284 EltW newc = L.eval(ds[i].tagp);
285 EltW count = ds[i].count_as_field_element;
286 if (i + 1 < n) {
287 count = L.mux(&ds[i].count_is_next_v8, &ds[i + 1].as_field_element,
288 count);
289 }
290 newc = L.add(&newc, L.lmul(&ds[i].itemsp, count));
291 newc = L.add(&newc, L.lmul(&ds[i].mapp, count));
292 AA[i] = newc;
293
294 auto sel = L.land(&ps[i].sel[l], ds[i].header);
295 auto tag = L.lor(&ds[i].tagp, ds[i].itemsp);
296 SS[i] = L.land(&sel, tag);
297 }
298 }
299
300 // Assert that we don't want to start new segments at a level
301 // that does not exist.
302 for (size_t i = 0; i < n; ++i) {
303 L.assert0(SS[i]);
304 }
305 }
306
307 void assert_parse(size_t n, const decode ds[/*n*/],
308 const parse_output ps[/*n*/],
309 const global_witness& gw) const {
310 const Logic& L = l_; // shorthand
311
312 for (size_t i = 0; i < n; ++i) {
313 // "The SEL witnesses are mutually exclusive."
314 // Verify by asserting that they are all bits
315 // and that their sum (in the field) is a bit.
316 auto sum = L.bit(0);
317 for (size_t l = 0; l < kNCounters; ++l) {
318 L.assert_is_bit(ps[i].sel[l]);
319 sum = L.lor_exclusive(&sum, ps[i].sel[l]);
320 }
321 L.assert_is_bit(sum);
322
323 // "at a header, at least one SEL bit is set"
324 L.assert_implies(&ds[i].header, sum);
325 }
326
327 // "All counters are zero at the end of the input"
328 // COUNTER[I][L] is the state of the parser at the end
329 // of position I, so COUNTER[N-1][L] is the final state.
330 for (size_t l = 0; l < kNCounters; ++l) {
331 L.assert0(ps[n - 1].c[l]);
332 }
333
334 // SEL[0][0] is set. We implicitly define COUNTER[-1][L] to make
335 // this the correct choice.
336 L.assert1(ps[0].sel[0]);
337
338 for (size_t i = 0; i + 1 < n; ++i) {
339 // "If SEL[I+1][L] is set, then COUNTER[I][L] is the nonzero
340 // counter of maximal L. (COUNTER[I][L] contains the output
341 // counter of stage I, which affects SEL[I+1].) Here we check
342 // maximality: COUNTER[I][J]=0 for J>L. See below for
343 // SEL[I+1][L] => (COUNTER[I][L] != 0).
344 BitW b = ps[i + 1].sel[0];
345 for (size_t l = 1; l < kNCounters; ++l) {
346 // b => COUNTER[i][l] == 0
347 L.assert0(L.lmul(&b, ps[i].c[l]));
348 b = L.lor(&b, ps[i + 1].sel[l]);
349 }
350 }
351
352 // "SEL[I+1][L] => (COUNTER[I][L] != 0)"
353 // Check via the invertibility of
354 //
355 // PROD_{I, L} SEL[I+1][L] ? COUNTER[I][L] : 1
356 std::vector<EltW> prod(kNCounters);
357
358 auto one = L.konst(1);
359 for (size_t l = 0; l < kNCounters; ++l) {
360 auto f = [&](size_t i) {
361 return L.mux(&ps[i + 1].sel[l], &ps[i].c[l], one);
362 };
363 prod[l] = L.mul(0, n - 1, f);
364 }
365
366 EltW p = L.mul(0, kNCounters, [&](size_t l) { return prod[l]; });
367 auto want_one = L.mul(&p, gw.invprod_parse);
368 L.assert_eq(&want_one, one);
369 }
370
371 //------------------------------------------------------------
372 // "J is the header of a string of length LEN containing BYTES"
373 //------------------------------------------------------------
374 void assert_text_at(size_t n, const vindex& j, size_t len,
375 const uint8_t bytes[/*len*/],
376 const decode ds[/*n*/]) const {
377 const Logic& L = l_; // shorthand
378 const Routing<Logic> R(L);
379
380 // we don't handle long strings
381 proofs::check(len < 24, "len < 24");
382
383 assert_header(n, j, ds);
384
385 std::vector<EltW> A(n);
386 for (size_t i = 0; i < n; ++i) {
387 A[i] = ds[i].as_field_element;
388 }
389
390 // shift len+1 bytes, including the header.
391 std::vector<EltW> B(len + 1);
392 const EltW defaultA = L.konst(256); // a constant that cannot appear in A[]
393 R.shift(j, len + 1, B.data(), n, A.data(), defaultA, /*unroll=*/3);
394
395 size_t expected_header = (3 << 5) + len;
396 L.assert_eq(&B[0], L.konst(expected_header));
397 for (size_t i = 0; i < len; ++i) {
398 auto bi = L.konst(bytes[i]);
399 L.assert_eq(&B[i + 1], bi);
400 }
401 }
402
403 //------------------------------------------------------------
404 // "J is a header containing unsigned U."
405 //------------------------------------------------------------
406 void assert_unsigned_at(size_t n, const vindex& j, uint64_t u,
407 const decode ds[/*n*/]) const {
408 // only small u for now
409 proofs::check(u < 24, "u < 24");
410
411 size_t expected = (0 << 5) + u;
412 assert_atom_at(n, j, l_.konst(expected), ds);
413 }
414
415 //------------------------------------------------------------
416 // "J is a header containing negative U." (U >= 0, and
417 // CBOR distinguishes 0 from -0 apparently)
418 //------------------------------------------------------------
419 void assert_negative_at(size_t n, const vindex& j, uint64_t u,
420 const decode ds[/*n*/]) const {
421 // only small u for now
422 proofs::check(u < 24, "u < 24");
423
424 size_t expected = (1 << 5) + u;
425 assert_atom_at(n, j, l_.konst(expected), ds);
426 }
427
428 //------------------------------------------------------------
429 // "J is a header containing a boolean primitive (0xF4 or 0xF5)."
430 //
431 //------------------------------------------------------------
432 void assert_bool_at(size_t n, const vindex& j, bool val,
433 const decode ds[/*n*/]) const {
434 size_t expected = (7 << 5) + (val ? 21 : 20);
435 assert_atom_at(n, j, l_.konst(expected), ds);
436 }
437
438 // Helps assemble the checks for date assertions.
439 void date_helper(size_t n, const vindex& j, const decode ds[/*n*/],
440 std::vector<v8>& B /* size 22 */) const {
441 const Logic& L = l_; // shorthand
442 const Routing<Logic> R(L);
443 assert_header(n, j, ds);
444
445 std::vector<v8> A(n);
446 for (size_t i = 0; i < n; ++i) {
447 A[i] = ds[i].as_bits;
448 }
449
450 const v8 defaultA =
451 L.template vbit<8>(0); // a constant that cannot appear in A[]
452 R.shift(j, 20 + 2, B.data(), n, A.data(), defaultA, /*unroll=*/3);
453
454 // Check for tag: date/time string.
455 L.vassert_eq(&B[0], L.template vbit<8>(0xc0));
456
457 // Check for string(20)
458 L.vassert_eq(&B[1], L.template vbit<8>(0x74));
459 }
460
461 //------------------------------------------------------------
462 // "J is a header containing date d < now." now is 20 bytes
463 // in the format 2023-11-01T09:00:00Z
464 //------------------------------------------------------------
465 void assert_date_before_at(size_t n, const vindex& j, const v8 now[/* 20 */],
466 const decode ds[/*n*/]) const {
467 const Logic& L = l_; // shorthand
468 const Memcmp<Logic> CMP(L);
469 std::vector<v8> B(20 + 2);
470 date_helper(n, j, ds, B);
471 auto lt = CMP.lt(20, &B[2], now);
472 L.assert1(lt);
473 }
474
475 //------------------------------------------------------------
476 // "J is a header containing date d > now." now is 20 bytes in the
477 // format 2023-11-01T09:00:00Z
478 // ------------------------------------------------------------
479 void assert_date_after_at(size_t n, const vindex& j, const v8 now[/* 20 */],
480 const decode ds[/*n*/]) const {
481 const Logic& L = l_; // shorthand
482 const Memcmp<Logic> CMP(L);
483 std::vector<v8> B(20 + 2);
484 date_helper(n, j, ds, B);
485 auto lt = CMP.lt(20, now, &B[2]);
486 L.assert1(lt);
487 }
488
489 //------------------------------------------------------------
490 // "J is a header containing represented by the byte EXPECTED in the
491 // input."
492 //------------------------------------------------------------
493 void assert_atom_at(size_t n, const vindex& j, const EltW& expected,
494 const decode ds[/*n*/]) const {
495 const Logic& L = l_; // shorthand
496 const Routing<Logic> R(L);
497
498 assert_header(n, j, ds);
499
500 std::vector<EltW> A(n);
501 for (size_t i = 0; i < n; ++i) {
502 A[i] = ds[i].as_field_element;
503 }
504
505 EltW B[1];
506 size_t unroll = 3;
507 R.shift(j, 1, B, n, A.data(), L.konst(256), unroll);
508 L.assert_eq(&B[0], expected);
509 }
510
511 //------------------------------------------------------------
512 // "J is a header beginning a byte array of length LEN that
513 // is the big-endian representation of EltW X."
514 // ------------------------------------------------------------
515 void assert_elt_as_be_bytes_at(size_t n, const vindex& j, size_t len, EltW X,
516 const decode ds[/*n*/]) const {
517 const Logic& L = l_; // shorthand
518 const Routing<Logic> R(L);
519
520 std::vector<EltW> A(n);
521 for (size_t i = 0; i < n; ++i) {
522 A[i] = ds[i].as_field_element;
523 }
524 EltW tx = L.konst(0), k256 = L.konst(256);
525
526 std::vector<EltW> B(2 + len);
527 size_t unroll = 3;
528 size_t si = 1;
529 R.shift(j, len + 2, B.data(), n, A.data(), L.konst(0), unroll);
530 if (len < 24) {
531 size_t expected_header = (2 << 5) + len;
532 auto eh = L.konst(expected_header);
533 L.assert_eq(&B[0], eh);
534 } else if (len < 256) {
535 size_t expected_header = (2 << 5) + 24;
536 auto eh = L.konst(expected_header);
537 L.assert_eq(&B[0], eh);
538 L.assert_eq(&B[1], L.konst(len));
539 si = 2;
540 } else {
541 check(false, "len >= 256");
542 }
543
544 for (size_t i = 0; i < len; ++i) {
545 auto tmp = L.mul(&tx, k256);
546 tx = L.add(&tmp, B[i + si]);
547 }
548
549 L.assert_eq(&tx, X);
550 }
551
552 //------------------------------------------------------------
553 // "Position j contains a header"
554 //------------------------------------------------------------
555 void assert_header(size_t n, const vindex& j, const decode ds[/*n*/]) const {
556 const Logic& L = l_; // shorthand
557
558 L.vassert_is_bit(j);
559
560 // giant dot product since the veq(j, .) terms are mutually exclusive.
561 auto f = [&](size_t i) { return L.land(&ds[i].header, L.veq(j, i)); };
562 L.assert1(L.lor_exclusive(0, n, f));
563 }
564
565 //------------------------------------------------------------
566 // "A map starts at position j"
567 //------------------------------------------------------------
568 void assert_map_header(size_t n, const vindex& j,
569 const decode ds[/*n*/]) const {
570 const Logic& L = l_; // shorthand
571
572 L.vassert_is_bit(j);
573
574 // giant dot product since the veq(j, .) terms are mutually exclusive.
575 auto f = [&](size_t i) {
576 auto eq_ji = L.veq(j, i);
577 auto dsi = L.land(&ds[i].mapp, ds[i].header);
578 return L.land(&eq_ji, dsi);
579 };
580 L.assert1(L.lor_exclusive(0, n, f));
581 }
582
583 //------------------------------------------------------------
584 // "Position M starts a map of level LEVEL. (K, V) are headers
585 // representing the J-th pair in that map"
586 //------------------------------------------------------------
587 void assert_map_entry(size_t n, const vindex& m, size_t level,
588 const vindex& k, const vindex& v, const vindex& j,
589 const decode ds[/*n*/],
590 const parse_output ps[/*n*/]) const {
591 const Logic& L = l_; // shorthand
592 const Routing<Logic> R(L);
593
594 assert_map_header(n, m, ds);
595 assert_header(n, k, ds);
596 assert_header(n, v, ds);
597
598 for (size_t l = 0; l < kNCounters; ++l) {
599 std::vector<EltW> A(n);
600 for (size_t i = 0; i < n; ++i) {
601 A[i] = ps[i].c[l];
602 }
603
604 // Select counters[m], counters[k], and counters[v].
605 EltW cm, ck, cv;
606
607 const size_t unroll = 3;
608 R.shift(m, 1, &cm, n, A.data(), L.konst(0), unroll);
609 R.shift(k, 1, &ck, n, A.data(), L.konst(0), unroll);
610 R.shift(v, 1, &cv, n, A.data(), L.konst(0), unroll);
611
612 if (l <= level) {
613 // Counters[L] must agree at the key, value, and root
614 // of the map.
615 L.assert_eq(&cm, ck);
616 L.assert_eq(&cm, cv);
617 } else if (l == level + 1) {
618 auto one = L.konst(1);
619 auto two = L.konst(2);
620 // LEVEL+1 counters must have the right number of decrements.
621 // Specifically, if the counter at the map is N, then the j-th
622 // key has N-(2*j+1) and the j-th value has N-(2*j+2)
623 auto twoj = L.mul(&two, ba_index_.as_field_element(j));
624 L.assert_eq(&cm, L.add(&ck, L.add(&twoj, one)));
625 L.assert_eq(&cm, L.add(&cv, L.add(&twoj, two)));
626 } else {
627 // not sure if this is necessary, but all other counters
628 // of CM are supposed to be zero.
629 L.assert0(cm);
630 }
631 }
632 }
633
634 //------------------------------------------------------------
635 // "JROOT is the first byte of the actual (unpadded) input and
636 // all previous bytes are 0"
637 //------------------------------------------------------------
638 void assert_input_starts_at(size_t n, const vindex& jroot,
639 const vindex& input_len,
640 const decode ds[/*n*/]) const {
641 const Logic& L = l_; // shorthand
642
643 L.assert1(L.vleq(input_len, n));
644 L.assert1(L.vlt(jroot, n));
645 auto tot = L.vadd(jroot, input_len);
646 L.vassert_eq(tot, n);
647
648 for (size_t i = 0; i < n; ++i) {
649 L.assert0(L.lmul(&ds[i].as_field_element, L.vlt(i, jroot)));
650 }
651 }
652
653 //------------------------------------------------------------
654 // Utilities
655 //------------------------------------------------------------
656 // The circuit accepts up to N input positions, of which
657 // INPUT_LEN are actual input and the rest are ignored.
658 void decode_all(size_t n, decode ds[/*n*/], const v8 in[/*n*/],
659 const position_witness pw[/*n*/]) const {
660 for (size_t i = 0; i < n; ++i) {
661 ds[i] = decode_one_v8(in[i]);
662 ds[i].header = bp_.pluckb(pw[i].encoded_sel_header);
663 }
664 }
665
666 void decode_and_assert_decode(size_t n, decode ds[/*n*/], const v8 in[/*n*/],
667 const position_witness pw[/*n*/],
668 const global_witness& gw) const {
669 decode_all(n, ds, in, pw);
670 assert_decode(n, ds, pw, gw);
671 }
672
673 void decode_and_assert_decode_and_parse(size_t n, decode ds[/*n*/],
674 parse_output ps[/*n*/],
675 const v8 in[/*n*/],
676 const position_witness pw[/*n*/],
677 const global_witness& gw) const {
678 decode_and_assert_decode(n, ds, in, pw, gw);
679 parse(n, ps, ds, pw, gw);
680 assert_parse(n, ds, ps, gw);
681 }
682
683 private:
684 const Logic& l_;
685 const BitAdder<Logic, 5> ba_count_;
686 const BitAdder<Logic, 8> ba_byte_;
687 const BitAdder<Logic, kIndexBits> ba_index_;
688 const CborPlucker<Logic, kNCounters> bp_;
689};
690} // namespace proofs
691
692#endif // PRIVACY_PROOFS_ZK_LIB_CIRCUITS_CBOR_PARSER_CBOR_H_
Definition logic.h:38
Definition scan.h:24
Definition cbor.h:67
Definition cbor.h:54
Definition cbor.h:224
Definition cbor.h:60
Definition logic.h:130