Skip to content

Commit 6dbdb06

Browse files
committed
signoff!: u64::Incr
BREAKING CHANGE: Remove the implementation of `DeprecatedSnippet` for `u64::incr::Incr`, implement `BasicSnippet` directly.
1 parent e0ef6ca commit 6dbdb06

File tree

4 files changed

+101
-141
lines changed

4 files changed

+101
-141
lines changed

tasm-lib/benchmarks/tasmlib_arithmetic_u64_incr.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
{
33
"name": "tasmlib_arithmetic_u64_incr",
44
"benchmark_result": {
5-
"clock_cycle_count": 9,
5+
"clock_cycle_count": 8,
66
"hash_table_height": 24,
77
"u32_table_height": 0,
8-
"op_stack_table_height": 6,
8+
"op_stack_table_height": 4,
99
"ram_table_height": 0
1010
},
1111
"case": "CommonCase"
1212
},
1313
{
1414
"name": "tasmlib_arithmetic_u64_incr",
1515
"benchmark_result": {
16-
"clock_cycle_count": 21,
16+
"clock_cycle_count": 19,
1717
"hash_table_height": 24,
1818
"u32_table_height": 0,
19-
"op_stack_table_height": 16,
19+
"op_stack_table_height": 12,
2020
"ram_table_height": 0
2121
},
2222
"case": "WorstCase"

tasm-lib/benchmarks/tasmlib_mmr_calculate_new_peaks_from_append.json

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,21 @@
22
{
33
"name": "tasmlib_mmr_calculate_new_peaks_from_append",
44
"benchmark_result": {
5-
"clock_cycle_count": 3637,
6-
"hash_table_height": 360,
5+
"clock_cycle_count": 3636,
6+
"hash_table_height": 354,
77
"u32_table_height": 613,
8-
"op_stack_table_height": 3232,
8+
"op_stack_table_height": 3230,
99
"ram_table_height": 878
1010
},
1111
"case": "CommonCase"
1212
},
1313
{
1414
"name": "tasmlib_mmr_calculate_new_peaks_from_append",
1515
"benchmark_result": {
16-
"clock_cycle_count": 7184,
17-
"hash_table_height": 546,
16+
"clock_cycle_count": 7182,
17+
"hash_table_height": 540,
1818
"u32_table_height": 1194,
19-
"op_stack_table_height": 6406,
19+
"op_stack_table_height": 6402,
2020
"ram_table_height": 1746
2121
},
2222
"case": "WorstCase"
Lines changed: 90 additions & 131 deletions
Original file line numberDiff line numberDiff line change
@@ -1,179 +1,138 @@
11
use std::collections::HashMap;
22

3-
use num::One;
4-
use rand::prelude::*;
53
use triton_vm::prelude::*;
6-
use twenty_first::prelude::U32s;
74

8-
use crate::empty_stack;
95
use crate::prelude::*;
10-
use crate::push_encodable;
11-
use crate::traits::deprecated_snippet::DeprecatedSnippet;
12-
use crate::InitVmState;
13-
14-
#[derive(Clone, Debug)]
6+
use crate::traits::basic_snippet::Reviewer;
7+
use crate::traits::basic_snippet::SignOffFingerprint;
8+
9+
/// Increment a `u64` by 1.
10+
///
11+
/// Crashes the VM if the input is [`u64::MAX`].
12+
///
13+
/// ### Behavior
14+
///
15+
/// ```text
16+
/// BEFORE: _ v
17+
/// AFTER: _ (v+1)
18+
/// ```
19+
///
20+
/// ### Preconditions
21+
///
22+
/// - all input arguments are properly [`BFieldCodec`] encoded
23+
///
24+
/// ### Postconditions
25+
///
26+
/// - the output is properly [`BFieldCodec`] encoded
27+
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
1528
pub struct Incr;
1629

17-
impl DeprecatedSnippet for Incr {
18-
fn entrypoint_name(&self) -> String {
19-
"tasmlib_arithmetic_u64_incr".to_string()
20-
}
21-
22-
fn input_field_names(&self) -> Vec<String> {
23-
vec!["value_hi".to_string(), "value_lo".to_string()]
24-
}
30+
impl Incr {
31+
pub const OVERFLOW_ERROR_ID: i128 = 440;
32+
}
2533

26-
fn input_types(&self) -> Vec<DataType> {
27-
vec![DataType::U64]
34+
impl BasicSnippet for Incr {
35+
fn inputs(&self) -> Vec<(DataType, String)> {
36+
vec![(DataType::U64, "value".to_string())]
2837
}
2938

30-
fn output_field_names(&self) -> Vec<String> {
31-
vec!["(value + 1)_hi".to_string(), "(value + 1)_lo".to_string()]
39+
fn outputs(&self) -> Vec<(DataType, String)> {
40+
vec![(DataType::U64, "value + 1".to_string())]
3241
}
3342

34-
fn output_types(&self) -> Vec<DataType> {
35-
vec![DataType::U64]
43+
fn entrypoint(&self) -> String {
44+
"tasmlib_arithmetic_u64_incr".to_string()
3645
}
3746

38-
fn stack_diff(&self) -> isize {
39-
0
40-
}
47+
fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
48+
let entrypoint = self.entrypoint();
49+
let carry = format!("{entrypoint}_carry");
50+
triton_asm!(
51+
// BEFORE: _ [value: u64]
52+
// AFTER: _ [value + 1: u64]
53+
{entrypoint}:
54+
addi 1
55+
dup 0
56+
push {1_u64 << 32}
57+
eq
58+
skiz
59+
call {carry}
60+
return
4161

42-
fn function_code(&self, _library: &mut Library) -> String {
43-
let entrypoint = self.entrypoint_name();
44-
const TWO_POW_32: u64 = 1 << 32;
45-
format!(
46-
"
47-
// Before: _ value_hi value_lo
48-
// After: _ (value + 1)_hi (value + 1)_lo
49-
{entrypoint}_carry:
62+
{carry}:
5063
pop 1
51-
push 1
52-
add
64+
addi 1
5365
dup 0
54-
push {TWO_POW_32}
66+
push {1_u64 << 32}
5567
eq
5668
push 0
5769
eq
58-
assert
70+
assert error_id {Self::OVERFLOW_ERROR_ID}
5971
push 0
6072
return
61-
62-
{entrypoint}:
63-
push 1
64-
add
65-
dup 0
66-
push {TWO_POW_32}
67-
eq
68-
skiz
69-
call {entrypoint}_carry
70-
return
71-
",
7273
)
7374
}
7475

75-
fn crash_conditions(&self) -> Vec<String> {
76-
vec!["value == u64::MAX".to_string()]
77-
}
78-
79-
fn gen_input_states(&self) -> Vec<InitVmState> {
80-
let mut rng = rand::thread_rng();
81-
let values = vec![
82-
U32s::new([u32::MAX, 0]),
83-
U32s::new([0, u32::MAX]),
84-
U32s::new([u32::MAX, u32::MAX - 1]),
85-
// U32s::new([u32::MAX, u32::MAX])
86-
rng.next_u32().into(),
87-
U32s::<2>::try_from(rng.next_u64()).unwrap(),
88-
];
89-
values
90-
.into_iter()
91-
.map(|value| {
92-
let mut stack = empty_stack();
93-
push_encodable(&mut stack, &value);
94-
InitVmState::with_stack(stack)
95-
})
96-
.collect()
97-
}
98-
99-
fn common_case_input_state(&self) -> InitVmState {
100-
// no carry
101-
InitVmState::with_stack(
102-
[
103-
empty_stack(),
104-
vec![BFieldElement::new(1000), BFieldElement::new(7)],
105-
]
106-
.concat(),
107-
)
108-
}
109-
110-
fn worst_case_input_state(&self) -> InitVmState {
111-
// with carry
112-
InitVmState::with_stack(
113-
[
114-
empty_stack(),
115-
vec![BFieldElement::new(1000), BFieldElement::new((1 << 32) - 1)],
116-
]
117-
.concat(),
118-
)
119-
}
120-
121-
fn rust_shadowing(
122-
&self,
123-
stack: &mut Vec<BFieldElement>,
124-
_std_in: Vec<BFieldElement>,
125-
_secret_in: Vec<BFieldElement>,
126-
_memory: &mut HashMap<BFieldElement, BFieldElement>,
127-
) {
128-
let a: u32 = stack.pop().unwrap().try_into().unwrap();
129-
let b: u32 = stack.pop().unwrap().try_into().unwrap();
130-
let ab = U32s::<2>::new([a, b]);
131-
let ab_incr = ab + U32s::one();
132-
let mut res = ab_incr.encode();
133-
for _ in 0..res.len() {
134-
stack.push(res.pop().unwrap());
135-
}
76+
fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
77+
let mut sign_offs = HashMap::new();
78+
sign_offs.insert(Reviewer("ferdinand"), 0x786629a8064b2786.into());
79+
sign_offs
13680
}
13781
}
13882

13983
#[cfg(test)]
14084
mod tests {
14185
use super::*;
142-
use crate::empty_stack;
143-
use crate::test_helpers::test_rust_equivalence_multiple_deprecated;
86+
use crate::test_prelude::*;
14487

145-
#[test]
146-
fn incr_u64_test() {
147-
test_rust_equivalence_multiple_deprecated(&Incr, true);
88+
impl Closure for Incr {
89+
type Args = u64;
90+
91+
fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
92+
let v = pop_encodable::<Self::Args>(stack);
93+
let incr = v.checked_add(1).unwrap();
94+
push_encodable(stack, &incr);
95+
}
96+
97+
fn pseudorandom_args(
98+
&self,
99+
seed: [u8; 32],
100+
bench_case: Option<BenchmarkCase>,
101+
) -> Self::Args {
102+
match bench_case {
103+
Some(BenchmarkCase::CommonCase) => (1000 << 32) + 7, // no carry
104+
Some(BenchmarkCase::WorstCase) => (1000 << 32) + u64::from(u32::MAX), // carry
105+
None => StdRng::from_seed(seed).gen(),
106+
}
107+
}
108+
109+
fn corner_case_args(&self) -> Vec<Self::Args> {
110+
vec![0, u32::MAX.into(), u64::MAX - 1]
111+
}
148112
}
149113

150114
#[test]
151-
fn incr_u64_negative_tasm_test() {
152-
let mut stack = empty_stack();
153-
let u64_max = U32s::<2>::try_from(u64::MAX).unwrap();
154-
push_encodable(&mut stack, &u64_max);
155-
assert!(Incr
156-
.link_and_run_tasm_for_test(&mut stack, vec![], NonDeterminism::default())
157-
.is_err());
115+
fn rust_shadow() {
116+
ShadowedClosure::new(Incr).test();
158117
}
159118

160119
#[test]
161-
#[should_panic]
162-
fn incr_u64_negative_rust_test() {
163-
let mut stack = empty_stack();
164-
let u64_max = U32s::<2>::try_from(u64::MAX).unwrap();
165-
push_encodable(&mut stack, &u64_max);
166-
Incr::rust_shadowing(&Incr, &mut stack, vec![], vec![], &mut HashMap::default());
120+
fn u64_max_crashes_vm() {
121+
test_assertion_failure(
122+
&ShadowedClosure::new(Incr),
123+
InitVmState::with_stack(Incr.set_up_test_stack(u64::MAX)),
124+
&[Incr::OVERFLOW_ERROR_ID],
125+
);
167126
}
168127
}
169128

170129
#[cfg(test)]
171130
mod benches {
172131
use super::*;
173-
use crate::snippet_bencher::bench_and_write;
132+
use crate::test_prelude::*;
174133

175134
#[test]
176-
fn incr_u64_benchmark() {
177-
bench_and_write(Incr);
135+
fn benchmark() {
136+
ShadowedClosure::new(Incr).bench();
178137
}
179138
}

tasm-lib/src/assertion_error_ids.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,3 +53,4 @@ often.
5353
| 410..420 | [`list::push`](list/push.rs) |
5454
| 420..430 | [`u64::DivMod`](arithmetic/u64/div_mod.rs) |
5555
| 430..440 | [`MerkleRoot`](hashing/merkle_root.rs) |
56+
| 440..450 | [`u64::Incr`](arithmetic/u64/incr.rs) |

0 commit comments

Comments
 (0)