Skip to content

Commit f7d708c

Browse files
committed
signoff!: list::Range
BREAKING CHANGE: Remove the implementation of `DeprecatedSnippet` for `u128::range::Range`, implement `BasicSnippet` directly.
1 parent f42a244 commit f7d708c

File tree

3 files changed

+131
-175
lines changed

3 files changed

+131
-175
lines changed

tasm-lib/benchmarks/tasmlib_list_range.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
{
33
"name": "tasmlib_list_range",
44
"benchmark_result": {
5-
"clock_cycle_count": 914,
6-
"hash_table_height": 78,
5+
"clock_cycle_count": 549,
6+
"hash_table_height": 66,
77
"u32_table_height": 39,
8-
"op_stack_table_height": 763,
8+
"op_stack_table_height": 311,
99
"ram_table_height": 49
1010
},
1111
"case": "CommonCase"
1212
},
1313
{
1414
"name": "tasmlib_list_range",
1515
"benchmark_result": {
16-
"clock_cycle_count": 4809,
17-
"hash_table_height": 78,
16+
"clock_cycle_count": 2804,
17+
"hash_table_height": 66,
1818
"u32_table_height": 41,
19-
"op_stack_table_height": 4043,
19+
"op_stack_table_height": 1541,
2020
"ram_table_height": 254
2121
},
2222
"case": "WorstCase"

tasm-lib/src/assertion_error_ids.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,4 @@ often.
6363
| 520..530 | [`u128::Sub`](arithmetic/u128/sub.rs) |
6464
| 530..540 | [`u128::ShiftLeft`](arithmetic/u128/shift_left.rs) |
6565
| 540..550 | [`u128::ShiftRight`](arithmetic/u128/shift_right.rs) |
66+
| 550..560 | [`list::Range`](list/range.rs) |

tasm-lib/src/list/range.rs

Lines changed: 124 additions & 169 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,67 @@
11
use std::collections::HashMap;
22

3-
use itertools::Itertools;
43
use triton_vm::prelude::*;
54

6-
use crate::empty_stack;
75
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)]
1830
pub struct Range;
1931

2032
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;
2734
}
2835

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()
5041
}
5142

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())]
5446
}
5547

56-
fn stack_diff(&self) -> isize
57-
where
58-
Self: Sized,
59-
{
60-
-1
48+
fn entrypoint(&self) -> String {
49+
"tasmlib_list_range".into()
6150
}
6251

63-
fn function_code(&self, library: &mut crate::library::Library) -> String {
52+
fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
6453
let new_list = library.import(Box::new(New));
65-
let set_length = library.import(Box::new(SetLength));
6654

67-
let entrypoint = self.entrypoint_name();
55+
let entrypoint = self.entrypoint();
6856
let inner_loop = format!("{entrypoint}_loop");
6957

7058
triton_asm!(
7159
// BEFORE: _ minimum supremum
7260
// AFTER: _ *list
7361
{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
7763
lt // _ minimum supremum (minimum <= supremum)
78-
assert
64+
assert error_id {Self::INVALID_ERROR_ID}
7965

8066
// calculate length
8167
dup 0 dup 2 // _ minimum supremum supremum minimum
@@ -84,152 +70,121 @@ impl DeprecatedSnippet for Range {
8470

8571
// create list object
8672
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
9377
return
9478

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]
9882
{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]
10885

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]
11588

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]
11890
recurse
11991
)
120-
.iter()
121-
.join("\n")
12292
}
12393

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
13398
}
99+
}
134100

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+
}
145118
}
146119

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);
153129

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);
160133

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);
190135
}
191136

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+
}
204155

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+
}
208161
}
209162

210163
#[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],
220177
);
221-
let err = terminal_state.unwrap_err();
222-
assert!(matches!(err, InstructionError::AssertionFailed(_)));
223178
}
224179
}
225180

226181
#[cfg(test)]
227182
mod benches {
228183
use super::*;
229-
use crate::snippet_bencher::bench_and_write;
184+
use crate::test_prelude::*;
230185

231186
#[test]
232187
fn benchmark() {
233-
bench_and_write(Range);
188+
ShadowedFunction::new(Range).bench();
234189
}
235190
}

0 commit comments

Comments
 (0)