Skip to main content

dbl/
lib.rs

1//! Double operation in Galois Field (GF)
2#![no_std]
3#![doc(
4    html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg",
5    html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg"
6)]
7#![forbid(unsafe_code)]
8
9use hybrid_array::Array;
10use hybrid_array::typenum::{U8, U16, U32};
11
12const C64: u64 = 0b1_1011;
13const C128: u64 = 0b1000_0111;
14const C256: u64 = 0b100_0010_0101;
15
16mod sealed {
17    pub trait Sealed {}
18}
19
20/// Double and inverse double over `GF(2^n)` with the lexicographically first polynomial
21/// among the irreducible degree `n` polynomials having a minimum number of coefficients.
22///
23/// This trait is implemented using big-endian byte order for 64, 128 and 256 bit block sizes.
24pub trait Dbl: sealed::Sealed {
25    /// Double block. (alternatively: multiply block by x)
26    ///
27    /// If most significant bit of the block equals to zero will return
28    /// `block<<1`, otherwise `(block<<1)^C`, where `C` is the non-leading
29    /// coefficients of the lexicographically first irreducible degree-b binary
30    /// polynomial with the minimal number of ones.
31    #[must_use]
32    fn dbl(self) -> Self;
33
34    /// Reverse double block. (alternatively: divide block by x)
35    ///
36    /// If least significant bit of the block equals to zero will return
37    /// `block>>1`, otherwise `(block>>1)^(1<<n)^(C>>1)`
38    #[must_use]
39    fn inv_dbl(self) -> Self;
40}
41
42impl Dbl for Array<u8, U8> {
43    #[inline]
44    fn dbl(self) -> Self {
45        let mut val = u64::from_be_bytes(self.into());
46
47        let a = val >> 63;
48        val <<= 1;
49        val ^= a * C64;
50
51        val.to_be_bytes().into()
52    }
53
54    #[inline]
55    fn inv_dbl(self) -> Self {
56        let mut val = u64::from_be_bytes(self.into());
57
58        let a = val & 1;
59        val >>= 1;
60        val ^= a * ((1 << 63) ^ (C64 >> 1));
61
62        val.to_be_bytes().into()
63    }
64}
65
66impl sealed::Sealed for Array<u8, U8> {}
67
68impl Dbl for Array<u8, U16> {
69    #[inline]
70    fn dbl(self) -> Self {
71        let mut val = [
72            u64::from_be_bytes(self[..8].try_into().unwrap()),
73            u64::from_be_bytes(self[8..].try_into().unwrap()),
74        ];
75
76        let b = val[1] >> 63;
77        let a = val[0] >> 63;
78
79        val[0] <<= 1;
80        val[0] ^= b;
81        val[1] <<= 1;
82        val[1] ^= a * C128;
83
84        let mut res = Self::default();
85        res[..8].copy_from_slice(&val[0].to_be_bytes());
86        res[8..].copy_from_slice(&val[1].to_be_bytes());
87        res
88    }
89
90    #[inline]
91    fn inv_dbl(self) -> Self {
92        let mut val = [
93            u64::from_be_bytes(self[..8].try_into().unwrap()),
94            u64::from_be_bytes(self[8..].try_into().unwrap()),
95        ];
96
97        let a = (val[0] & 1) << 63;
98        let b = val[1] & 1;
99
100        val[0] >>= 1;
101        val[1] >>= 1;
102        val[1] ^= a;
103        val[0] ^= b * (1 << 63);
104        val[1] ^= b * (C128 >> 1);
105
106        let mut res = Self::default();
107        res[..8].copy_from_slice(&val[0].to_be_bytes());
108        res[8..].copy_from_slice(&val[1].to_be_bytes());
109        res
110    }
111}
112
113impl sealed::Sealed for Array<u8, U16> {}
114
115impl Dbl for Array<u8, U32> {
116    #[inline]
117    fn dbl(self) -> Self {
118        let mut val = [
119            u64::from_be_bytes(self[0..8].try_into().unwrap()),
120            u64::from_be_bytes(self[8..16].try_into().unwrap()),
121            u64::from_be_bytes(self[16..24].try_into().unwrap()),
122            u64::from_be_bytes(self[24..32].try_into().unwrap()),
123        ];
124
125        let a = val[0] >> 63;
126        let b = val[1] >> 63;
127        let c = val[2] >> 63;
128        let d = val[3] >> 63;
129
130        val[0] <<= 1;
131        val[0] ^= b;
132        val[1] <<= 1;
133        val[1] ^= c;
134        val[2] <<= 1;
135        val[2] ^= d;
136        val[3] <<= 1;
137        val[3] ^= a * C256;
138
139        let mut res = Self::default();
140        res[0..8].copy_from_slice(&val[0].to_be_bytes());
141        res[8..16].copy_from_slice(&val[1].to_be_bytes());
142        res[16..24].copy_from_slice(&val[2].to_be_bytes());
143        res[24..32].copy_from_slice(&val[3].to_be_bytes());
144        res
145    }
146
147    #[inline]
148    fn inv_dbl(self) -> Self {
149        let mut val = [
150            u64::from_be_bytes(self[0..8].try_into().unwrap()),
151            u64::from_be_bytes(self[8..16].try_into().unwrap()),
152            u64::from_be_bytes(self[16..24].try_into().unwrap()),
153            u64::from_be_bytes(self[24..32].try_into().unwrap()),
154        ];
155
156        let a = (val[0] & 1) << 63;
157        let b = (val[1] & 1) << 63;
158        let c = (val[2] & 1) << 63;
159        let d = val[3] & 1;
160
161        val[0] >>= 1;
162        val[1] >>= 1;
163        val[2] >>= 1;
164        val[3] >>= 1;
165        val[1] ^= a;
166        val[2] ^= b;
167        val[3] ^= c;
168
169        val[0] ^= d * (1 << 63);
170        val[3] ^= d * (C256 >> 1);
171
172        let mut res = Self::default();
173        res[0..8].copy_from_slice(&val[0].to_be_bytes());
174        res[8..16].copy_from_slice(&val[1].to_be_bytes());
175        res[16..24].copy_from_slice(&val[2].to_be_bytes());
176        res[24..32].copy_from_slice(&val[3].to_be_bytes());
177        res
178    }
179}
180
181impl sealed::Sealed for Array<u8, U32> {}