1
1
use std:: collections:: HashMap ;
2
2
3
- use itertools:: Itertools ;
4
3
use triton_vm:: prelude:: * ;
5
4
6
- use crate :: empty_stack;
7
5
use crate :: list:: new:: New ;
8
- use crate :: list:: set_length:: SetLength ;
9
- use crate :: list:: LIST_METADATA_SIZE ;
10
- use crate :: prelude:: DataType ;
11
- use crate :: rust_shadowing_helper_functions;
12
- use crate :: traits:: deprecated_snippet:: DeprecatedSnippet ;
13
- use crate :: InitVmState ;
14
-
15
- /// Generates a list containing all integers between the minimum (inclusive lower bound) and the
16
- /// supremum (exclusive upper bound).
17
- #[ derive( Debug , Default , Copy , Clone , Eq , PartialEq ) ]
6
+ use crate :: prelude:: * ;
7
+ use crate :: traits:: basic_snippet:: Reviewer ;
8
+ use crate :: traits:: basic_snippet:: SignOffFingerprint ;
9
+
10
+ /// Generates a list containing all integers between the minimum (inclusive
11
+ /// lower bound) and the supremum (exclusive upper bound).
12
+ ///
13
+ /// ### Behavior
14
+ ///
15
+ /// ```text
16
+ /// BEFORE: _ [minimum: u32] [supremum: u32]
17
+ /// AFTER: _ *list
18
+ /// ```
19
+ ///
20
+ /// ### Preconditions
21
+ ///
22
+ /// - all input arguments are properly [`BFieldCodec`] encoded
23
+ /// - the `minimum` is less than or equal to the `supremum`
24
+ ///
25
+ /// ### Postconditions
26
+ ///
27
+ /// - `*list` is a pointer to a [`BFieldCodec`] encoded list of properly encoded
28
+ /// `u32`s
29
+ #[ derive( Debug , Default , Copy , Clone , Eq , PartialEq , Hash ) ]
18
30
pub struct Range ;
19
31
20
32
impl Range {
21
- fn init_state ( minimum : u32 , supremum : u32 ) -> InitVmState {
22
- let mut stack = empty_stack ( ) ;
23
- stack. push ( BFieldElement :: new ( minimum as u64 ) ) ;
24
- stack. push ( BFieldElement :: new ( supremum as u64 ) ) ;
25
- InitVmState :: with_stack ( stack)
26
- }
33
+ pub const INVALID_ERROR_ID : i128 = 550 ;
27
34
}
28
35
29
- impl DeprecatedSnippet for Range {
30
- fn entrypoint_name ( & self ) -> String {
31
- "tasmlib_list_range" . into ( )
32
- }
33
-
34
- fn input_field_names ( & self ) -> Vec < String >
35
- where
36
- Self : Sized ,
37
- {
38
- vec ! [ "minimum" . to_string( ) , "supremum" . to_string( ) ]
39
- }
40
-
41
- fn input_types ( & self ) -> Vec < DataType > {
42
- vec ! [ DataType :: U32 , DataType :: U32 ]
43
- }
44
-
45
- fn output_field_names ( & self ) -> Vec < String >
46
- where
47
- Self : Sized ,
48
- {
49
- vec ! [ "*list" . to_string( ) ]
36
+ impl BasicSnippet for Range {
37
+ fn inputs ( & self ) -> Vec < ( DataType , String ) > {
38
+ [ "minimum" , "supremum" ]
39
+ . map ( |s| ( DataType :: U32 , s. to_string ( ) ) )
40
+ . to_vec ( )
50
41
}
51
42
52
- fn output_types ( & self ) -> Vec < DataType > {
53
- vec ! [ DataType :: List ( Box :: new( DataType :: U32 ) ) ]
43
+ fn outputs ( & self ) -> Vec < ( DataType , String ) > {
44
+ let list_type = DataType :: List ( Box :: new ( DataType :: U32 ) ) ;
45
+ vec ! [ ( list_type, "*list" . to_string( ) ) ]
54
46
}
55
47
56
- fn stack_diff ( & self ) -> isize
57
- where
58
- Self : Sized ,
59
- {
60
- -1
48
+ fn entrypoint ( & self ) -> String {
49
+ "tasmlib_list_range" . into ( )
61
50
}
62
51
63
- fn function_code ( & self , library : & mut crate :: library :: Library ) -> String {
52
+ fn code ( & self , library : & mut Library ) -> Vec < LabelledInstruction > {
64
53
let new_list = library. import ( Box :: new ( New ) ) ;
65
- let set_length = library. import ( Box :: new ( SetLength ) ) ;
66
54
67
- let entrypoint = self . entrypoint_name ( ) ;
55
+ let entrypoint = self . entrypoint ( ) ;
68
56
let inner_loop = format ! ( "{entrypoint}_loop" ) ;
69
57
70
58
triton_asm ! (
71
59
// BEFORE: _ minimum supremum
72
60
// AFTER: _ *list
73
61
{ entrypoint} :
74
- hint supremum = stack[ 0 ]
75
- hint minimum = stack[ 1 ]
76
- dup 0 push 1 add dup 2 // _ minimum supremum (supremum + 1) minimum
62
+ dup 0 addi 1 dup 2 // _ minimum supremum (supremum + 1) minimum
77
63
lt // _ minimum supremum (minimum <= supremum)
78
- assert
64
+ assert error_id { Self :: INVALID_ERROR_ID }
79
65
80
66
// calculate length
81
67
dup 0 dup 2 // _ minimum supremum supremum minimum
@@ -84,152 +70,121 @@ impl DeprecatedSnippet for Range {
84
70
85
71
// create list object
86
72
call { new_list} // _ minimum supremum length *list
87
- dup 1 // _ minimum supremum length *list length
88
- call { set_length} // _ minimum supremum length *list
89
- call { inner_loop} // _ minimum supremum 0 *list
90
-
91
- // clean up stack
92
- swap 3 pop 3 // _ *list
73
+ dup 0 place 4 // _ *list minimum supremum length *list
74
+ write_mem 1 // _ *list minimum supremum *list[0]
75
+ call { inner_loop} // _ *list supremum supremum *list[n]
76
+ pop 3 // _ *list
93
77
return
94
78
95
- // BEFORE: _ minimum supremum length *list
96
- // INVARIANT: _ minimum supremum (length - i) *list
97
- // AFTER: _ minimum supremum 0 *list
79
+ // BEFORE: _ minimum supremum *list[0]
80
+ // INVARIANT: _ (minimum+ i) supremum *list[i]
81
+ // AFTER: _ supremum supremum *list[n]
98
82
{ inner_loop} :
99
- // compute termination condition
100
- dup 1 push 0 eq // _ minimum supremum index *list (index == 0)
101
- skiz return
102
-
103
- // decrement index
104
- swap 1 push -1 add // _ minimum supremum *list (index - 1)
105
-
106
- // value to write
107
- dup 3 dup 1 add // _ minimum supremum *list (index - 1) (minimum + index - 1)
83
+ dup 2 dup 2 eq // _ (minimum+i) supremum *list[i] (minimum+i == supremum)
84
+ skiz return // _ (minimum+i) supremum *list[i]
108
85
109
- // address to write to
110
- dup 2 // _ minimum supremum *list (index - 1) (minimum + index - 1) *list
111
- push { LIST_METADATA_SIZE }
112
- hint list_metadata_size = stack[ 0 ]
113
- add // _ minimum supremum *list (index - 1) (minimum + index - 1) *list_start
114
- dup 2 add // _ minimum supremum *list (index - 1) (minimum + index - 1) *element
86
+ dup 2 place 1 // _ (minimum+i) supremum (minimum+i) *list[i]
87
+ write_mem 1 // _ (minimum+i) supremum *list[i+1]
115
88
116
- write_mem 1 // _ minimum supremum *list (index - 1) (*element + 1)
117
- pop 1 swap 1 // _ minimum supremum (index - 1) *list
89
+ pick 2 addi 1 place 2 // _ (minimum+i+1) supremum *list[i+1]
118
90
recurse
119
91
)
120
- . iter ( )
121
- . join ( "\n " )
122
92
}
123
93
124
- fn crash_conditions ( & self ) -> Vec < String >
125
- where
126
- Self : Sized ,
127
- {
128
- vec ! [
129
- "minimum not u32" . to_string( ) ,
130
- "supremum not u32" . to_string( ) ,
131
- "minimum larger than supremum" . to_string( ) ,
132
- ]
94
+ fn sign_offs ( & self ) -> HashMap < Reviewer , SignOffFingerprint > {
95
+ let mut sign_offs = HashMap :: new ( ) ;
96
+ sign_offs. insert ( Reviewer ( "ferdinand" ) , 0xf536cdedd1ce0903 . into ( ) ) ;
97
+ sign_offs
133
98
}
99
+ }
134
100
135
- fn gen_input_states ( & self ) -> Vec < InitVmState >
136
- where
137
- Self : Sized ,
138
- {
139
- vec ! [
140
- Self :: init_state( 0 , 1 ) ,
141
- Self :: init_state( 0 , 10 ) ,
142
- Self :: init_state( 5 , 15 ) ,
143
- Self :: init_state( 12 , 12 ) , // should generate empty list
144
- ]
101
+ #[ cfg( test) ]
102
+ mod tests {
103
+ use super :: * ;
104
+ use crate :: rust_shadowing_helper_functions:: dyn_malloc:: dynamic_allocator;
105
+ use crate :: test_prelude:: * ;
106
+
107
+ impl Range {
108
+ fn set_up_initial_state ( & self , minimum : u32 , supremum : u32 ) -> FunctionInitialState {
109
+ let mut stack = self . init_stack_for_isolated_run ( ) ;
110
+ stack. push ( bfe ! ( minimum) ) ;
111
+ stack. push ( bfe ! ( supremum) ) ;
112
+
113
+ FunctionInitialState {
114
+ stack,
115
+ ..Default :: default ( )
116
+ }
117
+ }
145
118
}
146
119
147
- fn common_case_input_state ( & self ) -> InitVmState
148
- where
149
- Self : Sized ,
150
- {
151
- Self :: init_state ( 0 , 45 )
152
- }
120
+ impl Function for Range {
121
+ fn rust_shadow (
122
+ & self ,
123
+ stack : & mut Vec < BFieldElement > ,
124
+ memory : & mut HashMap < BFieldElement , BFieldElement > ,
125
+ ) {
126
+ let supremum = pop_encodable :: < u32 > ( stack) ;
127
+ let minimum = pop_encodable :: < u32 > ( stack) ;
128
+ assert ! ( minimum <= supremum) ;
153
129
154
- fn worst_case_input_state ( & self ) -> InitVmState
155
- where
156
- Self : Sized ,
157
- {
158
- Self :: init_state ( 0 , 250 )
159
- }
130
+ let list_pointer = dynamic_allocator ( memory) ;
131
+ let list = ( minimum..supremum) . collect_vec ( ) ;
132
+ encode_to_memory ( memory, list_pointer, & list) ;
160
133
161
- fn rust_shadowing (
162
- & self ,
163
- stack : & mut Vec < BFieldElement > ,
164
- _std_in : Vec < BFieldElement > ,
165
- _secret_in : Vec < BFieldElement > ,
166
- memory : & mut HashMap < BFieldElement , BFieldElement > ,
167
- ) where
168
- Self : Sized ,
169
- {
170
- let supremum: u32 = stack. pop ( ) . unwrap ( ) . value ( ) . try_into ( ) . unwrap ( ) ;
171
- let minimum: u32 = stack. pop ( ) . unwrap ( ) . value ( ) . try_into ( ) . unwrap ( ) ;
172
- let num_elements: usize = ( supremum - minimum) . try_into ( ) . unwrap ( ) ;
173
-
174
- let safety_offset = LIST_METADATA_SIZE ;
175
- let length = num_elements;
176
-
177
- // allocate space
178
- let list_pointer = rust_shadowing_helper_functions:: dyn_malloc:: dynamic_allocator ( memory) ;
179
-
180
- // initialize list
181
- rust_shadowing_helper_functions:: list:: list_new ( list_pointer, memory) ;
182
- rust_shadowing_helper_functions:: list:: list_set_length ( list_pointer, length, memory) ;
183
-
184
- // write elements
185
- for i in minimum..supremum {
186
- memory. insert (
187
- list_pointer + BFieldElement :: new ( safety_offset as u64 + i as u64 - minimum as u64 ) ,
188
- BFieldElement :: new ( i as u64 ) ,
189
- ) ;
134
+ stack. push ( list_pointer) ;
190
135
}
191
136
192
- // leave list address on stack
193
- stack. push ( list_pointer) ;
194
- }
195
- }
196
-
197
- #[ cfg( test) ]
198
- mod tests {
199
- use triton_vm:: error:: InstructionError ;
200
-
201
- use super :: * ;
202
- use crate :: execute_with_terminal_state;
203
- use crate :: test_helpers:: test_rust_equivalence_multiple_deprecated;
137
+ fn pseudorandom_initial_state (
138
+ & self ,
139
+ seed : [ u8 ; 32 ] ,
140
+ bench_case : Option < BenchmarkCase > ,
141
+ ) -> FunctionInitialState {
142
+ let ( minimum, supremum) = match bench_case {
143
+ Some ( BenchmarkCase :: CommonCase ) => ( 0 , 45 ) ,
144
+ Some ( BenchmarkCase :: WorstCase ) => ( 0 , 250 ) ,
145
+ None => {
146
+ let mut rng = StdRng :: from_seed ( seed) ;
147
+ let supremum = rng. gen_range ( 0 ..=400 ) ;
148
+ let minimum = rng. gen_range ( 0 ..=supremum) ;
149
+ ( minimum, supremum)
150
+ }
151
+ } ;
152
+
153
+ self . set_up_initial_state ( minimum, supremum)
154
+ }
204
155
205
- #[ test]
206
- fn new_snippet_test ( ) {
207
- test_rust_equivalence_multiple_deprecated ( & Range , true ) ;
156
+ fn corner_case_initial_states ( & self ) -> Vec < FunctionInitialState > {
157
+ [ ( 0 , 0 ) , ( 0 , 1 ) , ( 0 , 10 ) , ( 5 , 15 ) , ( 15 , 15 ) ]
158
+ . map ( |( min, sup) | self . set_up_initial_state ( min, sup) )
159
+ . to_vec ( )
160
+ }
208
161
}
209
162
210
163
#[ test]
211
- fn bad_range_test ( ) {
212
- let init_state = Range :: init_state ( 13 , 12 ) ;
213
- let snippet = Range ;
214
- let terminal_state = execute_with_terminal_state (
215
- Program :: new ( & snippet. link_for_isolated_run ( ) ) ,
216
- & init_state. public_input ,
217
- & init_state. stack ,
218
- & NonDeterminism :: default ( ) ,
219
- None ,
164
+ fn rust_shadow ( ) {
165
+ ShadowedFunction :: new ( Range ) . test ( ) ;
166
+ }
167
+
168
+ #[ proptest]
169
+ fn invalid_range_crashes_vm (
170
+ #[ strategy( 1_u32 ..) ] minimum : u32 ,
171
+ #[ strategy( ..#minimum) ] supremum : u32 ,
172
+ ) {
173
+ test_assertion_failure (
174
+ & ShadowedFunction :: new ( Range ) ,
175
+ Range . set_up_initial_state ( minimum, supremum) . into ( ) ,
176
+ & [ Range :: INVALID_ERROR_ID ] ,
220
177
) ;
221
- let err = terminal_state. unwrap_err ( ) ;
222
- assert ! ( matches!( err, InstructionError :: AssertionFailed ( _) ) ) ;
223
178
}
224
179
}
225
180
226
181
#[ cfg( test) ]
227
182
mod benches {
228
183
use super :: * ;
229
- use crate :: snippet_bencher :: bench_and_write ;
184
+ use crate :: test_prelude :: * ;
230
185
231
186
#[ test]
232
187
fn benchmark ( ) {
233
- bench_and_write ( Range ) ;
188
+ ShadowedFunction :: new ( Range ) . bench ( ) ;
234
189
}
235
190
}
0 commit comments