hacspec_lib/
array.rs

1//!
2//! # Arrays
3//!
4//! This module implements fixed-length arrays and utility functions for it.
5//!
6//! **Note** that all macros starting with an underscore (`_array_base` etc.)
7//! are note intended for public use. Unfortunately it's not possible to hide
8//! them.
9//!
10//! To define a new array type with name `State`, holding `16` `u32` run
11//!
12//! ```
13//! use hacspec_lib::*;
14//! array!(State, 16, u32, type_for_indexes: StateIdx);
15//! ```
16//!
17//! ## Instantiating Arrays
18//! There are several different ways of creating array types.
19//!
20//! ###
21
22#[macro_export]
23#[doc(hidden)]
24macro_rules! _array_base {
25    ($name:ident,$l:expr,$t:ty) => {
26        /// Fixed length byte array.
27        // Because Rust requires fixed length arrays to have a known size at
28        // compile time there's no generic fixed length byte array here.
29        // Use this to define the fixed length byte arrays needed in your code.
30        #[allow(non_camel_case_types)]
31        #[derive(Clone, Copy)]
32        pub struct $name(pub [$t; $l]);
33
34        impl $name {
35            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
36            pub fn new() -> Self {
37                Self([<$t>::default(); $l])
38            }
39
40            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
41            pub fn length() -> usize {
42                $l
43            }
44
45            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
46            pub fn from_array(v: [$t; $l]) -> Self {
47                Self(v.clone())
48            }
49
50            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
51            pub fn from_native_slice(v: &[$t]) -> Self {
52                debug_assert!(v.len() <= $l);
53                let mut tmp = [<$t>::default(); $l];
54                for i in 0..v.len() {
55                    tmp[i] = v[i];
56                }
57                Self(tmp.clone())
58            }
59        }
60
61        impl $name {
62            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
63            pub fn from_slice<A: SeqTrait<$t>>(input: &A, start: usize, len: usize) -> Self {
64                let mut a = Self::new();
65                debug_assert!(len <= a.len(), "{} > {}", len, a.len());
66                a = a.update_slice(0, input, start, len);
67                a
68            }
69
70            #[cfg_attr(feature = "use_attributes", in_hacspec)]
71            pub fn concat<A: SeqTrait<$t>>(&self, next: &A) -> Seq<$t> {
72                let mut out = Seq::new(self.len() + next.len());
73                out = out.update_start(self);
74                out = out.update_slice(self.len(), next, 0, next.len());
75                out
76            }
77
78            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
79            pub fn from_slice_range<A: SeqTrait<$t>>(input: &A, r: Range<usize>) -> Self {
80                Self::from_slice(input, r.start, r.end - r.start)
81            }
82
83            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
84            pub fn slice(&self, start_out: usize, len: usize) -> Seq<$t> {
85                Seq::from_slice(self, start_out, len)
86            }
87
88            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
89            pub fn slice_range(&self, r: Range<usize>) -> Seq<$t> {
90                self.slice(r.start, r.end - r.start)
91            }
92
93            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
94            pub fn num_chunks(&self, chunk_size: usize) -> usize {
95                (self.len() + chunk_size - 1) / chunk_size
96            }
97
98            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
99            pub fn get_chunk_len(&self, chunk_size: usize, chunk_number: usize) -> usize {
100                let idx_start = chunk_size * chunk_number;
101                if idx_start + chunk_size > self.len() {
102                    self.len() - idx_start
103                } else {
104                    chunk_size
105                }
106            }
107
108            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
109            pub fn get_chunk(&self, chunk_size: usize, chunk_number: usize) -> (usize, Seq<$t>) {
110                let idx_start = chunk_size * chunk_number;
111                let len = self.get_chunk_len(chunk_size, chunk_number);
112                let out = self.slice(idx_start, len);
113                (len, out)
114            }
115
116            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
117            pub fn set_chunk<A: SeqTrait<$t>>(
118                self,
119                chunk_size: usize,
120                chunk_number: usize,
121                input: &A,
122            ) -> Self {
123                let idx_start = chunk_size * chunk_number;
124                let len = self.get_chunk_len(chunk_size, chunk_number);
125                debug_assert!(
126                    input.len() == len,
127                    "the chunk length should match the input. got {}, expected {}",
128                    input.len(),
129                    len
130                );
131                self.update_slice(idx_start, input, 0, len)
132            }
133        }
134
135        impl Default for $name {
136            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
137            fn default() -> Self {
138                $name::new()
139            }
140        }
141        impl SeqTrait<$t> for $name {
142            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
143            fn create(x: usize) -> Self {
144                assert_eq!(x, $l);
145                Self::new()
146            }
147
148            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
149            fn len(&self) -> usize {
150                $l
151            }
152            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
153            fn iter(&self) -> core::slice::Iter<$t> {
154                self.0.iter()
155            }
156
157            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
158            fn update_slice<A: SeqTrait<$t>>(
159                mut self,
160                start_out: usize,
161                v: &A,
162                start_in: usize,
163                len: usize,
164            ) -> Self {
165                debug_assert!(self.len() >= start_out + len);
166                debug_assert!(v.len() >= start_in + len);
167                for i in 0..len {
168                    self[start_out + i] = v[start_in + i];
169                }
170                self
171            }
172
173            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
174            fn update<A: SeqTrait<$t>>(self, start: usize, v: &A) -> Self {
175                let len = v.len();
176                self.update_slice(start, v, 0, len)
177            }
178
179            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
180            fn update_start<A: SeqTrait<$t>>(self, v: &A) -> Self {
181                let len = v.len();
182                self.update_slice(0, v, 0, len)
183            }
184        }
185
186        impl Index<usize> for $name {
187            type Output = $t;
188            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
189            fn index(&self, i: usize) -> &$t {
190                &self.0[i]
191            }
192        }
193        impl IndexMut<usize> for $name {
194            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
195            fn index_mut(&mut self, i: usize) -> &mut $t {
196                &mut self.0[i]
197            }
198        }
199
200        impl Index<u8> for $name {
201            type Output = $t;
202            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
203            fn index(&self, i: u8) -> &$t {
204                &self.0[i as usize]
205            }
206        }
207        impl IndexMut<u8> for $name {
208            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
209            fn index_mut(&mut self, i: u8) -> &mut $t {
210                &mut self.0[i as usize]
211            }
212        }
213        impl Index<u32> for $name {
214            type Output = $t;
215            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
216            fn index(&self, i: u32) -> &$t {
217                &self.0[i as usize]
218            }
219        }
220        impl IndexMut<u32> for $name {
221            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
222            fn index_mut(&mut self, i: u32) -> &mut $t {
223                &mut self.0[i as usize]
224            }
225        }
226        impl Index<i32> for $name {
227            type Output = $t;
228            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
229            fn index(&self, i: i32) -> &$t {
230                &self.0[i as usize]
231            }
232        }
233        impl IndexMut<i32> for $name {
234            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
235            fn index_mut(&mut self, i: i32) -> &mut $t {
236                &mut self.0[i as usize]
237            }
238        }
239        impl Index<RangeFull> for $name {
240            type Output = [$t];
241            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
242            fn index(&self, r: RangeFull) -> &[$t] {
243                &self.0[r]
244            }
245        }
246        impl $name {
247            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
248            pub fn from_vec(x: Vec<$t>) -> $name {
249                debug_assert_eq!(x.len(), $l);
250                let mut tmp = [<$t>::default(); $l];
251                for (i, e) in x.iter().enumerate() {
252                    tmp[i] = *e;
253                }
254                $name(tmp.clone())
255            }
256
257            // We can't use the [From] trait here because otherwise it would conflict with
258            // the From<T> for T core implementation, as the array also implements the [SeqTrait].
259            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
260            pub fn from_seq<T: SeqTrait<$t>>(x: &T) -> $name {
261                debug_assert_eq!(x.len(), $l);
262                let mut out = $name::new();
263                for i in 0..x.len() {
264                    out[i] = x[i];
265                }
266                out
267            }
268        }
269
270        impl $name {
271            fn hex_string_to_vec(s: &str) -> Vec<$t> {
272                debug_assert!(s.len() % core::mem::size_of::<$t>() == 0);
273                let b: Result<Vec<$t>, ParseIntError> = (0..s.len())
274                    .step_by(2)
275                    .map(|i| u8::from_str_radix(&s[i..i + 2], 16).map(<$t>::from))
276                    .collect();
277                b.expect("Error parsing hex string")
278            }
279
280            /// Read hex string to Bytes.
281            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
282            pub fn from_hex(s: &str) -> $name {
283                let v = $name::hex_string_to_vec(s);
284                let mut o = $name::new();
285                debug_assert!(v.len() == $l);
286                for i in 0..$l {
287                    o[i] = v[i]
288                }
289                o
290            }
291        }
292    };
293}
294
295#[macro_export]
296macro_rules! generic_array {
297    ($name:ident,$l:expr) => {
298        /// Fixed length byte array.
299        // Because Rust requires fixed length arrays to have a known size at
300        // compile time there's no generic fixed length byte array here.
301        // Use this to define the fixed length byte arrays needed in your code.
302        #[allow(non_camel_case_types)]
303        #[derive(Clone, Copy)]
304        pub struct $name<T>(pub [T; $l]);
305
306        impl<T: Numeric + Copy> $name<T> {
307            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
308            pub fn new() -> Self {
309                Self([<T>::default(); $l])
310            }
311
312            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
313            pub fn length() -> usize {
314                $l
315            }
316
317            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
318            pub fn from_array(v: [T; $l]) -> Self {
319                Self(v.clone())
320            }
321
322            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
323            pub fn from_native_slice(v: &[T]) -> Self {
324                debug_assert!(v.len() <= $l);
325                let mut tmp = [<T>::default(); $l];
326                for i in 0..v.len() {
327                    tmp[i] = v[i];
328                }
329                Self(tmp.clone())
330            }
331        }
332
333        impl<T: Numeric + Copy> $name<T> {
334            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
335            pub fn from_slice<A: SeqTrait<T>>(input: &A, start: usize, len: usize) -> Self {
336                let mut a = Self::new();
337                debug_assert!(len <= a.len());
338                a = a.update_slice(0, input, start, len);
339                a
340            }
341
342            #[cfg_attr(feature = "use_attributes", in_hacspec)]
343            pub fn concat<A: SeqTrait<T>>(&self, next: &A) -> Seq<T> {
344                let mut out = Seq::new(self.len() + next.len());
345                out = out.update_start(self);
346                out = out.update_slice(self.len(), next, 0, next.len());
347                out
348            }
349
350            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
351            pub fn from_slice_range<A: SeqTrait<T>>(input: &A, r: Range<usize>) -> Self {
352                Self::from_slice(input, r.start, r.end - r.start)
353            }
354
355            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
356            pub fn slice(&self, start_out: usize, len: usize) -> Seq<T> {
357                Seq::from_slice(self, start_out, len)
358            }
359
360            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
361            pub fn slice_range(&self, r: Range<usize>) -> Seq<T> {
362                self.slice(r.start, r.end - r.start)
363            }
364
365            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
366            pub fn num_chunks(&self, chunk_size: usize) -> usize {
367                (self.len() + chunk_size - 1) / chunk_size
368            }
369
370            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
371            pub fn get_chunk_len(&self, chunk_size: usize, chunk_number: usize) -> usize {
372                let idx_start = chunk_size * chunk_number;
373                if idx_start + chunk_size > self.len() {
374                    self.len() - idx_start
375                } else {
376                    chunk_size
377                }
378            }
379
380            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
381            pub fn get_chunk(&self, chunk_size: usize, chunk_number: usize) -> (usize, Seq<T>) {
382                let idx_start = chunk_size * chunk_number;
383                let len = self.get_chunk_len(chunk_size, chunk_number);
384                let out = self.slice(idx_start, len);
385                (len, out)
386            }
387
388            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
389            pub fn set_chunk<A: SeqTrait<T>>(
390                self,
391                chunk_size: usize,
392                chunk_number: usize,
393                input: &A,
394            ) -> Self {
395                let idx_start = chunk_size * chunk_number;
396                let len = self.get_chunk_len(chunk_size, chunk_number);
397                debug_assert!(
398                    input.len() == len,
399                    "the chunk length should match the input. got {}, expected {}",
400                    input.len(),
401                    len
402                );
403                self.update_slice(idx_start, input, 0, len)
404            }
405        }
406
407        impl<T: Numeric + Copy> Default for $name<T> {
408            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
409            fn default() -> Self {
410                $name::new()
411            }
412        }
413        impl<T: Numeric + Copy> SeqTrait<T> for $name<T> {
414            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
415            fn create(x: usize) -> Self {
416                assert_eq!(x, $l);
417                Self::new()
418            }
419
420            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
421            fn len(&self) -> usize {
422                $l
423            }
424            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
425            fn iter(&self) -> core::slice::Iter<T> {
426                self.0.iter()
427            }
428
429            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
430            fn update_slice<A: SeqTrait<T>>(
431                mut self,
432                start_out: usize,
433                v: &A,
434                start_in: usize,
435                len: usize,
436            ) -> Self {
437                debug_assert!(self.len() >= start_out + len);
438                debug_assert!(v.len() >= start_in + len);
439                for i in 0..len {
440                    self[start_out + i] = v[start_in + i];
441                }
442                self
443            }
444
445            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
446            fn update<A: SeqTrait<T>>(self, start: usize, v: &A) -> Self {
447                let len = v.len();
448                self.update_slice(start, v, 0, len)
449            }
450
451            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
452            fn update_start<A: SeqTrait<T>>(self, v: &A) -> Self {
453                let len = v.len();
454                self.update_slice(0, v, 0, len)
455            }
456        }
457
458        impl<T: Numeric + Copy> Index<usize> for $name<T> {
459            type Output = T;
460            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
461            fn index(&self, i: usize) -> &T {
462                &self.0[i]
463            }
464        }
465        impl<T: Numeric + Copy> IndexMut<usize> for $name<T> {
466            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
467            fn index_mut(&mut self, i: usize) -> &mut T {
468                &mut self.0[i]
469            }
470        }
471
472        impl<T: Numeric + Copy> Index<u8> for $name<T> {
473            type Output = T;
474            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
475            fn index(&self, i: u8) -> &T {
476                &self.0[i as usize]
477            }
478        }
479        impl<T: Numeric + Copy> IndexMut<u8> for $name<T> {
480            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
481            fn index_mut(&mut self, i: u8) -> &mut T {
482                &mut self.0[i as usize]
483            }
484        }
485        impl<T: Numeric + Copy> Index<u32> for $name<T> {
486            type Output = T;
487            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
488            fn index(&self, i: u32) -> &T {
489                &self.0[i as usize]
490            }
491        }
492        impl<T: Numeric + Copy> IndexMut<u32> for $name<T> {
493            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
494            fn index_mut(&mut self, i: u32) -> &mut T {
495                &mut self.0[i as usize]
496            }
497        }
498        impl<T: Numeric + Copy> Index<i32> for $name<T> {
499            type Output = T;
500            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
501            fn index(&self, i: i32) -> &T {
502                &self.0[i as usize]
503            }
504        }
505        impl<T: Numeric + Copy> IndexMut<i32> for $name<T> {
506            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
507            fn index_mut(&mut self, i: i32) -> &mut T {
508                &mut self.0[i as usize]
509            }
510        }
511        impl<T: Numeric + Copy> Index<RangeFull> for $name<T> {
512            type Output = [T];
513            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
514            fn index(&self, r: RangeFull) -> &[T] {
515                &self.0[r]
516            }
517        }
518        impl<T: Numeric + Copy> $name<T> {
519            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
520            pub fn from_vec(x: Vec<T>) -> $name<T> {
521                debug_assert_eq!(x.len(), $l);
522                let mut tmp = [<T>::default(); $l];
523                for (i, e) in x.iter().enumerate() {
524                    tmp[i] = *e;
525                }
526                $name(tmp.clone())
527            }
528
529            // We can't use the [From] trait here because otherwise it would conflict with
530            // the From<T> for T core implementation, as the array also implements the [SeqTrait].
531            #[cfg_attr(feature = "use_attributes", in_hacspec($name))]
532            pub fn from_seq<U: SeqTrait<T>>(x: &U) -> $name<T> {
533                debug_assert_eq!(x.len(), $l);
534                let mut out = $name::new();
535                for i in 0..x.len() {
536                    out[i] = x[i];
537                }
538                out
539            }
540        }
541
542        /// **Warning:** declassifies secret integer types.
543        impl<T: Numeric + Copy> fmt::Debug for $name<T> {
544            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
545            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
546                self.0[..].iter().collect::<Vec<_>>().fmt(f)
547            }
548        }
549    };
550}
551
552#[macro_export]
553#[doc(hidden)]
554/// This creates arrays for secret integers, i.e. `$t` is the secret integer
555/// type and `$tbase` is the according Rust type.
556macro_rules! _secret_array {
557    ($name:ident,$l:expr,$t:ty, $tbase:ty) => {
558        _array_base!($name, $l, $t);
559
560        /// **Warning:** declassifies secret integer types.
561        impl fmt::Debug for $name {
562            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
563            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
564                self.0[..]
565                    .iter()
566                    .map(|x| <$t>::declassify(*x))
567                    .collect::<Vec<_>>()
568                    .fmt(f)
569            }
570        }
571        /// **Warning:** declassifies secret integer types.
572        impl $name {
573            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
574            pub fn declassify_eq(&self, other: &Self) -> bool {
575                self.0[..]
576                    .iter()
577                    .map(|x| <$t>::declassify(*x))
578                    .collect::<Vec<_>>()
579                    == other.0[..]
580                        .iter()
581                        .map(|x| <$t>::declassify(*x))
582                        .collect::<Vec<_>>()
583            }
584        }
585        impl $name {
586            #[cfg_attr(feature = "use_attributes", unsafe_hacspec)]
587            pub fn to_be_bytes(&self) -> Seq<U8> {
588                const FACTOR: usize = core::mem::size_of::<$t>();
589                let mut out: Seq<U8> = Seq::new($l * FACTOR);
590                for i in 0..$l {
591                    let tmp: $t = self[i];
592                    let tmp = <$t>::to_be_bytes(&[tmp]);
593                    for j in 0..FACTOR {
594                        out[i * FACTOR + j] = tmp[j];
595                    }
596                }
597                out
598            }
599
600            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
601            pub fn to_le_bytes(&self) -> Seq<U8> {
602                const FACTOR: usize = core::mem::size_of::<$t>();
603                let mut out: Seq<U8> = Seq::new($l * FACTOR);
604                for i in 0..$l {
605                    let tmp: $t = self[i];
606                    let tmp = <$t>::to_le_bytes(&[tmp]);
607                    for j in 0..FACTOR {
608                        out[i * FACTOR + j] = tmp[j];
609                    }
610                }
611                out
612            }
613        }
614        impl $name {
615            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
616            pub fn from_public_slice(v: &[$tbase]) -> $name {
617                debug_assert!(v.len() == $l);
618                Self::from_vec(
619                    v[..]
620                        .iter()
621                        .map(|x| <$t>::classify(*x))
622                        .collect::<Vec<$t>>(),
623                )
624            }
625
626            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
627            pub fn to_public_array(&self) -> [$tbase; $l] {
628                let mut out = [0; $l];
629                for (x, o) in self.0.iter().zip(out.iter_mut()) {
630                    *o = <$t>::declassify(*x);
631                }
632                out
633            }
634
635            /// Create an array from a regular Rust array.
636            ///
637            /// # Examples
638            ///
639            /// ```
640            /// use hacspec_lib::prelude::*;
641            ///
642            /// bytes!(Block, 5);
643            /// let b = Block::from_public_array([1, 2, 3, 4, 5]);
644            /// ```
645            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
646            pub fn from_public_array(v: [$tbase; $l]) -> $name {
647                debug_assert!(v.len() == $l);
648                Self::from_vec(
649                    v[..]
650                        .iter()
651                        .map(|x| <$t>::classify(*x))
652                        .collect::<Vec<$t>>(),
653                )
654            }
655        }
656    };
657}
658
659#[macro_export]
660#[doc(hidden)]
661macro_rules! _public_array {
662    ($name:ident,$l:expr,$t:ty) => {
663        _array_base!($name, $l, $t);
664
665        impl $name {
666            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
667            pub fn into_le_bytes(self) -> Seq<u8> {
668                const FACTOR: usize = core::mem::size_of::<$t>();
669                let mut out: Seq<u8> = Seq::new($l * FACTOR);
670                for i in 0..$l {
671                    let tmp = <$t>::to_le_bytes(self[i]);
672                    for j in 0..FACTOR {
673                        out[i * FACTOR + j] = tmp[j];
674                    }
675                }
676                out
677            }
678        }
679
680        impl fmt::Debug for $name {
681            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
682            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
683                self.0[..].fmt(f)
684            }
685        }
686        impl PartialEq for $name {
687            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
688            fn eq(&self, other: &Self) -> bool {
689                self.0[..] == other.0[..]
690            }
691        }
692    };
693}
694
695#[macro_export]
696#[doc(hidden)]
697macro_rules! _implement_secret_u8_array {
698    ($name:ident, $l:expr) => {
699        _secret_array!($name, $l, U8, u8);
700        _implement_numeric_unsigned_secret!($name, U8);
701
702        impl $name {
703            #[allow(non_snake_case)]
704            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
705            pub fn to_be_U32s(&self) -> Seq<U32> {
706                let mut out = Seq::new($l / 4);
707                for (i, block) in self.0.chunks(4).enumerate() {
708                    debug_assert!(block.len() == 4);
709                    out[i] = U32_from_be_bytes(U32Word::from_native_slice(block));
710                }
711                out
712            }
713            #[allow(non_snake_case)]
714            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
715            pub fn to_le_U32s(&self) -> Seq<U32> {
716                let mut out = Seq::new($l / 4);
717                for (i, block) in self.0.chunks(4).enumerate() {
718                    debug_assert!(block.len() == 4);
719                    out[i] = U32_from_le_bytes(U32Word::from_native_slice(block));
720                }
721                out
722            }
723            #[allow(non_snake_case)]
724            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
725            pub fn to_be_U64s(&self) -> Seq<U64> {
726                let mut out = Seq::new($l / 8);
727                for (i, block) in self.0.chunks(8).enumerate() {
728                    debug_assert!(block.len() == 8);
729                    out[i] = U64_from_be_bytes(U64Word::from_native_slice(block));
730                }
731                out
732            }
733            #[allow(non_snake_case)]
734            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
735            pub fn to_le_U64s(&self) -> Seq<U64> {
736                let mut out = Seq::new($l / 8);
737                for (i, block) in self.0.chunks(8).enumerate() {
738                    debug_assert!(block.len() == 8);
739                    out[i] = U64_from_le_bytes(U64Word::from_native_slice(block));
740                }
741                out
742            }
743            #[allow(non_snake_case)]
744            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
745            pub fn to_U128s_be(&self) -> Seq<U128> {
746                let mut out = Seq::new($l / 16);
747                for (i, block) in self.0.chunks(16).enumerate() {
748                    debug_assert!(block.len() == 16);
749                    out[i] = U128_from_be_bytes(U128Word::from_native_slice(block));
750                }
751                out
752            }
753            #[allow(non_snake_case)]
754            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
755            pub fn to_U128s_le(&self) -> Seq<U128> {
756                let mut out = Seq::new($l / 16);
757                for (i, block) in self.0.chunks(16).enumerate() {
758                    debug_assert!(block.len() == 16);
759                    out[i] = U128_from_le_bytes(U128Word::from_native_slice(block));
760                }
761                out
762            }
763            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
764            pub fn to_hex(&self) -> String {
765                let strs: Vec<String> = self.0.iter().map(|b| format!("{:02x}", b)).collect();
766                strs.join("")
767            }
768        }
769    };
770}
771
772#[macro_export]
773#[doc(hidden)]
774macro_rules! _implement_public_u8_array {
775    ($name:ident, $l:expr) => {
776        _public_array!($name, $l, u8);
777        _implement_numeric_unsigned_public!($name);
778
779        impl $name {
780            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
781            pub fn to_be_u32s(&self) -> Seq<u32> {
782                let mut out = Seq::new($l / 4);
783                for (i, block) in self.0.chunks(4).enumerate() {
784                    debug_assert!(block.len() == 4);
785                    out[i] = u32::from_be_bytes(to_array(block));
786                }
787                out
788            }
789            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
790            pub fn to_le_u32s(&self) -> Seq<u32> {
791                let mut out = Seq::new($l / 4);
792                for (i, block) in self.0.chunks(4).enumerate() {
793                    debug_assert!(block.len() == 4);
794                    out[i] = u32::from_le_bytes(to_array(block));
795                }
796                out
797            }
798            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
799            pub fn to_be_u64s(&self) -> Seq<u64> {
800                let mut out = Seq::new($l / 8);
801                for (i, block) in self.0.chunks(8).enumerate() {
802                    debug_assert!(block.len() == 8);
803                    out[i] = u64::from_be_bytes(to_array(block));
804                }
805                out
806            }
807            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
808            pub fn to_le_u64s(&self) -> Seq<u64> {
809                let mut out = Seq::new($l / 8);
810                for (i, block) in self.0.chunks(8).enumerate() {
811                    debug_assert!(block.len() == 8);
812                    out[i] = u64::from_le_bytes(to_array(block));
813                }
814                out
815            }
816            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
817            pub fn to_u128s_be(&self) -> Seq<u128> {
818                let mut out = Seq::new($l / 16);
819                for (i, block) in self.0.chunks(16).enumerate() {
820                    debug_assert!(block.len() == 16);
821                    out[i] = u128::from_be_bytes(to_array(block));
822                }
823                out
824            }
825            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
826            pub fn to_u128s_le(&self) -> Seq<u128> {
827                let mut out = Seq::new($l / 16);
828                for (i, block) in self.0.chunks(16).enumerate() {
829                    debug_assert!(block.len() == 16);
830                    out[i] = u128::from_le_bytes(to_array(block));
831                }
832                out
833            }
834            #[cfg_attr(feature = "use_attributes", not_hacspec($name))]
835            pub fn to_hex(&self) -> String {
836                let strs: Vec<String> = self.0.iter().map(|b| format!("{:02x}", b)).collect();
837                strs.join("")
838            }
839        }
840    };
841}
842
843// The following are the macros intended for use from the outside.
844
845#[macro_export]
846/// Create a new array with the given name, length, and type.
847macro_rules! array {
848    ($name:ident, $l:expr, U8) => {
849        _implement_secret_u8_array!($name, $l);
850    };
851    ($name:ident, $l:expr, U8, $idx: ident) => {
852        _implement_secret_u8_array!($name, $l);
853        pub type $idx = usize;
854    };
855    ($name:ident, $l:expr, U16) => {
856        _secret_array!($name, $l, U16, u16);
857        _implement_numeric_unsigned_secret!($name, U16);
858    };
859    ($name:ident, $l:expr, U16, type_for_indexes: $idx: ident) => {
860        _secret_array!($name, $l, U16, u16);
861        _implement_numeric_unsigned_secret!($name, U16);
862        pub type $idx = usize;
863    };
864    ($name:ident, $l:expr, U32) => {
865        _secret_array!($name, $l, U32, u32);
866        _implement_numeric_unsigned_secret!($name, U32);
867    };
868    ($name:ident, $l:expr, U32, type_for_indexes: $idx: ident) => {
869        _secret_array!($name, $l, U32, u32);
870        _implement_numeric_unsigned_secret!($name, U32);
871        pub type $idx = usize;
872    };
873    ($name:ident, $l:expr, U64) => {
874        _secret_array!($name, $l, U64, u64);
875        _implement_numeric_unsigned_secret!($name, U64);
876    };
877    ($name:ident, $l:expr, U64, type_for_indexes: $idx: ident) => {
878        _secret_array!($name, $l, U64, u64);
879        _implement_numeric_unsigned_secret!($name, U64);
880        pub type $idx = usize;
881    };
882    ($name:ident, $l:expr, U128) => {
883        _secret_array!($name, $l, U128, u128);
884        _implement_numeric_unsigned_secret!($name, U128);
885    };
886    ($name:ident, $l:expr, U128, type_for_indexes: $idx: ident) => {
887        _secret_array!($name, $l, U128, u128);
888        _implement_numeric_unsigned_secret!($name, U128);
889        pub type $idx = usize;
890    };
891    ($name:ident, $l:expr, u8) => {
892        _implement_public_u8_array!($name, $l);
893    };
894    ($name:ident, $l:expr, u8, type_for_indexes: $idx: ident) => {
895        _implement_public_u8_array!($name, $l);
896        pub type $idx = usize;
897    };
898    ($name:ident, $l:expr, u16) => {
899        _public_array!($name, $l, u16);
900        _implement_numeric_unsigned_public!($name);
901    };
902    ($name:ident, $l:expr, u16, type_for_indexes: $idx: ident) => {
903        _public_array!($name, $l, u16);
904        _implement_numeric_unsigned_public!($name);
905        pub type $idx = usize;
906    };
907    ($name:ident, $l:expr, u32) => {
908        _public_array!($name, $l, u32);
909        _implement_numeric_unsigned_public!($name);
910    };
911    ($name:ident, $l:expr, u32, type_for_indexes: $idx: ident) => {
912        _public_array!($name, $l, u32);
913        _implement_numeric_unsigned_public!($name);
914        pub type $idx = usize;
915    };
916    ($name:ident, $l:expr, u64) => {
917        _public_array!($name, $l, u64);
918        _implement_numeric_unsigned_public!($name);
919    };
920    ($name:ident, $l:expr, u64, type_for_indexes: $idx: ident) => {
921        _public_array!($name, $l, u64);
922        _implement_numeric_unsigned_public!($name);
923        pub type $idx = usize;
924    };
925    ($name:ident, $l:expr, u128) => {
926        _public_array!($name, $l, u128);
927        _implement_numeric_unsigned_public!($name);
928    };
929    ($name:ident, $l:expr, u128, type_for_indexes: $idx: ident) => {
930        _public_array!($name, $l, u128);
931        _implement_numeric_unsigned_public!($name);
932        pub type $idx = usize;
933    };
934    ($name:ident, $l:expr, $t:ty) => {
935        _public_array!($name, $l, $t);
936    };
937    ($name:ident, $l:expr, $t:ty, type_for_indexes: $idx: ident) => {
938        _public_array!($name, $l, $t);
939        pub type $idx = usize;
940    };
941}
942
943#[macro_export]
944/// Convenience function to create a new byte array (of type `U8`) with the given
945/// name and length.
946macro_rules! bytes {
947    ($name:ident, $l:expr) => {
948        array!($name, $l, U8);
949    };
950}
951
952#[macro_export]
953/// Convenience function to create a new public byte array (of type `u8`) with
954/// the given name and length.
955macro_rules! public_bytes {
956    ($name:ident, $l:expr) => {
957        array!($name, $l, u8);
958    };
959}
960
961#[macro_export]
962macro_rules! secret_array {
963    ( $int_type: ident, [ $( $x:expr ),+ ] ) => {
964        [
965            $(
966                $int_type($x)
967            ),+
968        ]
969    }
970}
971
972#[macro_export]
973macro_rules! secret_bytes {
974    ([ $( $x:expr ),+ ] ) => {
975        secret_array!(U8, [$($x),+])
976    }
977}
978
979#[macro_export]
980macro_rules! assert_secret_array_eq {
981    ( $a1: expr, $a2: expr, $si: ident) => {
982        assert_eq!(
983            $a1.iter().map(|x| $si::declassify(*x)).collect::<Vec<_>>(),
984            $a2.iter().map(|x| $si::declassify(*x)).collect::<Vec<_>>()
985        );
986    };
987}
988
989#[macro_export]
990macro_rules! assert_bytes_eq {
991    ( $a1: expr, $a2: expr) => {
992        assert_secret_array_eq!($a1, $a2, U8)
993    };
994}
995
996#[macro_export]
997macro_rules! both_arrays {
998    ($public_name:ident, $name:ident, $l:expr, $t:ty, $tbase:ty) => {
999        _secret_array!($name, $l, $t, $tbase);
1000        _public_array!($public_name, $l, $tbase);
1001
1002        impl $name {
1003            /// Conversion function between public and secret array versions.
1004            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
1005            pub fn from_public(v: $public_name) -> $name {
1006                Self::from_vec(
1007                    v[..]
1008                        .iter()
1009                        .map(|x| <$t>::classify(*x))
1010                        .collect::<Vec<$t>>(),
1011                )
1012            }
1013        }
1014
1015        impl $public_name {
1016            /// *Warning:* this function declassifies secret integers!
1017            #[cfg_attr(feature = "use_attributes", unsafe_hacspec($name))]
1018            pub fn from_secret_declassify(v: $name) -> $public_name {
1019                Self::from_vec(
1020                    v[..]
1021                        .iter()
1022                        .map(|x| <$t>::declassify(*x))
1023                        .collect::<Vec<$tbase>>(),
1024                )
1025            }
1026        }
1027    };
1028}
1029
1030#[macro_export]
1031macro_rules! both_bytes {
1032    ($public_name:ident, $name:ident, $l:expr) => {
1033        both_arrays!($public_name, $name, $l, U8, u8);
1034    };
1035}