cairo_vm/hint_processor/builtin_hint_processor/
blake2s_utils.rs

1use crate::stdlib::{borrow::Cow, collections::HashMap, prelude::*};
2
3use crate::types::errors::math_errors::MathError;
4use crate::Felt252;
5use crate::{
6    hint_processor::{
7        builtin_hint_processor::{
8            blake2s_hash::{blake2s_compress, IV},
9            hint_utils::{get_ptr_from_var_name, get_relocatable_from_var_name},
10        },
11        hint_processor_definition::HintReference,
12        hint_processor_utils::felt_to_u32,
13    },
14    math_utils::pow2_const_nz,
15    serde::deserialize_program::ApTracking,
16    types::relocatable::{MaybeRelocatable, Relocatable},
17    vm::{errors::hint_errors::HintError, vm_core::VirtualMachine},
18};
19
20use num_traits::ToPrimitive;
21
22use super::hint_utils::get_integer_from_var_name;
23
24fn get_fixed_size_u32_array<const T: usize>(
25    h_range: &Vec<Cow<Felt252>>,
26) -> Result<[u32; T], HintError> {
27    let mut u32_vec = Vec::<u32>::with_capacity(h_range.len());
28    for num in h_range {
29        u32_vec.push(num.to_u32().ok_or(HintError::BigintToU32Fail)?);
30    }
31    u32_vec
32        .try_into()
33        .map_err(|_| HintError::FixedSizeArrayFail(T))
34}
35
36fn get_maybe_relocatable_array_from_u32(array: &Vec<u32>) -> Vec<MaybeRelocatable> {
37    let mut new_array = Vec::<MaybeRelocatable>::with_capacity(array.len());
38    for element in array {
39        new_array.push(MaybeRelocatable::from(Felt252::from(*element)));
40    }
41    new_array
42}
43
44/*Helper function for the Cairo blake2s() implementation.
45Computes the blake2s compress function and fills the value in the right position.
46output_ptr should point to the middle of an instance, right after initial_state, message, t, f,
47which should all have a value at this point, and right before the output portion which will be
48written by this function.*/
49fn compute_blake2s_func(vm: &mut VirtualMachine, output_ptr: Relocatable) -> Result<(), HintError> {
50    let h = get_fixed_size_u32_array::<8>(&vm.get_integer_range((output_ptr - 26)?, 8)?)?;
51    let message = get_fixed_size_u32_array::<16>(&vm.get_integer_range((output_ptr - 18)?, 16)?)?;
52    let t = felt_to_u32(vm.get_integer((output_ptr - 2)?)?.as_ref())?;
53    let f = felt_to_u32(vm.get_integer((output_ptr - 1)?)?.as_ref())?;
54    let new_state =
55        get_maybe_relocatable_array_from_u32(&blake2s_compress(&h, &message, t, 0, f, 0));
56    vm.load_data(output_ptr, &new_state)
57        .map_err(HintError::Memory)?;
58    Ok(())
59}
60
61/* Implements hint:
62   from starkware.cairo.common.cairo_blake2s.blake2s_utils import compute_blake2s_func
63   compute_blake2s_func(segments=segments, output_ptr=ids.output)
64*/
65pub fn compute_blake2s(
66    vm: &mut VirtualMachine,
67    ids_data: &HashMap<String, HintReference>,
68    ap_tracking: &ApTracking,
69) -> Result<(), HintError> {
70    let output = get_ptr_from_var_name("output", vm, ids_data, ap_tracking)?;
71    compute_blake2s_func(vm, output)
72}
73
74/* Implements Hint:
75    # Add dummy pairs of input and output.
76    from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
77
78    _n_packed_instances = int(ids.N_PACKED_INSTANCES)
79    assert 0 <= _n_packed_instances < 20
80    _blake2s_input_chunk_size_felts = int(ids.INPUT_BLOCK_FELTS)
81    assert 0 <= _blake2s_input_chunk_size_felts < 100
82
83    message = [0] * _blake2s_input_chunk_size_felts
84    modified_iv = [IV[0] ^ 0x01010020] + IV[1:]
85    output = blake2s_compress(
86        message=message,
87        h=modified_iv,
88        t0=0,
89        t1=0,
90        f0=0xffffffff,
91        f1=0,
92    )
93    padding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
94    segments.write_arg(ids.blake2s_ptr_end, padding)
95*/
96pub fn finalize_blake2s(
97    vm: &mut VirtualMachine,
98    ids_data: &HashMap<String, HintReference>,
99    ap_tracking: &ApTracking,
100) -> Result<(), HintError> {
101    const N_PACKED_INSTANCES: usize = 7;
102    let blake2s_ptr_end = get_ptr_from_var_name("blake2s_ptr_end", vm, ids_data, ap_tracking)?;
103    let message: [u32; 16] = [0; 16];
104    let mut modified_iv = IV;
105    modified_iv[0] = IV[0] ^ 0x01010020;
106    let output = blake2s_compress(&modified_iv, &message, 0, 0, 0xffffffff, 0);
107    let mut padding = modified_iv.to_vec();
108    padding.extend(message);
109    padding.extend([0, 0xffffffff]);
110    padding.extend(output);
111    let padding = padding.as_slice();
112    let mut full_padding = Vec::<u32>::with_capacity(padding.len() * N_PACKED_INSTANCES);
113    for _ in 0..N_PACKED_INSTANCES - 1 {
114        full_padding.extend_from_slice(padding);
115    }
116    let data = get_maybe_relocatable_array_from_u32(&full_padding);
117    vm.load_data(blake2s_ptr_end, &data)
118        .map_err(HintError::Memory)?;
119    Ok(())
120}
121
122/* Implements Hint:
123        # Add dummy pairs of input and output.
124        from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
125
126        _n_packed_instances = int(ids.N_PACKED_INSTANCES)
127        assert 0 <= _n_packed_instances < 20
128        _blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
129        assert 0 <= _blake2s_input_chunk_size_felts < 100
130
131        message = [0] * _blake2s_input_chunk_size_felts
132        modified_iv = [IV[0] ^ 0x01010020] + IV[1:]
133        output = blake2s_compress(
134            message=message,
135            h=modified_iv,
136            t0=0,
137            t1=0,
138            f0=0xffffffff,
139            f1=0,
140        )
141        padding = (message + modified_iv + [0, 0xffffffff] + output) * (_n_packed_instances - 1)
142        segments.write_arg(ids.blake2s_ptr_end, padding)
143*/
144pub fn finalize_blake2s_v3(
145    vm: &mut VirtualMachine,
146    ids_data: &HashMap<String, HintReference>,
147    ap_tracking: &ApTracking,
148) -> Result<(), HintError> {
149    const N_PACKED_INSTANCES: usize = 7;
150    let blake2s_ptr_end = get_ptr_from_var_name("blake2s_ptr_end", vm, ids_data, ap_tracking)?;
151    let message: [u32; 16] = [0; 16];
152    let mut modified_iv = IV;
153    modified_iv[0] = IV[0] ^ 0x01010020;
154    let output = blake2s_compress(&modified_iv, &message, 0, 0, 0xffffffff, 0);
155    let mut padding = message.to_vec();
156    padding.extend(modified_iv);
157    padding.extend([0, 0xffffffff]);
158    padding.extend(output);
159    let padding = padding.as_slice();
160    let mut full_padding = Vec::<u32>::with_capacity(padding.len() * N_PACKED_INSTANCES);
161    for _ in 0..N_PACKED_INSTANCES - 1 {
162        full_padding.extend_from_slice(padding);
163    }
164    let data = get_maybe_relocatable_array_from_u32(&full_padding);
165    vm.load_data(blake2s_ptr_end, &data)
166        .map_err(HintError::Memory)?;
167    Ok(())
168}
169
170/* Implements Hint:
171    B = 32
172    MASK = 2 ** 32 - 1
173    segments.write_arg(ids.data, [(ids.low >> (B * i)) & MASK for i in range(4)])
174    segments.write_arg(ids.data + 4, [(ids.high >> (B * i)) & MASK for i in range(4)])
175*/
176pub fn blake2s_add_uint256(
177    vm: &mut VirtualMachine,
178    ids_data: &HashMap<String, HintReference>,
179    ap_tracking: &ApTracking,
180) -> Result<(), HintError> {
181    //Get variables from ids
182    let data_ptr = get_ptr_from_var_name("data", vm, ids_data, ap_tracking)?;
183    let low_addr = get_relocatable_from_var_name("low", vm, ids_data, ap_tracking)?;
184    let high_addr = get_relocatable_from_var_name("high", vm, ids_data, ap_tracking)?;
185    let mut low = vm.get_integer(low_addr)?.into_owned();
186    let mut high = vm.get_integer(high_addr)?.into_owned();
187    //Main logic
188    //Build first batch of data
189    let b = pow2_const_nz(32);
190    let mut data = Vec::<MaybeRelocatable>::with_capacity(8);
191    for _ in 0..4 {
192        let (q, r) = low.div_rem(b);
193        data.push(r.into());
194        low = q;
195    }
196    for _ in 0..4 {
197        let (q, r) = high.div_rem(b);
198        data.push(r.into());
199        high = q;
200    }
201    //Insert second batch of data
202    vm.load_data(data_ptr, &data).map_err(HintError::Memory)?;
203    Ok(())
204}
205
206/* Implements Hint:
207    B = 32
208    MASK = 2 ** 32 - 1
209    segments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)])
210    segments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])
211*/
212pub fn blake2s_add_uint256_bigend(
213    vm: &mut VirtualMachine,
214    ids_data: &HashMap<String, HintReference>,
215    ap_tracking: &ApTracking,
216) -> Result<(), HintError> {
217    //Get variables from ids
218    let data_ptr = get_ptr_from_var_name("data", vm, ids_data, ap_tracking)?;
219    let low_addr = get_relocatable_from_var_name("low", vm, ids_data, ap_tracking)?;
220    let high_addr = get_relocatable_from_var_name("high", vm, ids_data, ap_tracking)?;
221    let mut low = vm.get_integer(low_addr)?.into_owned();
222    let mut high = vm.get_integer(high_addr)?.into_owned();
223    //Main logic
224    let b = pow2_const_nz(32);
225    let mut data = Vec::<MaybeRelocatable>::with_capacity(8);
226    //Build first batch of data
227    for _ in 0..4 {
228        let (q, r) = low.div_rem(b);
229        data.push(r.into());
230        low = q;
231    }
232    //Build second batch of data
233    for _ in 0..4 {
234        let (q, r) = high.div_rem(b);
235        data.push(r.into());
236        high = q;
237    }
238    //Reverse to make big-endian
239    data.reverse();
240    //Insert second batch of data
241    vm.load_data(data_ptr, &data).map_err(HintError::Memory)?;
242    Ok(())
243}
244
245/* Implements Hint:
246    %{
247        from starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress
248
249        _blake2s_input_chunk_size_felts = int(ids.BLAKE2S_INPUT_CHUNK_SIZE_FELTS)
250        assert 0 <= _blake2s_input_chunk_size_felts < 100
251
252        new_state = blake2s_compress(
253            message=memory.get_range(ids.blake2s_start, _blake2s_input_chunk_size_felts),
254            h=[IV[0] ^ 0x01010020] + IV[1:],
255            t0=ids.n_bytes,
256            t1=0,
257            f0=0xffffffff,
258            f1=0,
259        )
260
261        segments.write_arg(ids.output, new_state)
262    %}
263
264Note: This hint belongs to the blake2s lib in cario_examples
265*/
266pub fn example_blake2s_compress(
267    vm: &mut VirtualMachine,
268    ids_data: &HashMap<String, HintReference>,
269    ap_tracking: &ApTracking,
270) -> Result<(), HintError> {
271    let blake2s_start = get_ptr_from_var_name("blake2s_start", vm, ids_data, ap_tracking)?;
272    let output = get_ptr_from_var_name("output", vm, ids_data, ap_tracking)?;
273    let n_bytes = get_integer_from_var_name("n_bytes", vm, ids_data, ap_tracking).map(|x| {
274        x.to_u32()
275            .ok_or_else(|| HintError::Math(MathError::Felt252ToU32Conversion(Box::new(x))))
276    })??;
277
278    let message = get_fixed_size_u32_array::<16>(&vm.get_integer_range(blake2s_start, 16)?)?;
279    let mut modified_iv = IV;
280    modified_iv[0] = IV[0] ^ 0x01010020;
281    let new_state = blake2s_compress(&modified_iv, &message, n_bytes, 0, 0xffffffff, 0);
282    let new_state: Vec<MaybeRelocatable> = new_state
283        .iter()
284        .map(|x| MaybeRelocatable::from(*x as usize))
285        .collect();
286    vm.segments.write_arg(output, &new_state)?;
287    Ok(())
288}
289
290#[cfg(test)]
291mod tests {
292    use super::*;
293    use crate::hint_processor::builtin_hint_processor::hint_code;
294    use crate::types::errors::math_errors::MathError;
295    use crate::{
296        any_box,
297        hint_processor::{
298            builtin_hint_processor::builtin_hint_processor_definition::{
299                BuiltinHintProcessor, HintProcessorData,
300            },
301            hint_processor_definition::HintProcessorLogic,
302        },
303        relocatable,
304        utils::test_utils::*,
305        vm::errors::memory_errors::MemoryError,
306    };
307    use assert_matches::assert_matches;
308
309    #[cfg(target_arch = "wasm32")]
310    use wasm_bindgen_test::*;
311
312    #[test]
313    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
314    fn compute_blake2s_output_offset_zero() {
315        let hint_code = "from starkware.cairo.common.cairo_blake2s.blake2s_utils import compute_blake2s_func\ncompute_blake2s_func(segments=segments, output_ptr=ids.output)";
316        //Create vm
317        let mut vm = vm!();
318        //Initialize fp
319        vm.run_context.fp = 1;
320        //Insert ids into memory (output)
321        vm.segments = segments![((1, 0), (2, 5))];
322        //Create hint data
323        let ids_data = ids_data!["output"];
324        //Execute the hint
325        assert_matches!(
326            run_hint!(vm, ids_data, hint_code),
327            Err(HintError::Math(MathError::RelocatableSubUsizeNegOffset(bx)))
328            if *bx == (relocatable!(2,5), 26)
329        );
330    }
331
332    #[test]
333    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
334    fn compute_blake2s_output_empty_segment() {
335        let hint_code = "from starkware.cairo.common.cairo_blake2s.blake2s_utils import compute_blake2s_func\ncompute_blake2s_func(segments=segments, output_ptr=ids.output)";
336        //Create vm
337        let mut vm = vm!();
338        //Initialize fp
339        vm.run_context.fp = 1;
340        //Insert ids into memory (output)
341        vm.segments = segments![((1, 0), (2, 26))];
342        add_segments!(vm, 1);
343        //Create hint data
344        let ids_data = ids_data!["output"];
345        //Execute the hint
346        assert_matches!(
347            run_hint!(vm, ids_data, hint_code),
348            Err(HintError::Memory(MemoryError::UnknownMemoryCell(
349                bx
350            ))) if *bx == Relocatable::from((2, 0))
351        );
352    }
353
354    #[test]
355    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
356    fn compute_blake2s_output_not_relocatable() {
357        let hint_code = "from starkware.cairo.common.cairo_blake2s.blake2s_utils import compute_blake2s_func\ncompute_blake2s_func(segments=segments, output_ptr=ids.output)";
358        //Create vm
359        let mut vm = vm!();
360        //Initialize fp
361        vm.run_context.fp = 1;
362        //Insert ids into memory (output)
363        vm.segments = segments![((1, 0), 12)];
364        //Create hint data
365        let ids_data = ids_data!["output"];
366        //Execute the hint
367        assert_matches!(
368            run_hint!(vm, ids_data, hint_code),
369            Err(HintError::IdentifierNotRelocatable(bx))
370            if bx.as_ref() == "output"
371        );
372    }
373
374    #[test]
375    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
376    fn compute_blake2s_output_input_bigger_than_u32() {
377        let hint_code = "from starkware.cairo.common.cairo_blake2s.blake2s_utils import compute_blake2s_func\ncompute_blake2s_func(segments=segments, output_ptr=ids.output)";
378        //Create vm
379        let mut vm = vm!();
380        //Initialize fp
381        //Insert ids into memory
382        vm.run_context.fp = 1;
383        vm.segments = segments![
384            ((1, 0), (2, 26)),
385            ((2, 0), 7842562439562793675803603603688959_i128),
386            ((2, 1), 7842562439562793675803603603688959_i128),
387            ((2, 2), 7842562439562793675803603603688959_i128),
388            ((2, 3), 7842562439562793675803603603688959_i128),
389            ((2, 4), 7842562439562793675803603603688959_i128),
390            ((2, 5), 7842562439562793675803603603688959_i128),
391            ((2, 6), 7842562439562793675803603603688959_i128),
392            ((2, 7), 7842562439562793675803603603688959_i128)
393        ];
394        //Create hint data
395        let ids_data = ids_data!["output"];
396        //Execute the hint
397        assert_matches!(
398            run_hint!(vm, ids_data, hint_code),
399            Err(HintError::BigintToU32Fail)
400        );
401    }
402
403    #[test]
404    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
405    fn compute_blake2s_output_input_relocatable() {
406        let hint_code = "from starkware.cairo.common.cairo_blake2s.blake2s_utils import compute_blake2s_func\ncompute_blake2s_func(segments=segments, output_ptr=ids.output)";
407        //Create vm
408        let mut vm = vm!();
409        //Initialize fp
410        vm.run_context.fp = 1;
411        //Insert ids into memory (output)
412        vm.segments = segments![((1, 0), (2, 26)), ((2, 0), (5, 5))];
413        //Create hint data
414        let ids_data = ids_data!["output"];
415        //Execute the hint
416        assert_matches!(
417            run_hint!(vm, ids_data, hint_code),
418            Err(HintError::Memory(MemoryError::ExpectedInteger(
419                bx
420            ))) if *bx == Relocatable::from((2, 0))
421        );
422    }
423
424    #[test]
425    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
426    fn finalize_blake2s_valid() {
427        let hint_code = "# Add dummy pairs of input and output.\nfrom starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress\n\n_n_packed_instances = int(ids.N_PACKED_INSTANCES)\nassert 0 <= _n_packed_instances < 20\n_blake2s_input_chunk_size_felts = int(ids.INPUT_BLOCK_FELTS)\nassert 0 <= _blake2s_input_chunk_size_felts < 100\n\nmessage = [0] * _blake2s_input_chunk_size_felts\nmodified_iv = [IV[0] ^ 0x01010020] + IV[1:]\noutput = blake2s_compress(\n    message=message,\n    h=modified_iv,\n    t0=0,\n    t1=0,\n    f0=0xffffffff,\n    f1=0,\n)\npadding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)\nsegments.write_arg(ids.blake2s_ptr_end, padding)";
428        //Create vm
429        let mut vm = vm!();
430        //Initialize fp
431        vm.run_context.fp = 1;
432        //Insert ids into memory (output)
433        vm.segments = segments![((1, 0), (2, 0))];
434        add_segments!(vm, 1);
435        //Create hint data
436        let ids_data = ids_data!["blake2s_ptr_end"];
437        //Execute the hint
438        assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
439        //Check the inserted data
440        let expected_data: [u32; 204] = [
441            1795745351, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635,
442            1541459225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4294967295, 813310313,
443            2491453561, 3491828193, 2085238082, 1219908895, 514171180, 4245497115, 4193177630,
444            1795745351, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635,
445            1541459225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4294967295, 813310313,
446            2491453561, 3491828193, 2085238082, 1219908895, 514171180, 4245497115, 4193177630,
447            1795745351, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635,
448            1541459225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4294967295, 813310313,
449            2491453561, 3491828193, 2085238082, 1219908895, 514171180, 4245497115, 4193177630,
450            1795745351, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635,
451            1541459225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4294967295, 813310313,
452            2491453561, 3491828193, 2085238082, 1219908895, 514171180, 4245497115, 4193177630,
453            1795745351, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635,
454            1541459225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4294967295, 813310313,
455            2491453561, 3491828193, 2085238082, 1219908895, 514171180, 4245497115, 4193177630,
456            1795745351, 3144134277, 1013904242, 2773480762, 1359893119, 2600822924, 528734635,
457            1541459225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4294967295, 813310313,
458            2491453561, 3491828193, 2085238082, 1219908895, 514171180, 4245497115, 4193177630,
459        ];
460        //Get data from memory
461        let data = get_fixed_size_u32_array::<204>(
462            &vm.segments
463                .memory
464                .get_integer_range(relocatable!(2, 0), 204)
465                .unwrap(),
466        )
467        .unwrap();
468        assert_eq!(expected_data, data);
469    }
470
471    #[test]
472    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
473    fn finalize_blake2s_invalid_segment_taken() {
474        let hint_code = "# Add dummy pairs of input and output.\nfrom starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress\n\n_n_packed_instances = int(ids.N_PACKED_INSTANCES)\nassert 0 <= _n_packed_instances < 20\n_blake2s_input_chunk_size_felts = int(ids.INPUT_BLOCK_FELTS)\nassert 0 <= _blake2s_input_chunk_size_felts < 100\n\nmessage = [0] * _blake2s_input_chunk_size_felts\nmodified_iv = [IV[0] ^ 0x01010020] + IV[1:]\noutput = blake2s_compress(\n    message=message,\n    h=modified_iv,\n    t0=0,\n    t1=0,\n    f0=0xffffffff,\n    f1=0,\n)\npadding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)\nsegments.write_arg(ids.blake2s_ptr_end, padding)";
475        //Create vm
476        let mut vm = vm!();
477        //Initialize fp
478        vm.run_context.fp = 1;
479        //Insert ids into memory (output)
480        vm.segments = segments![((1, 0), (2, 0)), ((2, 0), (2, 0))];
481        let ids_data = ids_data!["blake2s_ptr_end"];
482        //Execute the hint
483        assert_matches!(
484            run_hint!(vm, ids_data, hint_code),
485            Err(HintError::Memory(
486                MemoryError::InconsistentMemory(bx)
487            )) if *bx == (Relocatable::from((2, 0)),
488                    MaybeRelocatable::from((2, 0)),
489                    MaybeRelocatable::from(Felt252::from(1795745351)))
490        );
491    }
492
493    #[test]
494    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
495    fn finalize_blake2s_invalid_no_ids() {
496        let hint_code = "# Add dummy pairs of input and output.\nfrom starkware.cairo.common.cairo_blake2s.blake2s_utils import IV, blake2s_compress\n\n_n_packed_instances = int(ids.N_PACKED_INSTANCES)\nassert 0 <= _n_packed_instances < 20\n_blake2s_input_chunk_size_felts = int(ids.INPUT_BLOCK_FELTS)\nassert 0 <= _blake2s_input_chunk_size_felts < 100\n\nmessage = [0] * _blake2s_input_chunk_size_felts\nmodified_iv = [IV[0] ^ 0x01010020] + IV[1:]\noutput = blake2s_compress(\n    message=message,\n    h=modified_iv,\n    t0=0,\n    t1=0,\n    f0=0xffffffff,\n    f1=0,\n)\npadding = (modified_iv + message + [0, 0xffffffff] + output) * (_n_packed_instances - 1)\nsegments.write_arg(ids.blake2s_ptr_end, padding)";
497        //Create vm
498        let mut vm = vm!();
499        //Initialize fp
500        vm.run_context.fp = 1;
501        //Execute the hint
502        assert_matches!(
503            run_hint!(vm, HashMap::new(), hint_code),
504            Err(HintError::UnknownIdentifier(bx)) if bx.as_ref() == "blake2s_ptr_end"
505        );
506    }
507
508    #[test]
509    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
510    fn blake2s_add_uint256_valid_zero() {
511        let hint_code = "B = 32\nMASK = 2 ** 32 - 1\nsegments.write_arg(ids.data, [(ids.low >> (B * i)) & MASK for i in range(4)])\nsegments.write_arg(ids.data + 4, [(ids.high >> (B * i)) & MASK for i in range(4)])";
512        //Create vm
513        let mut vm = vm!();
514        //Initialize fp
515        vm.run_context.fp = 3;
516        //Insert ids into memory
517        vm.segments = segments![((1, 0), (2, 0)), ((1, 1), 0), ((1, 2), 0)];
518        vm.segments.add();
519        let ids_data = ids_data!["data", "high", "low"];
520        //Execute the hint
521        assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
522        //Check data ptr
523        check_memory![
524            vm.segments.memory,
525            ((2, 0), 0),
526            ((2, 1), 0),
527            ((2, 2), 0),
528            ((2, 3), 0),
529            ((2, 4), 0),
530            ((2, 5), 0),
531            ((2, 6), 0),
532            ((2, 7), 0)
533        ];
534        assert!(vm
535            .segments
536            .memory
537            .get(&MaybeRelocatable::from((2, 8)))
538            .is_none());
539    }
540
541    #[test]
542    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
543    fn blake2s_add_uint256_valid_non_zero() {
544        let hint_code = "B = 32\nMASK = 2 ** 32 - 1\nsegments.write_arg(ids.data, [(ids.low >> (B * i)) & MASK for i in range(4)])\nsegments.write_arg(ids.data + 4, [(ids.high >> (B * i)) & MASK for i in range(4)])";
545        //Create vm
546        let mut vm = vm!();
547        //Initialize fp
548        vm.run_context.fp = 3;
549        //Insert ids into memory
550        vm.segments = segments![((1, 0), (2, 0)), ((1, 1), 25), ((1, 2), 20)];
551        vm.segments.add();
552        let ids_data = ids_data!["data", "high", "low"];
553        //Execute the hint
554        assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
555        //Check data ptr
556        check_memory![
557            vm.segments.memory,
558            ((2, 0), 20),
559            ((2, 1), 0),
560            ((2, 2), 0),
561            ((2, 3), 0),
562            ((2, 4), 25),
563            ((2, 5), 0),
564            ((2, 6), 0),
565            ((2, 7), 0)
566        ];
567        assert!(vm
568            .segments
569            .memory
570            .get(&MaybeRelocatable::from((2, 8)))
571            .is_none());
572    }
573
574    #[test]
575    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
576    fn blake2s_add_uint256_bigend_valid_zero() {
577        let hint_code = "B = 32\nMASK = 2 ** 32 - 1\nsegments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)])\nsegments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])";
578        //Create vm
579        let mut vm = vm!();
580        //Initialize fp
581        vm.run_context.fp = 3;
582        //Insert ids into memory
583        vm.segments = segments![((1, 0), (2, 0)), ((1, 1), 0), ((1, 2), 0)];
584        add_segments!(vm, 1);
585        let ids_data = ids_data!["data", "high", "low"];
586        //Execute the hint
587        assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
588        //Check data ptr
589        check_memory![
590            vm.segments.memory,
591            ((2, 0), 0),
592            ((2, 1), 0),
593            ((2, 2), 0),
594            ((2, 3), 0),
595            ((2, 4), 0),
596            ((2, 5), 0),
597            ((2, 6), 0),
598            ((2, 7), 0)
599        ];
600        assert!(vm
601            .segments
602            .memory
603            .get(&MaybeRelocatable::from((2, 8)))
604            .is_none());
605    }
606
607    #[test]
608    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
609    fn blake2s_add_uint256_bigend_valid_non_zero() {
610        let hint_code = "B = 32\nMASK = 2 ** 32 - 1\nsegments.write_arg(ids.data, [(ids.high >> (B * (3 - i))) & MASK for i in range(4)])\nsegments.write_arg(ids.data + 4, [(ids.low >> (B * (3 - i))) & MASK for i in range(4)])";
611        //Create vm
612        let mut vm = vm!();
613        //Initialize fp
614        vm.run_context.fp = 3;
615        //Insert ids into memory
616        vm.segments = segments![((1, 0), (2, 0)), ((1, 1), 25), ((1, 2), 20)];
617        vm.segments.add();
618        let ids_data = ids_data!["data", "high", "low"];
619        //Execute the hint
620        assert_matches!(run_hint!(vm, ids_data, hint_code), Ok(()));
621        //Check data ptr
622        check_memory![
623            vm.segments.memory,
624            ((2, 0), 0),
625            ((2, 1), 0),
626            ((2, 2), 0),
627            ((2, 3), 25),
628            ((2, 4), 0),
629            ((2, 5), 0),
630            ((2, 6), 0),
631            ((2, 7), 20)
632        ];
633        assert!(vm
634            .segments
635            .memory
636            .get(&MaybeRelocatable::from((2, 8)))
637            .is_none());
638    }
639
640    #[test]
641    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
642    fn example_blake2s_compress_n_bytes_over_u32() {
643        //Create vm
644        let mut vm = vm!();
645        //Initialize fp
646        vm.run_context.fp = 3;
647        //Insert ids into memory
648        vm.segments = segments![((1, 0), 9999999999_u64), ((1, 1), (1, 0)), ((1, 2), (2, 0))];
649        let ids_data = ids_data!["n_bytes", "output", "blake2s_start"];
650        //Execute the hint
651        assert_matches!(run_hint!(vm, ids_data, hint_code::EXAMPLE_BLAKE2S_COMPRESS), Err(HintError::Math(MathError::Felt252ToU32Conversion(bx))) if *bx == Felt252::from(9999999999_u64));
652    }
653
654    #[test]
655    #[cfg_attr(target_arch = "wasm32", wasm_bindgen_test)]
656    fn example_blake2s_empty_input() {
657        //Create vm
658        let mut vm = vm!();
659        //Initialize fp
660        vm.run_context.fp = 3;
661        //Insert ids into memory
662        vm.segments = segments![((1, 0), 9), ((1, 1), (1, 0)), ((1, 2), (2, 0))];
663        let ids_data = ids_data!["n_bytes", "output", "blake2s_start"];
664        //Execute the hint
665        assert_matches!(run_hint!(vm, ids_data, hint_code::EXAMPLE_BLAKE2S_COMPRESS), Err(HintError::Memory(MemoryError::UnknownMemoryCell(bx))) if *bx == (2, 0).into());
666    }
667}