1use alloc::{string::String, vec::Vec};
4#[cfg(not(all(target_family = "wasm", miden)))]
5use core::fmt::Display;
6use core::{
7 cmp::Ordering,
8 hash::{Hash, Hasher},
9 mem::size_of,
10 ops::{Deref, DerefMut, Index, IndexMut, Range},
11 slice,
12};
13
14#[cfg(not(all(target_family = "wasm", miden)))]
15use miden_serde_utils::{
16 ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable,
17};
18#[cfg(not(all(target_family = "wasm", miden)))]
19use p3_field::integers::QuotientMap;
20#[cfg(not(all(target_family = "wasm", miden)))]
21use rand::{
22 Rng,
23 distr::{Distribution, StandardUniform},
24};
25use thiserror::Error;
26
27use super::Felt;
28use crate::utils::bytes_to_hex_string;
29
30#[cfg(test)]
31mod tests;
32
33#[derive(Default, Copy, Clone, Eq, PartialEq)]
41#[repr(C)]
42#[cfg_attr(all(target_family = "wasm", miden), repr(align(16)))]
43pub struct Word {
44 pub a: Felt,
46 pub b: Felt,
47 pub c: Felt,
48 pub d: Felt,
49 }
59
60#[cfg(not(all(target_family = "wasm", miden)))]
61impl Distribution<Word> for StandardUniform {
62 #[inline]
63 fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Word {
64 Word::new(core::array::from_fn(|_| self.sample(rng)))
65 }
66}
67
68const _: () = {
71 assert!(Word::NUM_ELEMENTS == 4, "Word::NUM_ELEMENTS is assumed to be 4");
72 assert!(Word::SERIALIZED_SIZE == 32, "Word::SERIALIZED_SIZE is assumed to be 32");
73 assert!(size_of::<Word>() == Word::NUM_ELEMENTS * size_of::<Felt>());
74 assert!(core::mem::offset_of!(Word, a) == 0);
75 assert!(core::mem::offset_of!(Word, b) == size_of::<Felt>());
76 assert!(core::mem::offset_of!(Word, c) == 2 * size_of::<Felt>());
77 assert!(core::mem::offset_of!(Word, d) == 3 * size_of::<Felt>());
78};
79
80impl core::fmt::Debug for Word {
81 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
82 f.debug_tuple("Word").field(&self.into_elements()).finish()
83 }
84}
85
86impl Word {
87 pub const NUM_ELEMENTS: usize = 4;
89
90 pub const SERIALIZED_SIZE: usize = 32;
92
93 pub const fn new(value: [Felt; Self::NUM_ELEMENTS]) -> Self {
95 let [a, b, c, d] = value;
96 Self { a, b, c, d }
97 }
98
99 pub const fn into_elements(self) -> [Felt; Self::NUM_ELEMENTS] {
101 [self.a, self.b, self.c, self.d]
102 }
103
104 fn as_elements_array(&self) -> &[Felt; Self::NUM_ELEMENTS] {
110 unsafe { &*(&self.a as *const Felt as *const [Felt; Self::NUM_ELEMENTS]) }
111 }
112
113 fn as_elements_array_mut(&mut self) -> &mut [Felt; Self::NUM_ELEMENTS] {
119 unsafe { &mut *(&mut self.a as *mut Felt as *mut [Felt; Self::NUM_ELEMENTS]) }
120 }
121
122 #[cfg(not(all(target_family = "wasm", miden)))]
146 pub const fn parse(hex: &str) -> Result<Self, &'static str> {
147 const fn parse_hex_digit(digit: u8) -> Result<u8, &'static str> {
148 match digit {
149 b'0'..=b'9' => Ok(digit - b'0'),
150 b'A'..=b'F' => Ok(digit - b'A' + 0x0a),
151 b'a'..=b'f' => Ok(digit - b'a' + 0x0a),
152 _ => Err("Invalid hex character"),
153 }
154 }
155 let hex_bytes = match hex.as_bytes() {
157 [b'0', b'x', rest @ ..] => rest,
158 _ => return Err("Hex string must have a \"0x\" prefix"),
159 };
160
161 if hex_bytes.len() > 64 {
162 return Err("Hex string has more than 64 characters");
163 }
164
165 let mut felts = [0u64; 4];
166 let mut i = 0;
167 while i < hex_bytes.len() {
168 let hex_digit = match parse_hex_digit(hex_bytes[i]) {
169 Ok(v) => v as u64,
172 Err(e) => return Err(e),
173 };
174
175 let inibble = if i.is_multiple_of(2) {
178 (i + 1) % 16
179 } else {
180 (i - 1) % 16
181 };
182
183 let value = hex_digit << (inibble * 4);
184 felts[i / 2 / 8] += value;
185
186 i += 1;
187 }
188
189 let mut idx = 0;
192 while idx < felts.len() {
193 if felts[idx] >= Felt::ORDER {
194 return Err("Felt overflow");
195 }
196 idx += 1;
197 }
198
199 Ok(Self::new([
200 Felt::new_unchecked(felts[0]),
201 Felt::new_unchecked(felts[1]),
202 Felt::new_unchecked(felts[2]),
203 Felt::new_unchecked(felts[3]),
204 ]))
205 }
206
207 pub const fn empty() -> Self {
209 Self::new([Felt::ZERO; Self::NUM_ELEMENTS])
210 }
211
212 pub fn is_empty(&self) -> bool {
214 let elements = self.as_elements_array();
215 elements[0] == Felt::ZERO
216 && elements[1] == Felt::ZERO
217 && elements[2] == Felt::ZERO
218 && elements[3] == Felt::ZERO
219 }
220
221 pub fn as_elements(&self) -> &[Felt] {
223 self.as_elements_array()
224 }
225
226 pub fn as_bytes(&self) -> [u8; Self::SERIALIZED_SIZE] {
228 let mut result = [0; Self::SERIALIZED_SIZE];
229
230 let elements = self.as_elements_array();
231 result[..8].copy_from_slice(&elements[0].as_canonical_u64().to_le_bytes());
232 result[8..16].copy_from_slice(&elements[1].as_canonical_u64().to_le_bytes());
233 result[16..24].copy_from_slice(&elements[2].as_canonical_u64().to_le_bytes());
234 result[24..].copy_from_slice(&elements[3].as_canonical_u64().to_le_bytes());
235
236 result
237 }
238
239 pub fn words_as_elements_iter<'a, I>(words: I) -> impl Iterator<Item = &'a Felt>
241 where
242 I: Iterator<Item = &'a Self>,
243 {
244 words.flat_map(|d| d.as_elements().iter())
245 }
246
247 pub fn words_as_elements(words: &[Self]) -> &[Felt] {
249 let len = words.len() * Self::NUM_ELEMENTS;
250 unsafe { slice::from_raw_parts(words.as_ptr() as *const Felt, len) }
251 }
252
253 pub fn to_hex(&self) -> String {
255 bytes_to_hex_string(self.as_bytes())
256 }
257
258 pub fn to_vec(&self) -> Vec<Felt> {
260 self.as_elements().to_vec()
261 }
262
263 pub fn reversed(&self) -> Self {
265 Word {
266 a: self.d,
267 b: self.c,
268 c: self.b,
269 d: self.a,
270 }
271 }
272}
273
274impl Hash for Word {
275 fn hash<H: Hasher>(&self, state: &mut H) {
276 state.write(&self.as_bytes());
277 }
278}
279
280impl Deref for Word {
281 type Target = [Felt; Word::NUM_ELEMENTS];
282
283 fn deref(&self) -> &Self::Target {
284 self.as_elements_array()
285 }
286}
287
288impl DerefMut for Word {
289 fn deref_mut(&mut self) -> &mut Self::Target {
290 self.as_elements_array_mut()
291 }
292}
293
294impl Index<usize> for Word {
295 type Output = Felt;
296
297 fn index(&self, index: usize) -> &Self::Output {
298 &self.as_elements_array()[index]
299 }
300}
301
302impl IndexMut<usize> for Word {
303 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
304 &mut self.as_elements_array_mut()[index]
305 }
306}
307
308impl Index<Range<usize>> for Word {
309 type Output = [Felt];
310
311 fn index(&self, index: Range<usize>) -> &Self::Output {
312 &self.as_elements_array()[index]
313 }
314}
315
316impl IndexMut<Range<usize>> for Word {
317 fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
318 &mut self.as_elements_array_mut()[index]
319 }
320}
321
322impl Ord for Word {
323 fn cmp(&self, other: &Self) -> Ordering {
324 for (felt0, felt1) in self
338 .iter()
339 .rev()
340 .map(Felt::as_canonical_u64)
341 .zip(other.iter().rev().map(Felt::as_canonical_u64))
342 {
343 let ordering = felt0.cmp(&felt1);
344 if let Ordering::Less | Ordering::Greater = ordering {
345 return ordering;
346 }
347 }
348
349 Ordering::Equal
350 }
351}
352
353impl PartialOrd for Word {
354 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
355 Some(self.cmp(other))
356 }
357}
358
359#[cfg(not(all(target_family = "wasm", miden)))]
360impl Display for Word {
361 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
362 write!(f, "{}", self.to_hex())
363 }
364}
365
366#[derive(Debug, Error)]
371pub enum WordError {
372 #[error("hex encoded values of a word are invalid")]
374 HexParse(#[from] crate::utils::HexParseError),
375 #[error("failed to convert to field element: {0}")]
377 InvalidFieldElement(String),
378 #[error("invalid input length: expected {1} {0}, but received {2}")]
380 InvalidInputLength(&'static str, usize, usize),
381 #[error("failed to convert the word's field elements to type {0}")]
383 TypeConversion(&'static str),
384}
385
386impl TryFrom<&Word> for [bool; Word::NUM_ELEMENTS] {
387 type Error = WordError;
388
389 fn try_from(value: &Word) -> Result<Self, Self::Error> {
390 (*value).try_into()
391 }
392}
393
394impl TryFrom<Word> for [bool; Word::NUM_ELEMENTS] {
395 type Error = WordError;
396
397 fn try_from(value: Word) -> Result<Self, Self::Error> {
398 fn to_bool(v: u64) -> Option<bool> {
399 if v <= 1 { Some(v == 1) } else { None }
400 }
401
402 let [a, b, c, d] = value.into_elements();
403 Ok([
404 to_bool(a.as_canonical_u64()).ok_or(WordError::TypeConversion("bool"))?,
405 to_bool(b.as_canonical_u64()).ok_or(WordError::TypeConversion("bool"))?,
406 to_bool(c.as_canonical_u64()).ok_or(WordError::TypeConversion("bool"))?,
407 to_bool(d.as_canonical_u64()).ok_or(WordError::TypeConversion("bool"))?,
408 ])
409 }
410}
411
412impl TryFrom<&Word> for [u8; Word::NUM_ELEMENTS] {
413 type Error = WordError;
414
415 fn try_from(value: &Word) -> Result<Self, Self::Error> {
416 (*value).try_into()
417 }
418}
419
420impl TryFrom<Word> for [u8; Word::NUM_ELEMENTS] {
421 type Error = WordError;
422
423 fn try_from(value: Word) -> Result<Self, Self::Error> {
424 let [a, b, c, d] = value.into_elements();
425 Ok([
426 a.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u8"))?,
427 b.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u8"))?,
428 c.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u8"))?,
429 d.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u8"))?,
430 ])
431 }
432}
433
434impl TryFrom<&Word> for [u16; Word::NUM_ELEMENTS] {
435 type Error = WordError;
436
437 fn try_from(value: &Word) -> Result<Self, Self::Error> {
438 (*value).try_into()
439 }
440}
441
442impl TryFrom<Word> for [u16; Word::NUM_ELEMENTS] {
443 type Error = WordError;
444
445 fn try_from(value: Word) -> Result<Self, Self::Error> {
446 let [a, b, c, d] = value.into_elements();
447 Ok([
448 a.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u16"))?,
449 b.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u16"))?,
450 c.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u16"))?,
451 d.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u16"))?,
452 ])
453 }
454}
455
456impl TryFrom<&Word> for [u32; Word::NUM_ELEMENTS] {
457 type Error = WordError;
458
459 fn try_from(value: &Word) -> Result<Self, Self::Error> {
460 (*value).try_into()
461 }
462}
463
464impl TryFrom<Word> for [u32; Word::NUM_ELEMENTS] {
465 type Error = WordError;
466
467 fn try_from(value: Word) -> Result<Self, Self::Error> {
468 let [a, b, c, d] = value.into_elements();
469 Ok([
470 a.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u32"))?,
471 b.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u32"))?,
472 c.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u32"))?,
473 d.as_canonical_u64().try_into().map_err(|_| WordError::TypeConversion("u32"))?,
474 ])
475 }
476}
477
478impl From<&Word> for [u64; Word::NUM_ELEMENTS] {
479 fn from(value: &Word) -> Self {
480 (*value).into()
481 }
482}
483
484impl From<Word> for [u64; Word::NUM_ELEMENTS] {
485 fn from(value: Word) -> Self {
486 value.into_elements().map(|felt| felt.as_canonical_u64())
487 }
488}
489
490impl From<&Word> for [Felt; Word::NUM_ELEMENTS] {
491 fn from(value: &Word) -> Self {
492 (*value).into()
493 }
494}
495
496impl From<Word> for [Felt; Word::NUM_ELEMENTS] {
497 fn from(value: Word) -> Self {
498 value.into_elements()
499 }
500}
501
502impl From<&Word> for [u8; Word::SERIALIZED_SIZE] {
503 fn from(value: &Word) -> Self {
504 (*value).into()
505 }
506}
507
508impl From<Word> for [u8; Word::SERIALIZED_SIZE] {
509 fn from(value: Word) -> Self {
510 value.as_bytes()
511 }
512}
513
514#[cfg(not(all(target_family = "wasm", miden)))]
515impl From<&Word> for String {
516 fn from(value: &Word) -> Self {
518 (*value).into()
519 }
520}
521
522#[cfg(not(all(target_family = "wasm", miden)))]
523impl From<Word> for String {
524 fn from(value: Word) -> Self {
526 value.to_hex()
527 }
528}
529
530impl From<&[bool; Word::NUM_ELEMENTS]> for Word {
534 fn from(value: &[bool; Word::NUM_ELEMENTS]) -> Self {
535 (*value).into()
536 }
537}
538
539impl From<[bool; Word::NUM_ELEMENTS]> for Word {
540 fn from(value: [bool; Word::NUM_ELEMENTS]) -> Self {
541 [value[0] as u32, value[1] as u32, value[2] as u32, value[3] as u32].into()
542 }
543}
544
545impl From<&[u8; Word::NUM_ELEMENTS]> for Word {
546 fn from(value: &[u8; Word::NUM_ELEMENTS]) -> Self {
547 (*value).into()
548 }
549}
550
551impl From<[u8; Word::NUM_ELEMENTS]> for Word {
552 fn from(value: [u8; Word::NUM_ELEMENTS]) -> Self {
553 Self::new([
554 Felt::from_u8(value[0]),
555 Felt::from_u8(value[1]),
556 Felt::from_u8(value[2]),
557 Felt::from_u8(value[3]),
558 ])
559 }
560}
561
562impl From<&[u16; Word::NUM_ELEMENTS]> for Word {
563 fn from(value: &[u16; Word::NUM_ELEMENTS]) -> Self {
564 (*value).into()
565 }
566}
567
568impl From<[u16; Word::NUM_ELEMENTS]> for Word {
569 fn from(value: [u16; Word::NUM_ELEMENTS]) -> Self {
570 Self::new([
571 Felt::from_u16(value[0]),
572 Felt::from_u16(value[1]),
573 Felt::from_u16(value[2]),
574 Felt::from_u16(value[3]),
575 ])
576 }
577}
578
579impl From<&[u32; Word::NUM_ELEMENTS]> for Word {
580 fn from(value: &[u32; Word::NUM_ELEMENTS]) -> Self {
581 (*value).into()
582 }
583}
584
585impl From<[u32; Word::NUM_ELEMENTS]> for Word {
586 fn from(value: [u32; Word::NUM_ELEMENTS]) -> Self {
587 Self::new([
588 Felt::from_u32(value[0]),
589 Felt::from_u32(value[1]),
590 Felt::from_u32(value[2]),
591 Felt::from_u32(value[3]),
592 ])
593 }
594}
595
596impl TryFrom<&[u64; Word::NUM_ELEMENTS]> for Word {
597 type Error = WordError;
598
599 fn try_from(value: &[u64; Word::NUM_ELEMENTS]) -> Result<Self, WordError> {
600 (*value).try_into()
601 }
602}
603
604impl TryFrom<[u64; Word::NUM_ELEMENTS]> for Word {
605 type Error = WordError;
606
607 fn try_from(value: [u64; Word::NUM_ELEMENTS]) -> Result<Self, WordError> {
608 let err = || WordError::InvalidFieldElement("value >= field modulus".into());
609 Ok(Self::new([
610 Felt::from_canonical_checked(value[0]).ok_or_else(err)?,
611 Felt::from_canonical_checked(value[1]).ok_or_else(err)?,
612 Felt::from_canonical_checked(value[2]).ok_or_else(err)?,
613 Felt::from_canonical_checked(value[3]).ok_or_else(err)?,
614 ]))
615 }
616}
617
618impl From<&[Felt; Word::NUM_ELEMENTS]> for Word {
619 fn from(value: &[Felt; Word::NUM_ELEMENTS]) -> Self {
620 Self::new(*value)
621 }
622}
623
624impl From<[Felt; Word::NUM_ELEMENTS]> for Word {
625 fn from(value: [Felt; Word::NUM_ELEMENTS]) -> Self {
626 Self::new(value)
627 }
628}
629
630impl TryFrom<&[u8; Word::SERIALIZED_SIZE]> for Word {
631 type Error = WordError;
632
633 fn try_from(value: &[u8; Word::SERIALIZED_SIZE]) -> Result<Self, Self::Error> {
634 (*value).try_into()
635 }
636}
637
638impl TryFrom<[u8; Word::SERIALIZED_SIZE]> for Word {
639 type Error = WordError;
640
641 fn try_from(value: [u8; Word::SERIALIZED_SIZE]) -> Result<Self, Self::Error> {
642 let a = u64::from_le_bytes(value[0..8].try_into().unwrap());
645 let b = u64::from_le_bytes(value[8..16].try_into().unwrap());
646 let c = u64::from_le_bytes(value[16..24].try_into().unwrap());
647 let d = u64::from_le_bytes(value[24..32].try_into().unwrap());
648
649 let err = || WordError::InvalidFieldElement("value >= field modulus".into());
650 let a: Felt = Felt::from_canonical_checked(a).ok_or_else(err)?;
651 let b: Felt = Felt::from_canonical_checked(b).ok_or_else(err)?;
652 let c: Felt = Felt::from_canonical_checked(c).ok_or_else(err)?;
653 let d: Felt = Felt::from_canonical_checked(d).ok_or_else(err)?;
654
655 Ok(Self::new([a, b, c, d]))
656 }
657}
658
659impl TryFrom<&[u8]> for Word {
660 type Error = WordError;
661
662 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
663 let value: [u8; Word::SERIALIZED_SIZE] = value.try_into().map_err(|_| {
664 WordError::InvalidInputLength("bytes", Word::SERIALIZED_SIZE, value.len())
665 })?;
666 value.try_into()
667 }
668}
669
670impl TryFrom<&[Felt]> for Word {
671 type Error = WordError;
672
673 fn try_from(value: &[Felt]) -> Result<Self, Self::Error> {
674 let value: [Felt; Word::NUM_ELEMENTS] = value.try_into().map_err(|_| {
675 WordError::InvalidInputLength("elements", Word::NUM_ELEMENTS, value.len())
676 })?;
677 Ok(value.into())
678 }
679}
680
681#[cfg(not(all(target_family = "wasm", miden)))]
682impl TryFrom<&str> for Word {
683 type Error = WordError;
684
685 fn try_from(value: &str) -> Result<Self, Self::Error> {
687 crate::utils::hex_to_bytes::<{ Word::SERIALIZED_SIZE }>(value)
688 .map_err(WordError::HexParse)
689 .and_then(Word::try_from)
690 }
691}
692
693#[cfg(not(all(target_family = "wasm", miden)))]
694impl TryFrom<String> for Word {
695 type Error = WordError;
696
697 fn try_from(value: String) -> Result<Self, Self::Error> {
699 value.as_str().try_into()
700 }
701}
702
703#[cfg(not(all(target_family = "wasm", miden)))]
704impl TryFrom<&String> for Word {
705 type Error = WordError;
706
707 fn try_from(value: &String) -> Result<Self, Self::Error> {
709 value.as_str().try_into()
710 }
711}
712
713#[cfg(not(all(target_family = "wasm", miden)))]
717impl Serializable for Word {
718 fn write_into<W: ByteWriter>(&self, target: &mut W) {
719 target.write_bytes(&self.as_bytes());
720 }
721
722 fn get_size_hint(&self) -> usize {
723 Self::SERIALIZED_SIZE
724 }
725}
726
727#[cfg(not(all(target_family = "wasm", miden)))]
728impl Deserializable for Word {
729 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
730 let mut inner: [Felt; Word::NUM_ELEMENTS] = [Felt::ZERO; Word::NUM_ELEMENTS];
731 for inner in inner.iter_mut() {
732 let e = source.read_u64()?;
733 if e >= Felt::ORDER {
734 return Err(DeserializationError::InvalidValue(String::from(
735 "value not in the appropriate range",
736 )));
737 }
738 *inner = Felt::new_unchecked(e);
739 }
740
741 Ok(Self::new(inner))
742 }
743
744 fn min_serialized_size() -> usize {
745 Self::SERIALIZED_SIZE
746 }
747}
748
749impl IntoIterator for Word {
752 type Item = Felt;
753 type IntoIter = <[Felt; 4] as IntoIterator>::IntoIter;
754
755 fn into_iter(self) -> Self::IntoIter {
756 self.into_elements().into_iter()
757 }
758}
759
760#[cfg(not(all(target_family = "wasm", miden)))]
767#[macro_export]
768macro_rules! word {
769 ($hex:expr) => {{
770 let word: Word = match $crate::word::Word::parse($hex) {
771 Ok(v) => v,
772 Err(e) => panic!("{}", e),
773 };
774
775 word
776 }};
777}
778
779#[cfg(all(any(test, feature = "arbitrary"), not(all(target_family = "wasm", miden))))]
783mod arbitrary {
784 use proptest::prelude::*;
785
786 use super::{Felt, Word};
787
788 impl Arbitrary for Word {
789 type Parameters = ();
790 type Strategy = BoxedStrategy<Self>;
791
792 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
793 prop::array::uniform4(any::<Felt>()).prop_map(Word::new).boxed()
794 }
795 }
796}