1use alloc::{string::String, vec::Vec};
4use core::{
5 cmp::Ordering,
6 fmt::Display,
7 hash::{Hash, Hasher},
8 ops::{Deref, DerefMut, Index, IndexMut, Range},
9 slice,
10};
11
12use thiserror::Error;
13
14const WORD_SIZE_FELT: usize = 4;
15const WORD_SIZE_BYTES: usize = 32;
16
17use p3_field::integers::QuotientMap;
18
19use super::{Felt, ZERO};
20use crate::{
21 field::{PrimeCharacteristicRing, PrimeField64},
22 rand::Randomizable,
23 utils::{
24 ByteReader, ByteWriter, Deserializable, DeserializationError, HexParseError, Serializable,
25 bytes_to_hex_string, hex_to_bytes,
26 },
27};
28
29mod lexicographic;
30pub use lexicographic::LexicographicWord;
31
32#[cfg(test)]
33mod tests;
34
35#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
40#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
41#[cfg_attr(feature = "serde", serde(into = "String", try_from = "&str"))]
42pub struct Word([Felt; WORD_SIZE_FELT]);
43
44impl Word {
45 pub const SERIALIZED_SIZE: usize = WORD_SIZE_BYTES;
47
48 pub const fn new(value: [Felt; WORD_SIZE_FELT]) -> Self {
50 Self(value)
51 }
52
53 pub const fn parse(hex: &str) -> Result<Self, &'static str> {
69 const fn parse_hex_digit(digit: u8) -> Result<u8, &'static str> {
70 match digit {
71 b'0'..=b'9' => Ok(digit - b'0'),
72 b'A'..=b'F' => Ok(digit - b'A' + 0x0a),
73 b'a'..=b'f' => Ok(digit - b'a' + 0x0a),
74 _ => Err("Invalid hex character"),
75 }
76 }
77 let hex_bytes = match hex.as_bytes() {
79 [b'0', b'x', rest @ ..] => rest,
80 _ => return Err("Hex string must have a \"0x\" prefix"),
81 };
82
83 if hex_bytes.len() > 64 {
84 return Err("Hex string has more than 64 characters");
85 }
86
87 let mut felts = [0u64; 4];
88 let mut i = 0;
89 while i < hex_bytes.len() {
90 let hex_digit = match parse_hex_digit(hex_bytes[i]) {
91 Ok(v) => v as u64,
94 Err(e) => return Err(e),
95 };
96
97 let inibble = if i.is_multiple_of(2) {
100 (i + 1) % 16
101 } else {
102 (i - 1) % 16
103 };
104
105 let value = hex_digit << (inibble * 4);
106 felts[i / 2 / 8] += value;
107
108 i += 1;
109 }
110
111 let mut idx = 0;
114 while idx < felts.len() {
115 if felts[idx] >= Felt::ORDER_U64 {
116 return Err("Felt overflow");
117 }
118 idx += 1;
119 }
120
121 Ok(Self::new([
122 Felt::new(felts[0]),
123 Felt::new(felts[1]),
124 Felt::new(felts[2]),
125 Felt::new(felts[3]),
126 ]))
127 }
128
129 pub const fn empty() -> Self {
131 Self([Felt::ZERO; WORD_SIZE_FELT])
132 }
133
134 pub fn is_empty(&self) -> bool {
136 self.0[0] == Felt::ZERO
137 && self.0[1] == Felt::ZERO
138 && self.0[2] == Felt::ZERO
139 && self.0[3] == Felt::ZERO
140 }
141
142 pub fn as_elements(&self) -> &[Felt] {
144 self.as_ref()
145 }
146
147 pub fn as_bytes(&self) -> [u8; WORD_SIZE_BYTES] {
149 let mut result = [0; WORD_SIZE_BYTES];
150
151 result[..8].copy_from_slice(&self.0[0].as_canonical_u64().to_le_bytes());
152 result[8..16].copy_from_slice(&self.0[1].as_canonical_u64().to_le_bytes());
153 result[16..24].copy_from_slice(&self.0[2].as_canonical_u64().to_le_bytes());
154 result[24..].copy_from_slice(&self.0[3].as_canonical_u64().to_le_bytes());
155
156 result
157 }
158
159 pub(crate) fn words_as_elements_iter<'a, I>(words: I) -> impl Iterator<Item = &'a Felt>
161 where
162 I: Iterator<Item = &'a Self>,
163 {
164 words.flat_map(|d| d.0.iter())
165 }
166
167 pub fn words_as_elements(words: &[Self]) -> &[Felt] {
169 let p = words.as_ptr();
170 let len = words.len() * WORD_SIZE_FELT;
171 unsafe { slice::from_raw_parts(p as *const Felt, len) }
172 }
173
174 pub fn to_hex(&self) -> String {
176 bytes_to_hex_string(self.as_bytes())
177 }
178
179 pub fn to_vec(&self) -> Vec<Felt> {
181 self.0.to_vec()
182 }
183}
184
185impl Hash for Word {
186 fn hash<H: Hasher>(&self, state: &mut H) {
187 state.write(&self.as_bytes());
188 }
189}
190
191impl Deref for Word {
192 type Target = [Felt; WORD_SIZE_FELT];
193
194 fn deref(&self) -> &Self::Target {
195 &self.0
196 }
197}
198
199impl DerefMut for Word {
200 fn deref_mut(&mut self) -> &mut Self::Target {
201 &mut self.0
202 }
203}
204
205impl Index<usize> for Word {
206 type Output = Felt;
207
208 fn index(&self, index: usize) -> &Self::Output {
209 &self.0[index]
210 }
211}
212
213impl IndexMut<usize> for Word {
214 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
215 &mut self.0[index]
216 }
217}
218
219impl Index<Range<usize>> for Word {
220 type Output = [Felt];
221
222 fn index(&self, index: Range<usize>) -> &Self::Output {
223 &self.0[index]
224 }
225}
226
227impl IndexMut<Range<usize>> for Word {
228 fn index_mut(&mut self, index: Range<usize>) -> &mut Self::Output {
229 &mut self.0[index]
230 }
231}
232
233impl Ord for Word {
234 fn cmp(&self, other: &Self) -> Ordering {
235 self.0
249 .iter()
250 .map(Felt::as_canonical_u64)
251 .zip(other.0.iter().map(Felt::as_canonical_u64))
252 .fold(Ordering::Equal, |ord, (a, b)| match ord {
253 Ordering::Equal => a.cmp(&b),
254 _ => ord,
255 })
256 }
257}
258
259impl PartialOrd for Word {
260 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
261 Some(self.cmp(other))
262 }
263}
264
265impl Display for Word {
266 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
267 write!(f, "{}", self.to_hex())
268 }
269}
270
271impl Randomizable for Word {
272 const VALUE_SIZE: usize = WORD_SIZE_BYTES;
273
274 fn from_random_bytes(bytes: &[u8]) -> Option<Self> {
275 let bytes_array: Option<[u8; 32]> = bytes.try_into().ok();
276 if let Some(bytes_array) = bytes_array {
277 Self::try_from(bytes_array).ok()
278 } else {
279 None
280 }
281 }
282}
283
284#[derive(Debug, Error)]
289pub enum WordError {
290 #[error("hex encoded values of a word are invalid")]
292 HexParse(#[from] HexParseError),
293 #[error("failed to convert to field element: {0}")]
295 InvalidFieldElement(String),
296 #[error("invalid input length: expected {1} {0}, but received {2}")]
298 InvalidInputLength(&'static str, usize, usize),
299 #[error("failed to convert the word's field elements to type {0}")]
301 TypeConversion(&'static str),
302}
303
304impl TryFrom<&Word> for [bool; WORD_SIZE_FELT] {
305 type Error = WordError;
306
307 fn try_from(value: &Word) -> Result<Self, Self::Error> {
308 (*value).try_into()
309 }
310}
311
312impl TryFrom<Word> for [bool; WORD_SIZE_FELT] {
313 type Error = WordError;
314
315 fn try_from(value: Word) -> Result<Self, Self::Error> {
316 fn to_bool(v: u64) -> Option<bool> {
317 if v <= 1 { Some(v == 1) } else { None }
318 }
319
320 Ok([
321 to_bool(value.0[0].as_canonical_u64()).ok_or(WordError::TypeConversion("bool"))?,
322 to_bool(value.0[1].as_canonical_u64()).ok_or(WordError::TypeConversion("bool"))?,
323 to_bool(value.0[2].as_canonical_u64()).ok_or(WordError::TypeConversion("bool"))?,
324 to_bool(value.0[3].as_canonical_u64()).ok_or(WordError::TypeConversion("bool"))?,
325 ])
326 }
327}
328
329impl TryFrom<&Word> for [u8; WORD_SIZE_FELT] {
330 type Error = WordError;
331
332 fn try_from(value: &Word) -> Result<Self, Self::Error> {
333 (*value).try_into()
334 }
335}
336
337impl TryFrom<Word> for [u8; WORD_SIZE_FELT] {
338 type Error = WordError;
339
340 fn try_from(value: Word) -> Result<Self, Self::Error> {
341 Ok([
342 value.0[0]
343 .as_canonical_u64()
344 .try_into()
345 .map_err(|_| WordError::TypeConversion("u8"))?,
346 value.0[1]
347 .as_canonical_u64()
348 .try_into()
349 .map_err(|_| WordError::TypeConversion("u8"))?,
350 value.0[2]
351 .as_canonical_u64()
352 .try_into()
353 .map_err(|_| WordError::TypeConversion("u8"))?,
354 value.0[3]
355 .as_canonical_u64()
356 .try_into()
357 .map_err(|_| WordError::TypeConversion("u8"))?,
358 ])
359 }
360}
361
362impl TryFrom<&Word> for [u16; WORD_SIZE_FELT] {
363 type Error = WordError;
364
365 fn try_from(value: &Word) -> Result<Self, Self::Error> {
366 (*value).try_into()
367 }
368}
369
370impl TryFrom<Word> for [u16; WORD_SIZE_FELT] {
371 type Error = WordError;
372
373 fn try_from(value: Word) -> Result<Self, Self::Error> {
374 Ok([
375 value.0[0]
376 .as_canonical_u64()
377 .try_into()
378 .map_err(|_| WordError::TypeConversion("u16"))?,
379 value.0[1]
380 .as_canonical_u64()
381 .try_into()
382 .map_err(|_| WordError::TypeConversion("u16"))?,
383 value.0[2]
384 .as_canonical_u64()
385 .try_into()
386 .map_err(|_| WordError::TypeConversion("u16"))?,
387 value.0[3]
388 .as_canonical_u64()
389 .try_into()
390 .map_err(|_| WordError::TypeConversion("u16"))?,
391 ])
392 }
393}
394
395impl TryFrom<&Word> for [u32; WORD_SIZE_FELT] {
396 type Error = WordError;
397
398 fn try_from(value: &Word) -> Result<Self, Self::Error> {
399 (*value).try_into()
400 }
401}
402
403impl TryFrom<Word> for [u32; WORD_SIZE_FELT] {
404 type Error = WordError;
405
406 fn try_from(value: Word) -> Result<Self, Self::Error> {
407 Ok([
408 value.0[0]
409 .as_canonical_u64()
410 .try_into()
411 .map_err(|_| WordError::TypeConversion("u32"))?,
412 value.0[1]
413 .as_canonical_u64()
414 .try_into()
415 .map_err(|_| WordError::TypeConversion("u32"))?,
416 value.0[2]
417 .as_canonical_u64()
418 .try_into()
419 .map_err(|_| WordError::TypeConversion("u32"))?,
420 value.0[3]
421 .as_canonical_u64()
422 .try_into()
423 .map_err(|_| WordError::TypeConversion("u32"))?,
424 ])
425 }
426}
427
428impl From<&Word> for [u64; WORD_SIZE_FELT] {
429 fn from(value: &Word) -> Self {
430 (*value).into()
431 }
432}
433
434impl From<Word> for [u64; WORD_SIZE_FELT] {
435 fn from(value: Word) -> Self {
436 [
437 value.0[0].as_canonical_u64(),
438 value.0[1].as_canonical_u64(),
439 value.0[2].as_canonical_u64(),
440 value.0[3].as_canonical_u64(),
441 ]
442 }
443}
444
445impl From<&Word> for [Felt; WORD_SIZE_FELT] {
446 fn from(value: &Word) -> Self {
447 (*value).into()
448 }
449}
450
451impl From<Word> for [Felt; WORD_SIZE_FELT] {
452 fn from(value: Word) -> Self {
453 value.0
454 }
455}
456
457impl From<&Word> for [u8; WORD_SIZE_BYTES] {
458 fn from(value: &Word) -> Self {
459 (*value).into()
460 }
461}
462
463impl From<Word> for [u8; WORD_SIZE_BYTES] {
464 fn from(value: Word) -> Self {
465 value.as_bytes()
466 }
467}
468
469impl From<&Word> for String {
470 fn from(value: &Word) -> Self {
472 (*value).into()
473 }
474}
475
476impl From<Word> for String {
477 fn from(value: Word) -> Self {
479 value.to_hex()
480 }
481}
482
483impl From<&[bool; WORD_SIZE_FELT]> for Word {
487 fn from(value: &[bool; WORD_SIZE_FELT]) -> Self {
488 (*value).into()
489 }
490}
491
492impl From<[bool; WORD_SIZE_FELT]> for Word {
493 fn from(value: [bool; WORD_SIZE_FELT]) -> Self {
494 [value[0] as u32, value[1] as u32, value[2] as u32, value[3] as u32].into()
495 }
496}
497
498impl From<&[u8; WORD_SIZE_FELT]> for Word {
499 fn from(value: &[u8; WORD_SIZE_FELT]) -> Self {
500 (*value).into()
501 }
502}
503
504impl From<[u8; WORD_SIZE_FELT]> for Word {
505 fn from(value: [u8; WORD_SIZE_FELT]) -> Self {
506 Self([
507 Felt::from_u8(value[0]),
508 Felt::from_u8(value[1]),
509 Felt::from_u8(value[2]),
510 Felt::from_u8(value[3]),
511 ])
512 }
513}
514
515impl From<&[u16; WORD_SIZE_FELT]> for Word {
516 fn from(value: &[u16; WORD_SIZE_FELT]) -> Self {
517 (*value).into()
518 }
519}
520
521impl From<[u16; WORD_SIZE_FELT]> for Word {
522 fn from(value: [u16; WORD_SIZE_FELT]) -> Self {
523 Self([
524 Felt::from_u16(value[0]),
525 Felt::from_u16(value[1]),
526 Felt::from_u16(value[2]),
527 Felt::from_u16(value[3]),
528 ])
529 }
530}
531
532impl From<&[u32; WORD_SIZE_FELT]> for Word {
533 fn from(value: &[u32; WORD_SIZE_FELT]) -> Self {
534 (*value).into()
535 }
536}
537
538impl From<[u32; WORD_SIZE_FELT]> for Word {
539 fn from(value: [u32; WORD_SIZE_FELT]) -> Self {
540 Self([
541 Felt::from_u32(value[0]),
542 Felt::from_u32(value[1]),
543 Felt::from_u32(value[2]),
544 Felt::from_u32(value[3]),
545 ])
546 }
547}
548
549impl TryFrom<&[u64; WORD_SIZE_FELT]> for Word {
550 type Error = WordError;
551
552 fn try_from(value: &[u64; WORD_SIZE_FELT]) -> Result<Self, WordError> {
553 (*value).try_into()
554 }
555}
556
557impl TryFrom<[u64; WORD_SIZE_FELT]> for Word {
558 type Error = WordError;
559
560 fn try_from(value: [u64; WORD_SIZE_FELT]) -> Result<Self, WordError> {
561 let err = || WordError::InvalidFieldElement("value >= field modulus".into());
562 Ok(Self([
563 Felt::from_canonical_checked(value[0]).ok_or_else(err)?,
564 Felt::from_canonical_checked(value[1]).ok_or_else(err)?,
565 Felt::from_canonical_checked(value[2]).ok_or_else(err)?,
566 Felt::from_canonical_checked(value[3]).ok_or_else(err)?,
567 ]))
568 }
569}
570
571impl From<&[Felt; WORD_SIZE_FELT]> for Word {
572 fn from(value: &[Felt; WORD_SIZE_FELT]) -> Self {
573 Self(*value)
574 }
575}
576
577impl From<[Felt; WORD_SIZE_FELT]> for Word {
578 fn from(value: [Felt; WORD_SIZE_FELT]) -> Self {
579 Self(value)
580 }
581}
582
583impl TryFrom<&[u8; WORD_SIZE_BYTES]> for Word {
584 type Error = WordError;
585
586 fn try_from(value: &[u8; WORD_SIZE_BYTES]) -> Result<Self, Self::Error> {
587 (*value).try_into()
588 }
589}
590
591impl TryFrom<[u8; WORD_SIZE_BYTES]> for Word {
592 type Error = WordError;
593
594 fn try_from(value: [u8; WORD_SIZE_BYTES]) -> Result<Self, Self::Error> {
595 let a = u64::from_le_bytes(value[0..8].try_into().unwrap());
598 let b = u64::from_le_bytes(value[8..16].try_into().unwrap());
599 let c = u64::from_le_bytes(value[16..24].try_into().unwrap());
600 let d = u64::from_le_bytes(value[24..32].try_into().unwrap());
601
602 let err = || WordError::InvalidFieldElement("value >= field modulus".into());
603 let a: Felt = Felt::from_canonical_checked(a).ok_or_else(err)?;
604 let b: Felt = Felt::from_canonical_checked(b).ok_or_else(err)?;
605 let c: Felt = Felt::from_canonical_checked(c).ok_or_else(err)?;
606 let d: Felt = Felt::from_canonical_checked(d).ok_or_else(err)?;
607
608 Ok(Word([a, b, c, d]))
609 }
610}
611
612impl TryFrom<&[u8]> for Word {
613 type Error = WordError;
614
615 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
616 let value: [u8; WORD_SIZE_BYTES] = value
617 .try_into()
618 .map_err(|_| WordError::InvalidInputLength("bytes", WORD_SIZE_BYTES, value.len()))?;
619 value.try_into()
620 }
621}
622
623impl TryFrom<&[Felt]> for Word {
624 type Error = WordError;
625
626 fn try_from(value: &[Felt]) -> Result<Self, Self::Error> {
627 let value: [Felt; WORD_SIZE_FELT] = value
628 .try_into()
629 .map_err(|_| WordError::InvalidInputLength("elements", WORD_SIZE_FELT, value.len()))?;
630 Ok(value.into())
631 }
632}
633
634impl TryFrom<&str> for Word {
635 type Error = WordError;
636
637 fn try_from(value: &str) -> Result<Self, Self::Error> {
639 hex_to_bytes::<WORD_SIZE_BYTES>(value)
640 .map_err(WordError::HexParse)
641 .and_then(Word::try_from)
642 }
643}
644
645impl TryFrom<String> for Word {
646 type Error = WordError;
647
648 fn try_from(value: String) -> Result<Self, Self::Error> {
650 value.as_str().try_into()
651 }
652}
653
654impl TryFrom<&String> for Word {
655 type Error = WordError;
656
657 fn try_from(value: &String) -> Result<Self, Self::Error> {
659 value.as_str().try_into()
660 }
661}
662
663impl Serializable for Word {
667 fn write_into<W: ByteWriter>(&self, target: &mut W) {
668 target.write_bytes(&self.as_bytes());
669 }
670
671 fn get_size_hint(&self) -> usize {
672 Self::SERIALIZED_SIZE
673 }
674}
675
676impl Deserializable for Word {
677 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
678 let mut inner: [Felt; WORD_SIZE_FELT] = [ZERO; WORD_SIZE_FELT];
679 for inner in inner.iter_mut() {
680 let e = source.read_u64()?;
681 if e >= Felt::ORDER_U64 {
682 return Err(DeserializationError::InvalidValue(String::from(
683 "value not in the appropriate range",
684 )));
685 }
686 *inner = Felt::new(e);
687 }
688
689 Ok(Self(inner))
690 }
691}
692
693impl IntoIterator for Word {
696 type Item = Felt;
697 type IntoIter = <[Felt; 4] as IntoIterator>::IntoIter;
698
699 fn into_iter(self) -> Self::IntoIter {
700 self.0.into_iter()
701 }
702}
703
704#[macro_export]
711macro_rules! word {
712 ($hex:expr) => {{
713 let word: Word = match $crate::word::Word::parse($hex) {
714 Ok(v) => v,
715 Err(e) => panic!("{}", e),
716 };
717
718 word
719 }};
720}
721
722#[cfg(any(test, feature = "testing"))]
726mod arbitrary {
727 use proptest::prelude::*;
728
729 use super::{Felt, Word};
730
731 impl Arbitrary for Word {
732 type Parameters = ();
733 type Strategy = BoxedStrategy<Self>;
734
735 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
736 prop::collection::vec(any::<u64>(), 4)
737 .prop_map(|vals| {
738 Word::new([
739 Felt::new(vals[0]),
740 Felt::new(vals[1]),
741 Felt::new(vals[2]),
742 Felt::new(vals[3]),
743 ])
744 })
745 .no_shrink()
746 .boxed()
747 }
748 }
749}