Skip to content

Commit b7c0f8f

Browse files
added more comments + method descriptions
1 parent 0d1442c commit b7c0f8f

20 files changed

+1119
-867
lines changed

out.txt

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

src/bounds_checker.nr

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
2+
3+
/*
4+
5+
when iterating from 0 to N, validate i < M efficiently
6+
we have an array of flags that describe whether entry is valid
7+
flags start at 1 and at 0 more or less
8+
9+
we check:
10+
1. flag starts at 0 or 1
11+
2. flag transition cannot be 0 -> 1 i.e. new_flag * (1 - old_flag) == 0
12+
3. flag ends at 0 or 1
13+
14+
the above validates that only one transition point occurs
15+
we still need to test the transition point
16+
17+
transition happens when we get 1 -> 0 i.e. tx = i * (old_flag * (1 - new_flag))
18+
in this case, i == M
19+
20+
// o * (1 - n) = o - on
21+
// n * (1 - o) = n - on
22+
// i*(o - on) * (1/i) - o + n
23+
*/
24+
25+
/**
26+
* @brief helper method that provides an array of Field elements `flags`, where `flags[i] = i < boundary`
27+
* @description this method is cheaper than querying `i < boundary` for `u16` and `u32` types
28+
* cost = 3 gates + 2 gates per iteration
29+
**/
30+
pub fn get_validity_flags<let N: u16>(boundary: u16) -> [Field; N] {
31+
let flags: [Field; N] = __get_validity_flags(boundary);
32+
get_validity_flags_inner(boundary, flags)
33+
}
34+
35+
unconstrained fn __get_validity_flags<let N: u16>(boundary: u16) -> [Field; N] {
36+
let mut result: [Field; N] = [0; N];
37+
for i in 0..N as u16 {
38+
if i < boundary {
39+
result[i] = 1;
40+
}
41+
}
42+
result
43+
}
44+
45+
/**
46+
* @brief implementation of `get_validity_flags`
47+
* @description Given an array of `flags`, we apply the following checks to build an inductive proof about the validity of the flags array:
48+
* 1. the first element `flags[0]` is in the range [0,1]
49+
* 2. the last element `flags[N-1]` is in the range [0,1]
50+
* 3. for any two flags `old, new` where `old = flags[i-1], new = flags[i]` and `i>0, i <N`, we validate the following:
51+
* a. if `old` is 0, `new` *cannot* equal 1
52+
* b. if `old` is 1 and `new` is 0, set `transition_index = i`
53+
* The value of `transition_index` will equal the value `i` where `i = boundary` (or `N` if `boundary > N`)
54+
* 4. we finally validate `transition_index == boundary` to prove the location where `flags[i-1] = 1` and `flags[i] = 0`
55+
* aligns with what is expected from testing `i < boundary`
56+
* N.B. this method will revert if `boundary > N`
57+
**/
58+
fn get_validity_flags_inner<let N: u16>(boundary: u16, flags: [Field; N]) -> [Field; N] {
59+
let initial_flag = flags[0];
60+
let final_flag = flags[N - 1];
61+
62+
// check first and last flags are in the range [0, 1]
63+
assert(initial_flag * initial_flag == initial_flag);
64+
assert(final_flag * final_flag == final_flag);
65+
66+
let mut transition_index = 0;
67+
68+
for i in 1..N {
69+
let old_flag = flags[i - 1];
70+
let new_flag = flags[i];
71+
assert(new_flag == old_flag * new_flag);
72+
73+
// old = a, new = b
74+
let idx = (old_flag * (1 - new_flag)) * (i as Field);
75+
transition_index = transition_index + idx;
76+
std::as_witness(transition_index);
77+
}
78+
79+
assert(transition_index == boundary as Field);
80+
flags
81+
}
82+
83+
#[test]
84+
fn test_get_validity_flags() {
85+
for i in 0..32 {
86+
let flags: [Field; 32] = get_validity_flags(i);
87+
for j in 0..32 {
88+
assert(flags[j] == (j < i) as Field);
89+
}
90+
}
91+
}
92+
93+
#[test(should_fail)]
94+
fn test_get_validity_flags_fail() {
95+
let _ = get_validity_flags(33);
96+
}
97+
98+
#[test(should_fail)]
99+
fn test_get_validity_flags_bad_index_fail_a() {
100+
let bad_flags: [Field; 10] = [1, 1, 1, 0, 0, 0, 1, 0, 0, 0];
101+
let _ = get_validity_flags_inner(3, bad_flags);
102+
}
103+
#[test(should_fail)]
104+
fn test_get_validity_flags_bad_index_fail_b() {
105+
let bad_flags: [Field; 10] = [1, 1, 1, 1, 0, 0, 0, 0, 0, 0];
106+
let _ = get_validity_flags_inner(3, bad_flags);
107+
}
108+
109+
#[test(should_fail)]
110+
fn test_get_validity_flags_bad_index_fail_c() {
111+
let bad_flags: [Field; 10] = [1, 1, 0, 0, 0, 0, 0, 0, 0, 0];
112+
let _ = get_validity_flags_inner(3, bad_flags);
113+
}
114+
115+
#[test]
116+
fn test_get_validity_flags_good_index_d() {
117+
let bad_flags: [Field; 10] = [1, 1, 1, 0, 0, 0, 0, 0, 0, 0];
118+
let _ = get_validity_flags_inner(3, bad_flags);
119+
}
120+
121+
#[test(should_fail)]
122+
fn test_get_validity_flags_bad_index_fail_e() {
123+
let bad_flags: [Field; 10] = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1];
124+
let _ = get_validity_flags_inner(11, bad_flags);
125+
}
126+
127+
// this test uses bad flags but manipulates transition_index to be satisfiable
128+
// nevertheless test will fail because our transition test (old * new = new) will fail
129+
#[test(should_fail)]
130+
fn test_get_validity_flags_bad_index_fail_f() {
131+
let mut bad_flags: [Field; 10] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
132+
133+
let fake_index_a = 2;
134+
let fake_value_a = 100;
135+
136+
let fake_index_b = 4;
137+
// 4 * Y = -2 * X
138+
let fake_value_b = (-fake_value_a * fake_index_a) / fake_index_b;
139+
140+
bad_flags[fake_index_a] = fake_value_a;
141+
bad_flags[fake_index_b] = fake_value_b;
142+
let _ = get_validity_flags_inner(0, bad_flags);
143+
}

