Skip to content

Commit 831191b

Browse files
more optimizations
supports parsing an pure array type array get methods work on the root if root is an array added get_literal.nr and get_number.nr and get_string.nr added validation step that checks json is well formed
1 parent e928efc commit 831191b

File tree

12 files changed

+829
-753
lines changed

12 files changed

+829
-753
lines changed

out.txt

Lines changed: 3 additions & 3 deletions
Large diffs are not rendered by default.

src/getters.nr

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ use crate::redux_tables::{
1111
};
1212
use crate::keyhash::get_keyhash;
1313

14-
use crate::keymap::KeyLen; // todo make param
15-
1614
struct KeySearchResult {
1715
found: bool,
1816
target_lt_smallest_entry: bool,
@@ -59,12 +57,12 @@ impl JSONLiteral {
5957
}
6058
global MaxKeyBytes = 32;
6159

62-
impl<let NumBytes: u32, let NumPackedFields: u16, let TranscriptEntries: u32> JSON<NumBytes,NumPackedFields,TranscriptEntries> {
60+
impl<let NumBytes: u32, let NumPackedFields: u16, let MaxNumTokens: u16, let MaxNumValues: u16> JSON<NumBytes,NumPackedFields, MaxNumTokens, MaxNumValues> {
6361

6462
unconstrained fn find_key_in_map(self, target: Field) -> Field {
6563
let mut found_index: Field = 0;
6664
let mut found: bool = false;
67-
for i in 0..TranscriptEntries {
65+
for i in 0..MaxNumValues {
6866
let key_hash= self.key_hashes[i];
6967
if (key_hash == target) {
7068
found_index = i as Field;
@@ -84,7 +82,7 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let TranscriptEntries: u32> JS
8482
let mut rhs_minimum: Field = -1;
8583
let mut lhs_maximum_index: Field = 0;
8684
let mut rhs_minimum_index: Field = 0;
87-
for i in 0..TranscriptEntries {
85+
for i in 0..MaxNumValues {
8886
let key_hash= self.key_hashes[i];
8987
if (key_hash == target) {
9088
found_index = i as Field;
@@ -102,7 +100,7 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let TranscriptEntries: u32> JS
102100
}
103101
}
104102
let target_lt_smallest_entry = target.lt(self.key_hashes[0]);
105-
let target_gt_largest_entry = self.key_hashes[TranscriptEntries - 1].lt(target);
103+
let target_gt_largest_entry = self.key_hashes[MaxNumValues - 1].lt(target);
106104

107105
let result_not_first_or_last = !target_lt_smallest_entry & !target_gt_largest_entry & !found;
108106

@@ -114,7 +112,7 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let TranscriptEntries: u32> JS
114112
rhs_index = rhs_index * (1 - target_lt_smallest_entry as Field);
115113

116114
// we rely here on the fact that target_gt_largest_entry and result_not_first_or_last are mutually exclusive
117-
lhs_index = lhs_index + target_gt_largest_entry as Field * (TranscriptEntries as Field - 1);
115+
lhs_index = lhs_index + target_gt_largest_entry as Field * (MaxNumValues as Field - 1);
118116

119117
// If target is FOUND, we want the following:
120118
// keyhash[target_index] - 1 < hash < keyhash[target_index] + 1
@@ -419,7 +417,7 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let TranscriptEntries: u32> JS
419417

420418
assert(entry.entry_type == BEGIN_OBJECT_TOKEN, "key does not describe an object");
421419

422-
let mut result: Option<JSON<NumBytes, NumPackedFields, TranscriptEntries>> = Option::none();
420+
let mut result: Option<JSON<NumBytes, NumPackedFields, MaxNumTokens, MaxNumValues>> = Option::none();
423421
if (exists) {
424422
let mut r = self;
425423
r.layer_id = entry.parent_index;
@@ -438,7 +436,7 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let TranscriptEntries: u32> JS
438436
// TODO: ADD A layer_context VARIABLE INTO JSON WHICH DESCRIBES WHETHER WE ARE AN OBJECT, ARRAY OR SINGLE VALUE
439437
assert(entry.entry_type == BEGIN_ARRAY_TOKEN, "key does not describe an object");
440438

441-
let mut result: Option<JSON<NumBytes, NumPackedFields, TranscriptEntries>> = Option::none();
439+
let mut result: Option<JSON<NumBytes, NumPackedFields, MaxNumTokens, MaxNumValues>> = Option::none();
442440
if (exists) {
443441
let mut r = self;
444442
r.layer_id = entry.parent_index;

src/json_entry.nr

Lines changed: 76 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,51 @@
1+
struct JSONContextStackEntry {
2+
num_entries: Field,
3+
context: Field,
4+
current_key_length: Field,
5+
current_key_index: Field,
6+
json_index: Field,
7+
entry_pointer: Field,
8+
current_identity: Field
9+
}
10+
impl JSONContextStackEntry {
11+
unconstrained fn __from_field(f: Field) -> Self {
12+
// 19 + 6 = 25
13+
let bytes = f.to_be_bytes(13);
14+
let context = bytes[0] as Field;
15+
let num_entries = bytes[1] as Field * 0x100 + bytes[2] as Field;
16+
let current_key_length = bytes[3] as Field * 0x100 + bytes[4] as Field;
17+
let current_key_index = bytes[5] as Field * 0x100 + bytes[6] as Field;
18+
let json_index = bytes[7] as Field * 0x100 + bytes[8] as Field;
19+
let entry_pointer = bytes[9] as Field * 0x100 + bytes[10] as Field;
20+
let current_identity = bytes[11] as Field * 0x100 + bytes[12] as Field;
21+
JSONContextStackEntry { num_entries, context, current_key_length, current_key_index, json_index, entry_pointer, current_identity }
22+
}
23+
24+
fn from_field(f: Field) -> Self {
25+
let result = JSONContextStackEntry::__from_field(f);
26+
27+
result.context.assert_max_bit_size(8);
28+
result.num_entries.assert_max_bit_size(16);
29+
result.current_key_length.assert_max_bit_size(16);
30+
result.current_key_index.assert_max_bit_size(16);
31+
result.json_index.assert_max_bit_size(16);
32+
result.entry_pointer.assert_max_bit_size(16);
33+
result.current_identity.assert_max_bit_size(16);
34+
assert(result.to_field() == f); // 3
35+
result
36+
}
37+
38+
fn to_field(self) -> Field {
39+
self.current_identity
40+
+ self.entry_pointer * 0x10000
41+
+ self.json_index * 0x100000000
42+
+ self.current_key_index * 0x1000000000000
43+
+ self.current_key_length * 0x10000000000000000
44+
+ self.num_entries * 0x100000000000000000000
45+
+ self.context * 0x1000000000000000000000000
46+
}
47+
}
48+
149
struct JSONEntry {
250
array_pointer: Field,
351
entry_type: Field,
@@ -22,27 +70,16 @@ impl JSONEntry {
2270
}
2371
}
2472

25-
fn to_field(self) -> Field {
26-
self.id +
27-
self.parent_index * 0x10000
28-
+ self.array_pointer * 0x10000000000000000 // 2 bytes
29-
+ self.child_pointer * 0x100000000000000000000 // 2 bytes
30-
+ self.num_children * 0x1000000000000000000000000 // 2 bytes
31-
+ self.json_pointer * 0x10000000000000000000000000000 // 2 bytes
32-
+ self.json_length * 0x100000000000000000000000000000000 // 2 bytes
33-
+ self.entry_type * 0x100000000000000000000000000000000000000 // 1 byte
34-
// 4 gates. oof
35-
}
36-
3773
unconstrained fn __extract_parent_index_from_field(f: Field) -> (Field, Field, Field) {
3874
let entry = JSONEntry::from_field(f);
3975
let low = entry.id;
4076
let mid = entry.parent_index;
4177
let hi = (f - low - mid * 0x10000) / 0x100000000;
4278
(low, mid, hi)
4379
}
80+
4481
fn add_child_pointer_into_field(f: Field, child_pointer: Field) -> Field {
45-
f + child_pointer * 0x1000000000000
82+
f + child_pointer * 0x100000000000000000000
4683
}
4784
unconstrained fn __extract_entry_type_and_id_from_field(f: Field) -> (Field, Field, Field) {
4885
let entry = JSONEntry::from_field(f);
@@ -98,7 +135,7 @@ impl JSONEntry {
98135
// 10 gates?
99136
parent_index
100137
}
101-
fn from_field(f: Field) -> Self {
138+
unconstrained fn __from_field(f: Field) -> Self {
102139
let bytes: [u8; 20] = f.to_be_bytes(20).as_array(); // 10.5 gates
103140

104141
let entry_type = bytes[0] as Field;
@@ -111,16 +148,34 @@ impl JSONEntry {
111148
let parent_index = bytes[16] as Field * 0x100 + bytes[17] as Field; // 6 gates
112149
let id = bytes[18] as Field * 0x100 + bytes[19] as Field; // 6 gates
113150

114-
std::as_witness(json_length);
115-
std::as_witness(json_pointer);
116-
std::as_witness(num_children);
117-
std::as_witness(child_pointer);
118-
std::as_witness(array_pointer);
119-
std::as_witness(parent_index);
120-
std::as_witness(id);
121151
// this might cost 17 gates? oof
122152
JSONEntry { array_pointer, child_pointer, num_children, json_pointer, json_length, entry_type, parent_index, id }
123153
}
154+
155+
fn to_field(self) -> Field {
156+
self.id +
157+
self.parent_index * 0x10000
158+
+ self.array_pointer * 0x10000000000000000 // 2 bytes
159+
+ self.child_pointer * 0x100000000000000000000 // 2 bytes
160+
+ self.num_children * 0x1000000000000000000000000 // 2 bytes
161+
+ self.json_pointer * 0x10000000000000000000000000000 // 2 bytes
162+
+ self.json_length * 0x100000000000000000000000000000000 // 2 bytes
163+
+ self.entry_type * 0x100000000000000000000000000000000000000 // 1 byte
164+
// 4 gates. oof
165+
}
166+
fn from_field(f: Field) -> Self {
167+
let result = JSONEntry::__from_field(f);
168+
result.entry_type.assert_max_bit_size(8);
169+
result.json_length.assert_max_bit_size(16);
170+
result.json_pointer.assert_max_bit_size(16);
171+
result.num_children.assert_max_bit_size(16);
172+
result.child_pointer.assert_max_bit_size(16);
173+
result.array_pointer.assert_max_bit_size(16);
174+
result.parent_index.assert_max_bit_size(16);
175+
result.id.assert_max_bit_size(16);
176+
assert(result.to_field() == f);
177+
result
178+
}
124179
}
125180

126181
impl std::cmp::Eq for JSONEntry {

src/keyhash.nr

Lines changed: 2 additions & 132 deletions
Original file line numberDiff line numberDiff line change
@@ -164,113 +164,6 @@ global tail_path_multipliers_chunk3: [Field; 32] = [0x01000000000000000000000000
164164
global tail_path_multipliers_chunk2: [Field; 32] = [0x01000000000000000000000000000000000000000000000000, 0x01000000000000000000000000000000000000000000000000, 0x01000000000000000000000000000000000000000000000000, 0x01000000000000000000000000000000000000000000000000, 0x00, 0x00, 0x00, 0x00, 0x0100000000000000000000000000000000, 0x0100000000000000000000000000000000, 0x0100000000000000000000000000000000, 0x0100000000000000000000000000000000, 0x00, 0x00, 0x00, 0x00, 0x010000000000000000, 0x010000000000000000, 0x010000000000000000, 0x010000000000000000, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00];
165165
global tail_path_multipliers_chunk1: [Field; 32] = [0x0100000000000000000000000000000000000000000000000000000000, 0x0100000000000000000000000000000000000000000000000000000000, 0x00, 0x00, 0x01000000000000000000000000000000000000000000000000, 0x01000000000000000000000000000000000000000000000000, 0x00, 0x00, 0x010000000000000000000000000000000000000000, 0x010000000000000000000000000000000000000000, 0x00, 0x00, 0x0100000000000000000000000000000000, 0x0100000000000000000000000000000000, 0x00, 0x00, 0x01000000000000000000000000, 0x01000000000000000000000000, 0x00, 0x00, 0x010000000000000000, 0x010000000000000000, 0x00, 0x00, 0x0100000000, 0x0100000000, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00];
166166
global tail_path_multipliers_chunk0: [Field; 32] = [0x01000000000000000000000000000000000000000000000000000000000000, 0x00, 0x0100000000000000000000000000000000000000000000000000000000, 0x00, 0x010000000000000000000000000000000000000000000000000000, 0x00, 0x01000000000000000000000000000000000000000000000000, 0x00, 0x0100000000000000000000000000000000000000000000, 0x00, 0x010000000000000000000000000000000000000000, 0x00, 0x01000000000000000000000000000000000000, 0x00, 0x0100000000000000000000000000000000, 0x00, 0x010000000000000000000000000000, 0x00, 0x01000000000000000000000000, 0x00, 0x0100000000000000000000, 0x00, 0x010000000000000000, 0x00, 0x01000000000000, 0x00, 0x0100000000, 0x00, 0x010000, 0x00, 0x01, 0x00];
167-
// // what do we multiply 4 byte chunk by
168-
// global tail_path_multipliers_chunk2: [Field; 32] = [
169-
// /* 0 (00000) */ 0,
170-
// /* 1 (00001) */ 0,
171-
// /* 2 (00010) */ 0,
172-
// /* 3 (00011) */ 0,
173-
// /* 4 (00100) */ 1,
174-
// /* 5 (00101) */ 1,
175-
// /* 6 (00110) */ 1,
176-
// /* 7 (00111) */ 1,
177-
// /* 8 (01000) */ 0,
178-
// /* 9 (01001) */ 0,
179-
// /* 10 (01010) */ 0,
180-
// /* 11 (01011) */ 0,
181-
// /* 12 (01100) */ two_pow_64,
182-
// /* 13 (01101) */ two_pow_64,
183-
// /* 14 (01110) */ two_pow_64,
184-
// /* 15 (01111) */ two_pow_64,
185-
// /* 16 (10000) */ 0,
186-
// /* 17 (10001) */ 0,
187-
// /* 18 (10010) */ 0,
188-
// /* 19 (10011) */ 0,
189-
// /* 20 (10100) */ two_pow_128,
190-
// /* 21 (10101) */ two_pow_128,
191-
// /* 22 (10110) */ two_pow_128,
192-
// /* 23 (10111) */ two_pow_128,
193-
// /* 24 (11000) */ 0,
194-
// /* 25 (11001) */ 0,
195-
// /* 26 (11010) */ 0,
196-
// /* 27 (11011) */ 0,
197-
// /* 28 (11100) */ two_pow_128 * two_pow_64,
198-
// /* 29 (11101) */ two_pow_128 * two_pow_64,
199-
// /* 30 (11110) */ two_pow_128 * two_pow_64,
200-
// /* 31 (11111) */ two_pow_128 * two_pow_64
201-
// ];
202-
203-
// // what do we multiply 2 byte chunk by
204-
// global tail_path_multipliers_chunk1: [Field; 32] = [
205-
// /* 0 (00000) */ 0,
206-
// /* 1 (00001) */ 0,
207-
// /* 2 (00010) */ 1,
208-
// /* 3 (00011) */ 1,
209-
// /* 4 (00100) */ 0,
210-
// /* 5 (00101) */ 0,
211-
// /* 6 (00110) */ two_pow_32,
212-
// /* 7 (00111) */ two_pow_32,
213-
// /* 8 (01000) */ 0,
214-
// /* 9 (01001) */ 0,
215-
// /* 10 (01010) */ two_pow_64,
216-
// /* 11 (01011) */ two_pow_64,
217-
// /* 12 (01100) */ 0,
218-
// /* 13 (01101) */ 0,
219-
// /* 14 (01110) */ two_pow_64 * two_pow_32,
220-
// /* 15 (01111) */ two_pow_64 * two_pow_32,
221-
// /* 16 (10000) */ 0,
222-
// /* 17 (10001) */ 0,
223-
// /* 18 (10010) */ two_pow_128,
224-
// /* 19 (10011) */ two_pow_128,
225-
// /* 20 (10100) */ 0,
226-
// /* 21 (10101) */ 0,
227-
// /* 22 (10110) */ two_pow_128 * two_pow_32,
228-
// /* 23 (10111) */ two_pow_128 * two_pow_32,
229-
// /* 24 (11000) */ 0,
230-
// /* 25 (11001) */ 0,
231-
// /* 26 (11010) */ two_pow_128 * two_pow_64,
232-
// /* 27 (11011) */ two_pow_128 * two_pow_64,
233-
// /* 28 (11100) */ 0,
234-
// /* 29 (11101) */ 0,
235-
// /* 30 (11110) */ two_pow_128 * two_pow_64 * two_pow_32,
236-
// /* 31 (11111) */ two_pow_128 * two_pow_64 * two_pow_32
237-
// ];
238-
239-
// // what do we multiply 1 byte chunk by
240-
// global tail_path_multipliers_chunk0: [Field; 32] = [
241-
// /* 0 (00000) */ 0,
242-
// /* 1 (00001) */ 1,
243-
// /* 2 (00010) */ 0,
244-
// /* 3 (00011) */ two_pow_16,
245-
// /* 4 (00100) */ 0,
246-
// /* 5 (00101) */ two_pow_32,
247-
// /* 6 (00110) */ 0,
248-
// /* 7 (00111) */ two_pow_16 * two_pow_32,
249-
// /* 8 (01000) */ 0,
250-
// /* 9 (01001) */ two_pow_64,
251-
// /* 10 (01010) */ 0,
252-
// /* 11 (01011) */ two_pow_64 * two_pow_16,
253-
// /* 12 (01100) */ 0,
254-
// /* 13 (01101) */ two_pow_64 * two_pow_32,
255-
// /* 14 (01110) */ 0,
256-
// /* 15 (01111) */ two_pow_64 * two_pow_32 * two_pow_16,
257-
// /* 16 (10000) */ 0,
258-
// /* 17 (10001) */ two_pow_128,
259-
// /* 18 (10010) */ 0,
260-
// /* 19 (10011) */ two_pow_128 * two_pow_16,
261-
// /* 20 (10100) */ 0,
262-
// /* 21 (10101) */ two_pow_128 * two_pow_32,
263-
// /* 22 (10110) */ 0,
264-
// /* 23 (10111) */ two_pow_128 * two_pow_32 * two_pow_16,
265-
// /* 24 (11000) */ 0,
266-
// /* 25 (11001) */ two_pow_128 * two_pow_64,
267-
// /* 26 (11010) */ 0,
268-
// /* 27 (11011) */ two_pow_128 * two_pow_64 * two_pow_16,
269-
// /* 28 (11100) */ 0,
270-
// /* 29 (11101) */ two_pow_128 * two_pow_64 * two_pow_32,
271-
// /* 30 (11110) */ 0,
272-
// /* 31 (11111) */ two_pow_128 * two_pow_64 * two_pow_32 * two_pow_16
273-
// ];
274167

275168
fn sum_var_bytes_into_field<let N: u32>(body_text: [u8; N], body_index: Field, num_bytes: Field) -> Field {
276169
let path = get_path(num_bytes); // 5 gates
@@ -307,7 +200,6 @@ fn sum_var_bytes_into_field<let N: u32>(body_text: [u8; N], body_index: Field, n
307200
+ body_text[idx + 12] as Field * 0x1000000 + body_text[idx + 13] as Field * 0x10000
308201
+ body_text[idx + 14] as Field * 0x100 + body_text[idx + 15] as Field;
309202

310-
//chunks[4] = chunks[3] * chunks[3];
311203
chunks[0] *= path_f[0];
312204
chunks[1] *= path_f[1];
313205
chunks[2] *= path_f[2];
@@ -316,15 +208,7 @@ fn sum_var_bytes_into_field<let N: u32>(body_text: [u8; N], body_index: Field, n
316208

317209
let mut sum: Field = 0;
318210

319-
// if 0 0 1 1
320-
321-
// if 0 1 0 1 (little endian)
322-
// we have chunk[1] and chunk[3]
323-
// therefore we need chunk[1] * 8^16
324-
// if 0 1 1 1 (little endian)
325-
// we need chunk[2] * 8^16, chunk[3] * 8^24
326211
let mut multiplicand: Field = 1;
327-
// println(f"chunks = {chunks}");
328212
sum += chunks[4];
329213
multiplicand *= (0x100000000000000000000000000000000 * path_f[4]) + (1 - path_f[4]);
330214
sum += chunks[3] * multiplicand;
@@ -334,15 +218,8 @@ fn sum_var_bytes_into_field<let N: u32>(body_text: [u8; N], body_index: Field, n
334218
sum += chunks[1] * multiplicand;
335219
multiplicand *= (0x10000 * path_f[1]) + (1 - path_f[1]);
336220
sum += chunks[0] * multiplicand;
337-
338-
// sum *= BYTE_SHIFT[num_bytes];
339-
// 0x74657374410000000000000000000000000000000000000000000000000000
340-
// 0x74657374410000000000000000000000000000000000000000000000000000
341-
// length = l, byte_shift = (31 - l)
342221
sum
343222
}
344-
// 0x74657374410000000000000000000000000000000000000000000000000000
345-
// 0x7465737441
346223

347224
fn get_keyhash_chunky<let N: u32>(body_text: [u8; N], body_index: u16, key_length: u16) -> Field {
348225
assert(key_length < MaxKeyBytes, "key too large");
@@ -379,15 +256,8 @@ impl<let KeyFields: u16> Hasher<KeyFields> {
379256

380257
fn get_keyhash<let NumPackedFields: u16>(_: Self, packed_fields: [Field; NumPackedFields], body_index: Field, key_length: Field) -> Field {
381258
let key_fields: [Field; KeyFields] = slice_fields(packed_fields, body_index, key_length);
382-
383-
let hashed_full = dep::std::hash::poseidon2::Poseidon2::hash(key_fields, KeyFields as u32);
384-
// let hashed_full: Field = key_fields[0] + key_fields[1] + key_fields[2];
385-
386-
let r = slice_200_bits_from_field(hashed_full);
387-
r
388-
// let r = key_fields[0] + key_fields[1] + key_fields[2];
389-
// std::as_witness(r);
390-
// key_fields[2]
259+
let hashed = dep::std::hash::poseidon2::Poseidon2::hash(key_fields, KeyFields as u32);
260+
slice_200_bits_from_field(hashed)
391261
}
392262
}
393263

0 commit comments

Comments
 (0)