Skip to main content

sp1_core_machine/utils/
mod.rs

1pub mod concurrency;
2mod logger;
3mod prove;
4mod span;
5#[cfg(test)]
6mod test;
7mod zerocheck_unit_test;
8
9pub use logger::*;
10pub use prove::*;
11use slop_algebra::{AbstractField, Field};
12pub use span::*;
13#[cfg(test)]
14pub use test::*;
15pub use zerocheck_unit_test::*;
16
17use sp1_hypercube::{air::SP1AirBuilder, Word};
18pub use sp1_primitives::consts::{
19    bytes_to_words_le, bytes_to_words_le_vec, num_to_comma_separated, words_to_bytes_le,
20    words_to_bytes_le_vec,
21};
22use sp1_primitives::{consts::WORD_BYTE_SIZE, utils::reverse_bits_len};
23
24pub use sp1_hypercube::{indices_arr, next_multiple_of_32, pad_rows_fixed};
25
26pub fn limbs_to_words<AB: SP1AirBuilder>(limbs: Vec<AB::Var>) -> Vec<Word<AB::Expr>> {
27    let base = AB::Expr::from_canonical_u32(1 << 8);
28    let result_words: Vec<Word<AB::Expr>> = limbs
29        .chunks_exact(WORD_BYTE_SIZE)
30        .map(|l| {
31            Word([
32                l[0] + l[1] * base.clone(),
33                l[2] + l[3] * base.clone(),
34                l[4] + l[5] * base.clone(),
35                l[6] + l[7] * base.clone(),
36            ])
37        })
38        .collect();
39    result_words
40}
41
42pub fn u32_to_half_word<F: Field>(value: u32) -> [F; 2] {
43    [F::from_canonical_u16((value & 0xFFFF) as u16), F::from_canonical_u16((value >> 16) as u16)]
44}
45
46#[inline]
47pub fn log2_strict_usize(n: usize) -> usize {
48    let res = n.trailing_zeros();
49    assert_eq!(n.wrapping_shr(res), 1, "Not a power of two: {n}");
50    res as usize
51}
52
53/// Returns a vector of zeros of the given length. This is faster than vec![F::zero(); len] which
54/// requires copying.
55///
56/// This function is safe to use only for fields that can be transmuted from 0u32.
57pub fn zeroed_f_vec<F: Field>(len: usize) -> Vec<F> {
58    debug_assert!(std::mem::size_of::<F>() == 4);
59
60    let vec = vec![0u32; len];
61    unsafe { std::mem::transmute::<Vec<u32>, Vec<F>>(vec) }
62}
63
64/// Reverse the order of elements in a slice using bit-reversed indices.
65///
66/// This function reorders the elements of a slice such that the element at index `i`
67/// is moved to index `reverse_bits_len(i, log2(len))`.
68pub fn reverse_slice_index_bits<T>(slice: &mut [T]) {
69    let n = slice.len();
70    assert!(n.is_power_of_two(), "Slice length must be a power of two");
71    let log_n = log2_strict_usize(n);
72
73    for i in 0..n {
74        let j = reverse_bits_len(i, log_n);
75        if i < j {
76            slice.swap(i, j);
77        }
78    }
79}