Longfellow ZK 0290cb32
Loading...
Searching...
No Matches
cbor_witness.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_WITNESS_H_
16#define PRIVACY_PROOFS_ZK_LIB_CIRCUITS_CBOR_PARSER_CBOR_WITNESS_H_
17
18#include <stddef.h>
19#include <stdint.h>
20
21#include <array>
22
23#include "circuits/cbor_parser/cbor_constants.h"
24#include "circuits/cbor_parser/cbor_pluck.h"
25#include "util/panic.h"
26
27namespace proofs {
28template <class Field>
29class CborWitness {
30 public:
31 using Elt = typename Field::Elt;
32 using CElt = typename Field::CElt;
33 static constexpr size_t kNCounters = CborConstants::kNCounters;
34 static constexpr size_t kIndexBits = CborConstants::kIndexBits;
35 using counters = std::array<size_t, kNCounters>;
36 using vindex = std::array<Elt, kIndexBits>;
37
39 Elt encoded_sel_header;
40
41 // SLEN output value, used for debugging but not fed to the circuit
42 size_t slen_next_debug;
43 // counter values, used for debugging but not fed to the circuit
44 counters cc_debug;
45 size_t isel_debug;
46 };
47
49 Elt invprod_decode;
50 CElt cc0_counter;
51 Elt invprod_parse;
52 };
53
54 using v8 = std::array<Elt, 8>;
55
56 explicit CborWitness(const Field& F) : f_(F) {}
57
58 // Return an index as an array of Elt, which can be stored into W[]
59 vindex index(size_t j) const {
60 const Field& F = f_; // shorthand
61 vindex r;
62 for (size_t i = 0; i < kIndexBits; ++i) {
63 r[i] = F.of_scalar((j >> i) & 1);
64 }
65 return r;
66 }
67
68 void fill_witnesses(size_t n, size_t input_len, const uint8_t bytes[/*n*/],
69 v8 in[/*n*/], position_witness pw[/*n*/],
70 global_witness& gw) const {
71 const Field& F = f_; // shorthand
72
73 // First pass to compute the number of top-level items. In the
74 // second pass, we will use this value to that all counters are 0
75 // at the end of the input.
76 size_t top_level_items;
77 {
78 // start with a value of cc[0] guaranteed not to
79 // underflow counter 0.
80 counters cc{{n + 1}};
81
82 size_t slen = 1;
83 for (size_t i = 0; i < n; ++i) {
84 bool overflow;
85 bool header = (slen == 1);
86 cc = counters_next(bytes[i], header,
87 /*have_nextb=*/(i + 1) < n,
88 /*nextb=*/(i + 1) < n ? bytes[i + 1] : 0, cc,
89 &overflow);
90 proofs::check(!overflow, "!overflow");
91 slen = next_slen(slen, n, bytes, i);
92 }
93
94 top_level_items = (n + 1) - cc[0];
95 }
96
97 // second pass starting with the correct counter values
98 {
99 counters cc{{top_level_items}};
100 Elt prod_parse = F.one();
101 Elt prod_decode = F.one();
102
103 size_t slen = 1;
104 for (size_t i = 0; i < n; ++i) {
105 bool overflow;
106 bool header = (slen == 1);
107
108 // Require all bytes to be 0 except the last N-INPUT_LEN.
109 // That is, the input must be aligned towards the end
110 // of arrays, and padded with zeroes at the beginning.
111 proofs::check(input_len <= n, "input_len <= n");
112 if (i + input_len < n) {
113 proofs::check(bytes[i] == 0, "bytes[i] == 0");
114 }
115
116 // set up input
117 for (size_t j = 0; j < 8; ++j) {
118 in[i][j] = F.of_scalar((bytes[i] >> j) & 1);
119 }
120
121 if (!header) {
122 F.mul(prod_decode, F.znz_indicator(F.as_counter(slen - 1)));
123 }
124
125 // set up parse witness
126 size_t isel = kNCounters;
127 for (size_t l = kNCounters; l-- > 0;) {
128 if (cc[l] != 0) {
129 if (i > 0) {
130 F.mul(prod_parse, F.znz_indicator(F.as_counter(cc[l])));
131 }
132 isel = l;
133 break;
134 }
135 }
136
137 cc = counters_next(bytes[i], header,
138 /*have_nextb=*/(i + 1) < n,
139 /*nextb=*/(i + 1) < n ? bytes[i + 1] : 0, cc,
140 &overflow);
141 proofs::check(!overflow, "!overflow");
142 if (i == 0) {
143 gw.cc0_counter = F.as_counter(cc[0]);
144 }
145 pw[i].cc_debug = cc;
146
147 // set up decode witness
148 size_t slen_next = next_slen(slen, n, bytes, i);
149 pw[i].slen_next_debug = slen_next;
150
151 // encode witnesses
152 pw[i].encoded_sel_header =
153 cbor_plucker_point<Field, kNCounters>()(header, isel, F);
154 pw[i].isel_debug = isel;
155
156 // advance slen
157 slen = slen_next;
158 }
159
160 gw.invprod_decode = F.invertf(prod_decode);
161 gw.invprod_parse = F.invertf(prod_parse);
162 }
163 }
164
165 private:
166 static size_t next_slen(size_t slen, size_t n, const uint8_t bytes[/*n*/],
167 size_t i) {
168 size_t slenm1 = slen - 1;
169 bool header = (slenm1 == 0);
170 if (header) {
171 if (i + 1 < n) {
172 return item_length(bytes[i], true, bytes[i + 1]);
173 } else {
174 return item_length(bytes[i], false, 0);
175 }
176 } else {
177 return slenm1;
178 }
179 }
180
181 // TODO [matteof 2023-11-03] Should not panic() here.
182 static size_t item_length(uint8_t b, bool valid_nextb, uint8_t nextb) {
183 size_t type = (b >> 5) & 0x7u;
184 size_t count = b & 0x1Fu;
185 bool count0_23 = (count < 24);
186 bool count24 = (count == 24);
187 bool count25 = (count == 25);
188 bool count26 = (count == 26);
189 bool count27 = (count == 27);
190
191 switch (type) {
192 case 0: /* unsigned */
193 case 1: /* negative integer */
194 case 6: /* tag */
195 if (count0_23) {
196 return 1;
197 } else if (count24) {
198 return 2;
199 } else if (count25) {
200 return 3;
201 } else if (count26) {
202 return 5;
203 } else if (count27) {
204 return 9;
205 } else {
206 check(false, "unwitnessed count (atom)");
207 return 0;
208 }
209
210 case 4: /* array */
211 case 5: /* map */
212 if (count0_23) {
213 return 1;
214 } else if (count24) {
215 return 2;
216 } else {
217 check(false, "unwitnessed count (item)");
218 return 0;
219 }
220
221 case 2: /* bytes */
222 case 3: /* text */
223 if (count0_23) {
224 return 1 + count;
225 } else if (count24) {
226 if (valid_nextb) {
227 return 2 + nextb;
228 } else {
229 check(false, "invalid nextb");
230 return 0;
231 }
232 } else {
233 check(false, "unwitnessed count (bytes)");
234 return 0;
235 }
236
237 case 7: /* special */
238 check(false, "unwitnessed special");
239 return 0;
240
241 default:
242 check(false, "can't happen");
243 return 0;
244 }
245 }
246
247 static size_t decode_count(size_t count_in_header, bool have_nextb,
248 uint8_t nextb) {
249 if (count_in_header < 24) {
250 return count_in_header;
251 } else if (count_in_header == 24) {
252 if (have_nextb) {
253 return nextb;
254 } else {
255 check(false, "!have_nextb");
256 }
257 } else {
258 check(false, "count > 24");
259 }
260 return 0xdeadbeef;
261 }
262
263 static counters counters_next(uint8_t b, bool header, bool have_nextb,
264 uint8_t nextb, const counters& c,
265 bool* overflow) {
266 size_t type = (b >> 5) & 0x7u;
267 size_t count_in_header = b & 0x1Fu;
268 bool tagp = (type == 6);
269 bool arrayp = (type == 4);
270 bool mapp = (type == 5);
271
272 counters c1 = c;
273 *overflow = false;
274
275 for (size_t l = kNCounters; l-- > 0;) {
276 if (c[l] != 0) {
277 if (header) {
278 c1[l] = c[l] - 1;
279
280 if (tagp) {
281 if (l + 1 < kNCounters) {
282 c1[l + 1] = 1;
283 } else {
284 *overflow = true;
285 }
286 } else if (arrayp) {
287 if (l + 1 < kNCounters) {
288 c1[l + 1] = decode_count(count_in_header, have_nextb, nextb);
289 } else {
290 *overflow = true;
291 }
292 } else if (mapp) {
293 if (l + 1 < kNCounters) {
294 c1[l + 1] = 2 * decode_count(count_in_header, have_nextb, nextb);
295 } else {
296 *overflow = true;
297 }
298 }
299 }
300 break;
301 }
302 }
303
304 return c1;
305 }
306
307 private:
308 const Field& f_;
309};
310} // namespace proofs
311
312#endif // PRIVACY_PROOFS_ZK_LIB_CIRCUITS_CBOR_PARSER_CBOR_WITNESS_H_
Definition cbor_witness.h:48
Definition cbor_witness.h:38
Definition gf2_128.h:285
Definition gf2_128.h:63