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