src/get_array.nr

Lines changed: 59 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,32 @@
1-
use crate::getters;
2-
use dep::noir_sort;
31
use crate::json_entry::JSONEntry;
4-
use crate::redux::JSON;
5-
use crate::keymap;
6-
use crate::lt::{lt_field_8_bit, lt_field_16_bit, assert_lt_240_bit, assert_gt_240_bit};
7-
use crate::redux_tables::{
8-
OBJECT_LAYER, ARRAY_LAYER, NUMERIC_TOKEN, LITERAL_TOKEN, STRING_TOKEN, BEGIN_OBJECT_TOKEN,
9-
BEGIN_ARRAY_TOKEN, ASCII_TO_NUMBER, ESCAPE_SEQUENCE_END_CHARS, ESCAPE_SEQUENCE_START_CHARS,
10-
ESCAPE_SEQUENCE_REPLACEMENT
11-
};
12-
use crate::keyhash::Hasher;
2+
use crate::json::JSON;
3+
use crate::lt::lt_field_16_bit;
4+
use crate::json_tables::{OBJECT_LAYER, ARRAY_LAYER, BEGIN_ARRAY_TOKEN};
135
use crate::keyhash::get_keyhash;
14-
use crate::slice_field::slice_fields;
156
use crate::getters::JSONValue;
167

