winter_utils/
lib.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6//! This crate contains utility traits, functions, and macros used by other crates of Winterfell
7//! STARK prover and verifier.
8#![no_std]
9
10#[macro_use]
11extern crate alloc;
12
13#[cfg(feature = "std")]
14extern crate std;
15
16pub mod iterators;
17
18use alloc::vec::Vec;
19use core::{mem, slice};
20
21mod serde;
22#[cfg(feature = "std")]
23pub use serde::ReadAdapter;
24pub use serde::{ByteReader, ByteWriter, Deserializable, Serializable, SliceReader};
25
26mod errors;
27pub use errors::DeserializationError;
28
29#[cfg(test)]
30mod tests;
31
32// FEATURE-BASED RE-EXPORTS
33// ================================================================================================
34
35#[cfg(feature = "concurrent")]
36use iterators::*;
37#[cfg(feature = "concurrent")]
38pub use rayon;
39
40// AS BYTES
41// ================================================================================================
42
43/// Defines a zero-copy representation of `Self` as a sequence of bytes.
44pub trait AsBytes {
45    /// Returns a byte representation of `self`.
46    ///
47    /// This method is intended to re-interpret the underlying memory as a sequence of bytes, and
48    /// thus, should be zero-copy.
49    fn as_bytes(&self) -> &[u8];
50}
51
52impl<const N: usize, const M: usize> AsBytes for [[u8; N]; M] {
53    /// Flattens a two-dimensional array of bytes into a slice of bytes.
54    fn as_bytes(&self) -> &[u8] {
55        let p = self.as_ptr();
56        let len = N * M;
57        unsafe { slice::from_raw_parts(p as *const u8, len) }
58    }
59}
60
61impl<const N: usize> AsBytes for [[u8; N]] {
62    /// Flattens a slice of byte arrays into a slice of bytes.
63    fn as_bytes(&self) -> &[u8] {
64        let p = self.as_ptr();
65        let len = self.len() * N;
66        unsafe { slice::from_raw_parts(p as *const u8, len) }
67    }
68}
69
70// VECTOR FUNCTIONS
71// ================================================================================================
72
73/// Returns a vector of the specified length with un-initialized memory.
74///
75/// This is usually faster than requesting a vector with initialized memory and is useful when we
76/// overwrite all contents of the vector immediately after memory allocation.
77///
78/// # Safety
79/// Using values from the returned vector before initializing them will lead to undefined behavior.
80#[allow(clippy::uninit_vec)]
81pub unsafe fn uninit_vector<T>(length: usize) -> Vec<T> {
82    let mut vector = Vec::with_capacity(length);
83    vector.set_len(length);
84    vector
85}
86
87// GROUPING / UN-GROUPING FUNCTIONS
88// ================================================================================================
89
90/// Transmutes a slice of `n` elements into a slice of `n` / `N` elements, each of which is
91/// an array of `N` elements.
92///
93/// This function just re-interprets the underlying memory and is thus zero-copy.
94/// # Panics
95/// Panics if `n` is not divisible by `N`.
96///
97/// # Example
98/// ```
99/// # use winter_utils::group_slice_elements;
100/// let a = [0_u32, 1, 2, 3, 4, 5, 6, 7];
101/// let b: &[[u32; 2]] = group_slice_elements(&a);
102///
103/// assert_eq!(&[[0, 1], [2, 3], [4, 5], [6, 7]], b);
104/// ```
105pub fn group_slice_elements<T, const N: usize>(source: &[T]) -> &[[T; N]] {
106    assert_eq!(source.len() % N, 0, "source length must be divisible by {N}");
107    let p = source.as_ptr();
108    let len = source.len() / N;
109    unsafe { slice::from_raw_parts(p as *const [T; N], len) }
110}
111
112/// Transmutes a slice of `n` arrays each of length `N`, into a slice of `N` * `n` elements.
113///
114/// This function just re-interprets the underlying memory and is thus zero-copy.
115/// # Example
116/// ```
117/// # use winter_utils::flatten_slice_elements;
118/// let a = vec![[1, 2, 3, 4], [5, 6, 7, 8]];
119///
120/// let b = flatten_slice_elements(&a);
121/// assert_eq!(&[1, 2, 3, 4, 5, 6, 7, 8], b);
122/// ```
123pub fn flatten_slice_elements<T, const N: usize>(source: &[[T; N]]) -> &[T] {
124    let p = source.as_ptr();
125    let len = source.len() * N;
126    unsafe { slice::from_raw_parts(p as *const T, len) }
127}
128
129/// Transmutes a vector of `n` arrays each of length `N`, into a vector of `N` * `n` elements.
130///
131/// This function just re-interprets the underlying memory and is thus zero-copy.
132/// # Example
133/// ```
134/// # use winter_utils::flatten_vector_elements;
135/// let a = vec![[1, 2, 3, 4], [5, 6, 7, 8]];
136///
137/// let b = flatten_vector_elements(a);
138/// assert_eq!(vec![1, 2, 3, 4, 5, 6, 7, 8], b);
139/// ```
140pub fn flatten_vector_elements<T, const N: usize>(source: Vec<[T; N]>) -> Vec<T> {
141    let v = mem::ManuallyDrop::new(source);
142    let p = v.as_ptr();
143    let len = v.len() * N;
144    let cap = v.capacity() * N;
145    unsafe { Vec::from_raw_parts(p as *mut T, len, cap) }
146}
147
148// TRANSPOSING
149// ================================================================================================
150
151/// Transposes a slice of `n` elements into a matrix with `N` columns and `n`/`N` rows.
152///
153/// When `concurrent` feature is enabled, the slice will be transposed using multiple threads.
154///
155/// # Panics
156/// Panics if `n` is not divisible by `N`.
157///
158/// # Example
159/// ```
160/// # use winter_utils::transpose_slice;
161/// let a = [0_u32, 1, 2, 3, 4, 5, 6, 7];
162/// let b: Vec<[u32; 2]> = transpose_slice(&a);
163///
164/// assert_eq!(vec![[0, 4], [1, 5], [2, 6], [3, 7]], b);
165/// ```
166pub fn transpose_slice<T: Copy + Send + Sync, const N: usize>(source: &[T]) -> Vec<[T; N]> {
167    let row_count = source.len() / N;
168    assert_eq!(
169        row_count * N,
170        source.len(),
171        "source length must be divisible by {}, but was {}",
172        N,
173        source.len()
174    );
175
176    let mut result: Vec<[T; N]> = unsafe { uninit_vector(row_count) };
177    iter_mut!(result, 1024).enumerate().for_each(|(i, element)| {
178        for j in 0..N {
179            element[j] = source[i + j * row_count]
180        }
181    });
182    result
183}
184
185// RANDOMNESS
186// ================================================================================================
187
188/// Defines how `Self` can be read from a sequence of random bytes.
189pub trait Randomizable: Sized {
190    /// Size of `Self` in bytes.
191    ///
192    /// This is used to determine how many bytes should be passed to the
193    /// [from_random_bytes()](Self::from_random_bytes) function.
194    const VALUE_SIZE: usize;
195
196    /// Returns `Self` if the set of bytes forms a valid value, otherwise returns None.
197    fn from_random_bytes(source: &[u8]) -> Option<Self>;
198}
199
200impl Randomizable for u128 {
201    const VALUE_SIZE: usize = 16;
202
203    fn from_random_bytes(source: &[u8]) -> Option<Self> {
204        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
205            Some(u128::from_le_bytes(bytes))
206        } else {
207            None
208        }
209    }
210}
211
212impl Randomizable for u64 {
213    const VALUE_SIZE: usize = 8;
214
215    fn from_random_bytes(source: &[u8]) -> Option<Self> {
216        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
217            Some(u64::from_le_bytes(bytes))
218        } else {
219            None
220        }
221    }
222}
223
224impl Randomizable for u32 {
225    const VALUE_SIZE: usize = 4;
226
227    fn from_random_bytes(source: &[u8]) -> Option<Self> {
228        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
229            Some(u32::from_le_bytes(bytes))
230        } else {
231            None
232        }
233    }
234}
235
236impl Randomizable for u16 {
237    const VALUE_SIZE: usize = 2;
238
239    fn from_random_bytes(source: &[u8]) -> Option<Self> {
240        if let Ok(bytes) = source[..Self::VALUE_SIZE].try_into() {
241            Some(u16::from_le_bytes(bytes))
242        } else {
243            None
244        }
245    }
246}
247
248impl Randomizable for u8 {
249    const VALUE_SIZE: usize = 1;
250
251    fn from_random_bytes(source: &[u8]) -> Option<Self> {
252        Some(source[0])
253    }
254}