1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
use tasm_lib::data_type::DataType;
use tasm_lib::prelude::*;
use tasm_lib::triton_vm::prelude::*;
/// Generates a new Claim object given the lengths of the input and output.
/// Returns pointers to:
/// - the claim
/// - the output
/// - the input
/// - the program digest.
#[derive(Debug, Copy, Clone)]
pub struct NewClaim;
impl BasicSnippet for NewClaim {
fn parameters(&self) -> Vec<(DataType, String)> {
vec![
(DataType::U32, "input_length".to_string()),
(DataType::U32, "output_length".to_string()),
]
}
fn return_values(&self) -> Vec<(DataType, String)> {
vec![
(DataType::VoidPointer, "*claim".to_string()),
(DataType::VoidPointer, "*output".to_string()),
(DataType::VoidPointer, "*input".to_string()),
(DataType::VoidPointer, "*program_digest".to_string()),
]
}
fn entrypoint(&self) -> String {
"neptune_transaction_new_claim".to_string()
}
fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
let entrypoint = self.entrypoint();
let dyn_malloc = library.import(Box::new(DynMalloc));
let size_empty_claim = Claim::new(Digest::default()).encode().len();
triton_asm! {
// BEFORE: _ input_length output_length
// AFTER: _ *claim *output *input *program_digest
{entrypoint}:
/* Ensure claim lives within one page */
dup 1
pop_count
dup 1
pop_count
pop 2
// _ input_length output_length
dup 1
dup 1
add
addi {size_empty_claim}
pop_count
pop 1
call {dyn_malloc}
hint claim = stack[0]
// _ input_length output_length *claim
place 2
// _ *claim input_length output_length
dup 0 dup 0 addi 1
// _ *claim input_length output_length output_length output_size
dup 4
write_mem 2
hint output: Pointer = stack[0]
// _ *claim input_length output_length *output
dup 0
place 3
// _ *claim *output input_length output_length *output
add
// _ *claim *output input_length *input_si
dup 1 dup 2 addi 1
// _ *claim *output input_length *input_si input_length input_size
pick 2
write_mem 2
hint input: Pointer = stack[0]
// _ *claim *output input_length *input
dup 0
place 2
add
hint version: Pointer = stack[0]
// _ *claim *output *input *version
push {triton_vm::proof::CURRENT_VERSION}
pick 1
write_mem 1
hint program_digest: Pointer = stack[0]
// _ *claim *output *input *program_digest
return
}
}
}
#[cfg(test)]
#[cfg_attr(coverage_nightly, coverage(off))]
mod tests {
use std::collections::HashMap;
use rand::rngs::StdRng;
use rand::Rng;
use rand::SeedableRng;
use tasm_lib::prelude::BasicSnippet;
use tasm_lib::prelude::Digest;
use tasm_lib::rust_shadowing_helper_functions;
use tasm_lib::snippet_bencher::BenchmarkCase;
use tasm_lib::traits::function::Function;
use tasm_lib::traits::function::FunctionInitialState;
use tasm_lib::traits::function::ShadowedFunction;
use tasm_lib::traits::rust_shadow::RustShadow;
use tasm_lib::traits::rust_shadow::RustShadowError;
use super::*;
impl Function for NewClaim {
fn rust_shadow(
&self,
stack: &mut Vec<BFieldElement>,
memory: &mut HashMap<BFieldElement, BFieldElement>,
) -> Result<(), RustShadowError> {
let output_len = stack.pop().unwrap().value() as usize;
let input_len = stack.pop().unwrap().value() as usize;
let claim_pointer =
rust_shadowing_helper_functions::dyn_malloc::dynamic_allocator(memory);
// We can't just create a new claim and encode it to memory because that *sets*
// memory cells. The fact that the cells are being set to zero doesn't matter
// for the difference check in tasm-lib. Instead, encode it manually:
//
// | memory location | name | size |
// |----------------:|:----------------|-----------:|
// | 0 | output's size | 1 |
// | 1 | output's length | 1 |
// | 2 | output | output_len |
// | output_len + 2 | input's size | 1 |
// | output_len + 3 | input's length | 1 |
// | output_len + 4 | input | input_len |
// | both_lens + 4 | version | 1 |
// | both_lens + 5 | program_digest | 5 |
let output_size_pointer = claim_pointer;
let output_len_pointer = claim_pointer + bfe!(1);
let output_pointer = claim_pointer + bfe!(2);
let input_size_pointer = claim_pointer + bfe!(output_len + 2);
let input_len_pointer = claim_pointer + bfe!(output_len + 3);
let input_pointer = claim_pointer + bfe!(output_len + 4);
let version_pointer = claim_pointer + bfe!(output_len + input_len + 4);
let program_digest_pointer = claim_pointer + bfe!(output_len + input_len + 5);
memory.insert(output_size_pointer, bfe!(output_len + 1));
memory.insert(output_len_pointer, bfe!(output_len));
memory.insert(input_size_pointer, bfe!(input_len + 1));
memory.insert(input_len_pointer, bfe!(input_len));
memory.insert(version_pointer, bfe!(triton_vm::proof::CURRENT_VERSION));
stack.push(claim_pointer);
stack.push(output_pointer);
stack.push(input_pointer);
stack.push(program_digest_pointer);
// sanity check
let the_new_claim = *Claim::decode_from_memory(memory, claim_pointer).unwrap();
let empty_claim = Claim::new(Digest::default())
.with_input(bfe_vec![0; input_len])
.with_output(bfe_vec![0; output_len]);
assert_eq!(empty_claim, the_new_claim);
Ok(())
}
fn pseudorandom_initial_state(
&self,
seed: [u8; 32],
_bench_case: Option<BenchmarkCase>,
) -> FunctionInitialState {
let mut rng: StdRng = SeedableRng::from_seed(seed);
let input_length = rng.random_range(0..10);
let output_length = rng.random_range(0..10);
FunctionInitialState {
stack: [
self.init_stack_for_isolated_run(),
[bfe!(input_length as u64), bfe!(output_length as u64)].to_vec(),
]
.concat(),
memory: HashMap::new(),
}
}
}
#[test]
fn unit_test() {
ShadowedFunction::new(NewClaim).test()
}
}