8+
/**
9+
* @brief getter methods for extracting array types out of a JSON struct
10+
**/
1711
impl<let NumBytes: u32, let NumPackedFields: u16, let MaxNumTokens: u16, let MaxNumValues: u16> JSON<NumBytes,NumPackedFields, MaxNumTokens, MaxNumValues> {
1812

13+
/**
14+
* @brief if the root JSON is an array, return its length
15+
**/
1916
fn get_length(self) -> u32 {
2017
assert(self.layer_context == ARRAY_LAYER, "can only get length of an array type");
21-
let parent_entry = JSONEntry::from_field(self.packed_json_entries[self.layer_index_in_transcript]);
18+
let parent_entry: JSONEntry = self.packed_json_entries[self.layer_index_in_transcript].into();
2219
parent_entry.num_children as u32
2320
}
2421

22+
/**
23+
* @brief if the root JSON is an object, extract an array given by `key`
24+
* @description returns an Option<JSON> where, if the array exists, the JSON object will have the requested array as its root value
25+
**/
2526
fn get_array<let KeyBytes: u16>(self, key: [u8; KeyBytes]) -> Option<Self> {
2627
assert(self.layer_context != ARRAY_LAYER, "cannot extract array elements via a key");
2728
let (exists, key_index) = self.key_exists_impl(key, KeyBytes);
28-
let entry: JSONEntry = JSONEntry::from_field(self.packed_json_entries[key_index]);
29-
29+
let entry: JSONEntry = self.packed_json_entries[key_index].into();
3030
assert(
3131
(entry.entry_type - BEGIN_ARRAY_TOKEN) * exists as Field == 0, "key does not describe an object"
3232
);
@@ -40,12 +40,14 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let MaxNumTokens: u16, let Max
4040
Option { _is_some: exists, _value: r }
4141
}
4242

43+
/**
44+
* @brief if the root JSON is an object, extract an array given by `key`
45+
* @description will revert if the array does not exist
46+
**/
4347
fn get_array_unchecked<let KeyBytes: u16>(self, key: [u8; KeyBytes]) -> Self {
4448
assert(self.layer_context != ARRAY_LAYER, "cannot extract array elements via a key");
4549

46-
let key_index = self.key_exists_impl_unchecked(key, KeyBytes);
47-
let entry: JSONEntry = JSONEntry::from_field(self.packed_json_entries[key_index]);
48-
50+
let (entry, key_index) = self.get_json_entry_unchecked_with_key_index_var(key, KeyBytes);
4951
assert(entry.entry_type == BEGIN_ARRAY_TOKEN, "key does not describe an object");
5052

5153
let mut r = self;
@@ -57,51 +59,57 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let MaxNumTokens: u16, let Max
5759
r
5860
}
5961

60-
fn get_array_unchecked_var<let KeyBytes: u16>(self, key: [u8; KeyBytes], key_length: u16) -> Self {
62+
/**
63+
* @brief same as `get_array` for where the key length may be less than KeyBytes
64+
**/
65+
fn get_array_var<let KeyBytes: u16>(self, key: [u8; KeyBytes], key_length: u16) -> Option<Self> {
6166
assert(self.layer_context != ARRAY_LAYER, "cannot extract array elements via a key");
62-
63-
let key_index = self.key_exists_impl_unchecked(key, key_length);
64-
let entry: JSONEntry = JSONEntry::from_field(self.packed_json_entries[key_index]);
65-
66-
assert(entry.entry_type == BEGIN_ARRAY_TOKEN, "key does not describe an object");
67+
let (exists, key_index) = self.key_exists_impl(key, key_length);
68+
let entry: JSONEntry = self.packed_json_entries[key_index].into();
69+
// TODO: ADD A layer_context VARIABLE INTO JSON WHICH DESCRIBES WHETHER WE ARE AN OBJECT, ARRAY OR SINGLE VALUE
70+
assert(
71+
(entry.entry_type - BEGIN_ARRAY_TOKEN) * exists as Field == 0, "key does not describe an object"
72+
);
6773

6874
let mut r = self;
6975
r.layer_id = entry.parent_index;
7076
r.root_id = entry.id;
7177
r.layer_context = ARRAY_LAYER;
7278
r.layer_index_in_transcript = key_index;
7379

74-
r
80+
Option { _is_some: exists, _value: r }
7581
}
76-
fn get_array_var<let KeyBytes: u16>(self, key: [u8; KeyBytes], key_length: u16) -> Option<Self> {
82+
83+
/**
84+
* @brief same as `get_array_unchecked` for where the key length may be less than KeyBytes
85+
**/
86+
fn get_array_unchecked_var<let KeyBytes: u16>(self, key: [u8; KeyBytes], key_length: u16) -> Self {
7787
assert(self.layer_context != ARRAY_LAYER, "cannot extract array elements via a key");
78-
let (exists, key_index) = self.key_exists_impl(key, key_length);
79-
let entry: JSONEntry = JSONEntry::from_field(self.packed_json_entries[key_index]);
8088

81-
// TODO: ADD A layer_context VARIABLE INTO JSON WHICH DESCRIBES WHETHER WE ARE AN OBJECT, ARRAY OR SINGLE VALUE
82-
assert(
83-
(entry.entry_type - BEGIN_ARRAY_TOKEN) * exists as Field == 0, "key does not describe an object"
84-
);
89+
let (entry, key_index) = self.get_json_entry_unchecked_with_key_index_var(key, key_length);
90+
assert(entry.entry_type == BEGIN_ARRAY_TOKEN, "key does not describe an object");
8591

8692
let mut r = self;
8793
r.layer_id = entry.parent_index;
8894
r.root_id = entry.id;
8995
r.layer_context = ARRAY_LAYER;
9096
r.layer_index_in_transcript = key_index;
9197

92-
Option { _is_some: exists, _value: r }
98+
r
9399
}
94100

101+
/**
102+
* @brief if the root JSON is an array, extract an array given by the position of the target in the source array
103+
* @description returns an Option<JSON> where, if the array exists, the JSON object will have the requested array as its root value
104+
**/
95105
fn get_array_from_array(self, array_index: Field) -> Option<Self> {
96106
assert(self.layer_context == ARRAY_LAYER, "can only acceess array elements from array");
97107

98-
let parent_entry = JSONEntry::from_field(self.packed_json_entries[self.layer_index_in_transcript]);
99-
108+
let parent_entry: JSONEntry = self.packed_json_entries[self.layer_index_in_transcript].into();
100109
let valid = lt_field_16_bit(array_index, parent_entry.num_children);
101110
let entry_index = (parent_entry.child_pointer + array_index) * valid as Field;
102111

103-
let entry = JSONEntry::from_field(self.packed_json_entries[entry_index]);
104-
112+
let entry: JSONEntry = self.packed_json_entries[entry_index].into();
105113
assert(
106114
(entry.entry_type - BEGIN_ARRAY_TOKEN) * valid as Field == 0, "get_object_from_array: entry exists but is not an object!"
107115
);
@@ -115,17 +123,19 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let MaxNumTokens: u16, let Max
115123
Option { _is_some: valid, _value: r }
116124
}
117125

126+
/**
127+
* @brief if the root JSON is an array, extract an array given by the position of the target in the source array
128+
* @description will revert if the array does not exist
129+
**/
118130
fn get_array_from_array_unchecked(self, array_index: Field) -> Self {
119131
assert(self.layer_context == ARRAY_LAYER, "can only acceess array elements from array");
120132

121-
let parent_entry = JSONEntry::from_field(self.packed_json_entries[self.layer_index_in_transcript]);
122-
133+
let parent_entry: JSONEntry = self.packed_json_entries[self.layer_index_in_transcript].into();
123134
let valid = lt_field_16_bit(array_index, parent_entry.num_children);
124135
assert(valid, "array overflow");
125136
let entry_index = (parent_entry.child_pointer + array_index);
126137

127-
let entry = JSONEntry::from_field(self.packed_json_entries[entry_index]);
128-
138+
let entry: JSONEntry = self.packed_json_entries[entry_index].into();
129139
assert(
130140
entry.entry_type == BEGIN_ARRAY_TOKEN, "get_array_from_array_unchecked: entry exists but is not an array!"
131141
);
@@ -138,22 +148,20 @@ impl<let NumBytes: u32, let NumPackedFields: u16, let MaxNumTokens: u16, let Max
138148
r
139149
}
140150

141-
fn map<U, let MaxElements: u32, let MaxElementBytes: u32>(
142-
self,
143-
f: fn(JSONValue<MaxElementBytes>) -> U
144-
) -> [U; MaxElements] where U: std::default::Default {
151+
/**
152+
* @brief if the root is an array, map over the array values, applying `fn f` to each value
153+
**/
154+
fn map<U, let MaxElements: u32, let MaxElementBytes: u32>(self, f: fn(JSONValue<MaxElementBytes>) -> U) -> [U; MaxElements] where U: std::default::Default {
145155
assert(self.layer_context == ARRAY_LAYER, "can only call map on an array");
146156

147-
let entry = JSONEntry::from_field(self.packed_json_entries[self.layer_index_in_transcript]);
148-
157+
let entry: JSONEntry = self.packed_json_entries[self.layer_index_in_transcript].into();
149158
let num_children = entry.num_children;
150159
let mut r: [U; MaxElements] = [U::default(); MaxElements];
151160

152161
for i in 0..MaxElements {
153162
let valid = lt_field_16_bit(i as Field, num_children);
154163
let entry_index = (entry.child_pointer + i as Field) * valid as Field;
155-
let child_entry = JSONEntry::from_field(self.packed_json_entries[entry_index]);
156-
164+
let child_entry: JSONEntry = self.packed_json_entries[entry_index].into();
157165
let mut parsed_string: [u8; MaxElementBytes] = [0; MaxElementBytes];
158166
for j in 0..MaxElementBytes {
159167
let byte_valid = lt_field_16_bit(j as Field, child_entry.json_length);
@@ -209,9 +217,9 @@ fn test_array() {
209217

210218
let E = first.get_object_from_array_unchecked(4);
211219

212-
let entry_maybe = JSONEntry::from_field(E.packed_json_entries[E.layer_index_in_transcript]);
220+
let entry_maybe: JSONEntry = E.packed_json_entries[E.layer_index_in_transcript].into();
213221
println(f"entry = {entry_maybe}");
214-
let child = JSONEntry::from_field(E.packed_json_entries[entry_maybe.child_pointer]);
222+
let child: JSONEntry = E.packed_json_entries[entry_maybe.child_pointer].into();
215223
println(f"target? = {child}");
216224
println(f"{E}");
217225
let E_A = E.get_array_unchecked("bar".as_bytes());

0 commit comments

Comments
 (0)