Skip to content

Commit 7edf8ca

Browse files
committed
tasm_object: Add a few negative tests pre-loading integrity check
1 parent 5effd15 commit 7edf8ca

File tree

1 file changed

+160
-71
lines changed

1 file changed

+160
-71
lines changed

tasm-lib/src/structure/verify_nd_si_integrity.rs

Lines changed: 160 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -83,18 +83,172 @@ mod tests {
8383

8484
use super::*;
8585

86-
#[test]
87-
fn test_pbt_simple_struct() {
86+
impl<T: TasmObject + BFieldCodec + for<'a> Arbitrary<'a> + Debug> VerifyNdSiIntegrity<T> {
87+
fn initial_state(&self, address: BFieldElement, t: T) -> AccessorInitialState {
88+
let mut memory = HashMap::default();
89+
encode_to_memory(&mut memory, address, &t);
90+
91+
AccessorInitialState {
92+
stack: [self.init_stack_for_isolated_run(), vec![address]].concat(),
93+
memory,
94+
}
95+
}
96+
97+
fn prepare_random_object(&self, randomness: &[u8]) -> T {
98+
let unstructured = Unstructured::new(randomness);
99+
T::arbitrary_take_rest(unstructured).unwrap()
100+
}
101+
}
102+
103+
impl<T: TasmObject + BFieldCodec + for<'a> Arbitrary<'a> + Debug> Accessor
104+
for VerifyNdSiIntegrity<T>
105+
{
106+
fn rust_shadow(
107+
&self,
108+
stack: &mut Vec<BFieldElement>,
109+
memory: &HashMap<BFieldElement, BFieldElement>,
110+
) {
111+
// If the type can be decoded then it must have valid size indicators
112+
let pointer = stack.pop().unwrap();
113+
let obj = T::decode_from_memory(memory, pointer).unwrap();
114+
let encoding_len = obj.encode().len();
115+
let encoding_len: u32 = encoding_len.try_into().unwrap();
116+
117+
// Verify contained in ND-region
118+
let start_address: u32 = pointer.value().try_into().unwrap();
119+
let _end_address = start_address.checked_add(encoding_len).unwrap();
120+
121+
stack.push(bfe!(obj.encode().len() as u64));
122+
}
123+
124+
fn pseudorandom_initial_state(
125+
&self,
126+
seed: [u8; 32],
127+
_bench_case: Option<BenchmarkCase>,
128+
) -> AccessorInitialState {
129+
let mut rng: StdRng = SeedableRng::from_seed(seed);
130+
131+
let t: T = {
132+
let mut randomness = [0u8; 100000];
133+
rng.fill(&mut randomness);
134+
self.prepare_random_object(&randomness)
135+
};
136+
137+
let address: u32 = rng.gen_range(0..(1 << 30));
138+
let address = bfe!(address);
139+
self.initial_state(address, t)
140+
}
141+
142+
fn corner_case_initial_states(&self) -> Vec<AccessorInitialState> {
143+
// This *should* always return `None` if `T: Option<S>`, and empty
144+
// vec if type is Vec<T>. So some notion of "empty" or default.
145+
let empty_struct: T = {
146+
let unstructured = Unstructured::new(&[]);
147+
T::arbitrary_take_rest(unstructured).unwrap()
148+
};
149+
150+
println!("empty_struct:\n{empty_struct:?}");
151+
let empty_struct_at_zero = self.initial_state(BFieldElement::ZERO, empty_struct);
152+
153+
vec![empty_struct_at_zero]
154+
}
155+
}
156+
157+
mod simple_struct {
158+
use crate::test_helpers::negative_test;
159+
160+
use super::*;
161+
88162
#[derive(Debug, Clone, TasmObject, BFieldCodec, Arbitrary)]
89163
struct TestStruct {
90164
a: Vec<u128>,
91165
b: Digest,
92166
c: Vec<Digest>,
93167
}
94-
let snippet: VerifyNdSiIntegrity<TestStruct> = VerifyNdSiIntegrity {
95-
_phantom_data: PhantomData,
96-
};
97-
ShadowedAccessor::new(snippet).test();
168+
169+
#[test]
170+
fn test_pbt_simple_struct() {
171+
let snippet: VerifyNdSiIntegrity<TestStruct> = VerifyNdSiIntegrity {
172+
_phantom_data: PhantomData,
173+
};
174+
ShadowedAccessor::new(snippet).test();
175+
}
176+
177+
#[test]
178+
fn struct_not_contained_in_nd_region() {
179+
let snippet: VerifyNdSiIntegrity<TestStruct> = VerifyNdSiIntegrity {
180+
_phantom_data: PhantomData,
181+
};
182+
183+
let t: TestStruct = snippet.prepare_random_object(&[]);
184+
let begin_address = bfe!((1u64 << 32) - 4);
185+
let init_state = snippet.initial_state(begin_address, t.clone());
186+
187+
let actual_size = t.encode().len();
188+
let end_address = begin_address + bfe!(actual_size as u64);
189+
negative_test(
190+
&ShadowedAccessor::new(snippet),
191+
init_state.into(),
192+
&[InstructionError::FailedU32Conversion(end_address)],
193+
)
194+
}
195+
196+
#[test]
197+
fn struct_does_not_start_in_nd_region() {
198+
let snippet: VerifyNdSiIntegrity<TestStruct> = VerifyNdSiIntegrity {
199+
_phantom_data: PhantomData,
200+
};
201+
202+
let begin_address = bfe!(-4);
203+
let init_state =
204+
snippet.initial_state(begin_address, snippet.prepare_random_object(&[]));
205+
negative_test(
206+
&ShadowedAccessor::new(snippet),
207+
init_state.into(),
208+
&[InstructionError::FailedU32Conversion(begin_address)],
209+
)
210+
}
211+
212+
#[test]
213+
fn lie_about_digest_vec_size() {
214+
let snippet: VerifyNdSiIntegrity<TestStruct> = VerifyNdSiIntegrity {
215+
_phantom_data: PhantomData,
216+
};
217+
218+
let begin_address = bfe!(4);
219+
let mut init_state =
220+
snippet.initial_state(begin_address, snippet.prepare_random_object(&[]));
221+
let true_value = init_state.memory[&begin_address];
222+
init_state
223+
.memory
224+
.insert(begin_address, true_value + bfe!(1));
225+
negative_test(
226+
&ShadowedAccessor::new(snippet),
227+
init_state.into(),
228+
&[InstructionError::AssertionFailed],
229+
)
230+
}
231+
232+
#[test]
233+
fn lie_about_digest_vec_len() {
234+
let snippet: VerifyNdSiIntegrity<TestStruct> = VerifyNdSiIntegrity {
235+
_phantom_data: PhantomData,
236+
};
237+
238+
let begin_address = bfe!(4);
239+
let mut init_state =
240+
snippet.initial_state(begin_address, snippet.prepare_random_object(&[42u8; 200]));
241+
let vec_digest_len_indicator = begin_address + bfe!(1);
242+
let true_value = init_state.memory[&vec_digest_len_indicator];
243+
init_state
244+
.memory
245+
.insert(vec_digest_len_indicator, true_value + bfe!(1));
246+
negative_test(
247+
&ShadowedAccessor::new(snippet),
248+
init_state.into(),
249+
&[InstructionError::AssertionFailed],
250+
)
251+
}
98252
}
99253

100254
#[test]
@@ -409,71 +563,6 @@ mod tests {
409563
};
410564
ShadowedAccessor::new(snippet).test();
411565
}
412-
413-
impl<T: TasmObject + BFieldCodec> VerifyNdSiIntegrity<T> {
414-
fn initial_state(&self, address: BFieldElement, t: T) -> AccessorInitialState {
415-
let mut memory = HashMap::default();
416-
encode_to_memory(&mut memory, address, &t);
417-
418-
AccessorInitialState {
419-
stack: [self.init_stack_for_isolated_run(), vec![address]].concat(),
420-
memory,
421-
}
422-
}
423-
}
424-
425-
impl<T: TasmObject + BFieldCodec + for<'a> Arbitrary<'a> + Debug> Accessor
426-
for VerifyNdSiIntegrity<T>
427-
{
428-
fn rust_shadow(
429-
&self,
430-
stack: &mut Vec<BFieldElement>,
431-
memory: &HashMap<BFieldElement, BFieldElement>,
432-
) {
433-
// If the type can be decoded then it must have valid size indicators
434-
let pointer = stack.pop().unwrap();
435-
let obj = T::decode_from_memory(memory, pointer).unwrap();
436-
437-
stack.push(bfe!(obj.encode().len() as u64));
438-
}
439-
440-
fn pseudorandom_initial_state(
441-
&self,
442-
seed: [u8; 32],
443-
_bench_case: Option<BenchmarkCase>,
444-
) -> AccessorInitialState {
445-
fn prepare_random_object<T: for<'a> Arbitrary<'a>>(randomness: &[u8; 100000]) -> T {
446-
let unstructured = Unstructured::new(randomness);
447-
T::arbitrary_take_rest(unstructured).unwrap()
448-
}
449-
450-
let mut rng: StdRng = SeedableRng::from_seed(seed);
451-
452-
let t: T = {
453-
let mut randomness = [0u8; 100000];
454-
rng.fill(&mut randomness);
455-
prepare_random_object(&randomness)
456-
};
457-
458-
let address: u32 = rng.gen_range(0..(1 << 30));
459-
let address = bfe!(address);
460-
self.initial_state(address, t)
461-
}
462-
463-
fn corner_case_initial_states(&self) -> Vec<AccessorInitialState> {
464-
// This *should* always return `None` if `T: Option<S>`, and empty
465-
// vec if type is Vec<T>. So some notion of "empty" or default.
466-
let empty_struct: T = {
467-
let unstructured = Unstructured::new(&[]);
468-
T::arbitrary_take_rest(unstructured).unwrap()
469-
};
470-
471-
println!("empty_struct:\n{empty_struct:?}");
472-
let empty_struct_at_zero = self.initial_state(BFieldElement::ZERO, empty_struct);
473-
474-
vec![empty_struct_at_zero]
475-
}
476-
}
477566
}
478567

479568
#[cfg(test)]

0 commit comments

Comments
 (0)