bee_crypto/ternary/bigint/t243/
mod.rs

1// Copyright 2020-2021 IOTA Stiftung
2// SPDX-License-Identifier: Apache-2.0
3
4//! This module contains logic to convert an integer encoded by 243 trits to the same integer encoded by 384 bits (or 48
5//! signed bytes, `i8`).
6//!
7//! At the core of this a slice of binary-coded, balanced trits is interpreted fanned out `t243`, where `t243` is used
8//! analogous to `i64` or `u64`. If the latter are 64-bit signed/unsigned integer types, then `t243` is a 243-trit
9//! integer type. Analogous to fanning out a `u64` into 64 individual bits, `t243` is fanned out into 243 trits, each
10//! (rather inefficiently) represented by one `u8`.
11
12mod constants;
13
14pub use constants::{BTRIT_0, BTRIT_1, BTRIT_NEG_1, UTRIT_0, UTRIT_1, UTRIT_2, UTRIT_U384_MAX, UTRIT_U384_MAX_HALF};
15
16use crate::ternary::bigint::{
17    binary_representation::{U32Repr, U8Repr},
18    endianness::{BigEndian, LittleEndian},
19    I384, T242, U384,
20};
21
22use bee_ternary::{Btrit, ShiftTernary, T1B1Buf, Trit, TritBuf, Utrit};
23
24use std::cmp::Ordering;
25
26def_and_impl_ternary!(T243, 243);
27
28impl<T: Trit> T243<T> {
29    /// Converts the `T243` to a `T242`.
30    pub fn into_t242(self) -> T242<T> {
31        let mut trit_buf = self.into_inner();
32        trit_buf.pop();
33        T242::new(trit_buf)
34    }
35}
36
37impl T243<Utrit> {
38    /// Converts a big-endian `u32` represented `U384` to an unbalanced `T243`.
39    pub fn from_u384(value: U384<BigEndian, U32Repr>) -> Self {
40        let mut u384_value = value;
41        let mut u384_inner_slice = &mut u384_value.inner[..];
42
43        let mut trit_buf = T243::<Utrit>::zero().into_inner();
44        unsafe {
45            for trit in trit_buf.as_i8_slice_mut() {
46                let mut rem = 0;
47
48                // Skip the most significant digits if they are 0.
49                let mut first_digit = 0;
50                for (i, digit) in u384_inner_slice.iter().enumerate() {
51                    first_digit = i;
52                    if *digit != 0 {
53                        break;
54                    }
55                }
56                u384_inner_slice = &mut u384_inner_slice[first_digit..];
57
58                // Iterate over the digits of the bigint, starting from the most significant one.
59                for digit in u384_inner_slice.iter_mut() {
60                    let digit_with_rem = (u64::from(rem) << 32) | u64::from(*digit);
61                    #[allow(clippy::cast_possible_truncation)]
62                    // `digit_with_rem` is already truncated and `digit_with_rem % 3` is an integer modulo 3
63                    {
64                        *digit = (digit_with_rem / 3u64) as u32;
65                        rem = (digit_with_rem % 3u64) as u32;
66                    }
67                }
68                #[allow(clippy::cast_possible_truncation)] // `rem` is an integer modulo 3.
69                {
70                    *trit = rem as i8;
71                }
72            }
73        }
74
75        Self(trit_buf)
76    }
77}
78
79impl<T: Trit> From<T242<T>> for T243<T> {
80    fn from(value: T242<T>) -> Self {
81        value.into_t243()
82    }
83}
84
85impl From<I384<BigEndian, U8Repr>> for T243<Btrit> {
86    fn from(value: I384<BigEndian, U8Repr>) -> Self {
87        let be_u32 = Into::<I384<BigEndian, U32Repr>>::into(value);
88        let le_u32 = Into::<I384<LittleEndian, U32Repr>>::into(be_u32);
89        le_u32.into()
90    }
91}
92
93impl From<I384<BigEndian, U32Repr>> for T243<Btrit> {
94    fn from(value: I384<BigEndian, U32Repr>) -> Self {
95        let value_little_endian: I384<LittleEndian, U32Repr> = value.into();
96        value_little_endian.into()
97    }
98}
99
100impl From<I384<LittleEndian, U32Repr>> for T243<Btrit> {
101    fn from(value: I384<LittleEndian, U32Repr>) -> Self {
102        let u384_value = value.shift_into_u384();
103        let t243_unbalanced = T243::<Utrit>::from(u384_value);
104        t243_unbalanced.into_shifted()
105    }
106}
107
108impl From<U384<BigEndian, U32Repr>> for T243<Utrit> {
109    fn from(value: U384<BigEndian, U32Repr>) -> Self {
110        Self::from_u384(value)
111    }
112}
113
114impl From<U384<LittleEndian, U32Repr>> for T243<Utrit> {
115    fn from(value: U384<LittleEndian, U32Repr>) -> Self {
116        let value: U384<BigEndian, U32Repr> = value.into();
117        value.into()
118    }
119}