un_prim/
lib.rs

1// This file is part of the un-prim.
2//
3// Copyright (C) 2022 Ade M Ramdani
4//
5// SPDX-License-Identifier: GPL-3.0-or-later
6//
7// This program is free software: you can redistribute it and/or modify
8// it under the terms of the GNU General Public License as published by
9// the Free Software Foundation, either version 3 of the License, or
10// (at your option) any later version.
11//
12// This program is distributed in the hope that it will be useful,
13// but WITHOUT ANY WARRANTY; without even the implied warranty of
14// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15// GNU General Public License for more details.
16//
17// You should have received a copy of the GNU General Public License
18// along with this program.  If not, see <https://www.gnu.org/licenses/>.
19//!
20//! unprim contains primitive types from 8 into 256 bit.
21//! it is unstable and not intended for production use.
22//!
23//! ```rust
24//! use un_prim::*;
25//!
26//! let a = U256::from(100);
27//! let b = U256::from(2);
28//!
29//! assert_eq!(a * b, 200u64.into());
30//! ```
31//! Or you can use `.into()` method to init the types.
32//!
33//! ```rust
34//! use un_prim::*;
35//!
36//! let a: U24 = 100u64.into();
37//! let b: U24 = 2u64.into();
38//! let c: u32 = (a * b).into();
39//!
40//! assert_eq!(c, 200);
41//! ```
42//!
43//! You can use macro to define new types. In example if you want to
44//! define a type with 512 bit, you can use the macro.
45//! ```rust
46//!
47//! use un_prim::*;
48//!
49//! define!(U512, 64, "512 bit");
50//!
51//! let a = U512::from(100);
52//! let b = U512::from(2);
53//! let c = a * b;
54//! assert_eq!(c, 200u64.into());
55pub use std::{
56    ops::{
57        Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Div,
58        DivAssign, Mul, MulAssign, Not, Rem, RemAssign, Shl, ShlAssign, Shr, ShrAssign, Sub,
59        SubAssign,
60    },
61    str::FromStr,
62};
63
64pub use serde::{Deserialize, Serialize};
65
66#[macro_use]
67pub mod macros;
68
69pub fn mul8(x: u8, y: u8) -> (u8, u8) {
70    let z = x as u16 * y as u16;
71    ((z >> 8) as u8, z as u8)
72}
73
74pub fn mul_r(z: u8, x: u8, y: u8) -> (u8, u8) {
75    let (hi, lo) = mul8(x, y);
76    let (lo, c) = lo.overflowing_add(z);
77    let (hi, _) = hi.overflowing_add(c as u8);
78    (hi, lo)
79}
80
81pub fn mul_carry(z: u8, x: u8, y: u8, carry: u8) -> (u8, u8) {
82    let (hi, lo) = mul8(x, y);
83    let (lo, c) = lo.overflowing_add(carry);
84    let (hi, _) = hi.overflowing_add(c as u8);
85    let (lo, c) = lo.overflowing_add(z);
86    let (hi, _) = hi.overflowing_add(c as u8);
87    (hi, lo)
88}
89
90/// Computes 16-bit division of two 8-bit numbers and return the quotient and remainder.
91pub fn div8(hi: u8, lo: u8, y: u8) -> (u8, u8) {
92    if y != 0 && y <= hi {
93        panic!("forbidden");
94    }
95
96    let z = (hi as u16) << 8 | lo as u16;
97    ((z / y as u16) as u8, (z % y as u16) as u8)
98}
99
100/// Computes <!d, !0> / d.
101pub fn reciprocal_2by1(d: u8) -> u8 {
102    let (reciprocal, _) = div8(!d, !0u8, d);
103    reciprocal
104}
105
106/// Devides <uh, ul> / d, returns the quotient and remainder.
107/// It use provided d's reciprocal.
108/// Implementation is ported from https://github.com/holiman/uint250.
109pub fn div_rem_2by1(uh: u8, ul: u8, d: u8, reciprocal: u8) -> (u8, u8) {
110    let (qh, ql) = mul8(reciprocal, uh);
111    let (ql, carry) = ql.overflowing_add(ul);
112    let (mut qh, _) = qh.overflowing_add(uh);
113    qh = qh.overflowing_add(carry as u8 + 1).0;
114
115    let (mut r, _) = ul.overflowing_sub((qh as u16 * d as u16) as u8);
116
117    if r > ql {
118        qh = qh.overflowing_sub(1).0;
119        r = r.overflowing_add(d).0;
120    }
121
122    if r >= d {
123        qh = qh.overflowing_add(1).0;
124        r = r.overflowing_sub(d).0;
125    }
126
127    (qh, r)
128}
129
130/// Computes x -= y * multiplier.
131/// requires: len(x) >= len(y).
132pub fn sub_mul(nx: &[u8], y: &[u8], multiplier: u8) -> (Vec<u8>, u8) {
133    let mut x = vec![0u8; nx.len()];
134    x.copy_from_slice(nx);
135    let mut borrow = 0u8;
136
137    for i in 0..y.len() {
138        let (s, carry1) = x[i].overflowing_sub(borrow);
139        let (ph, pl) = mul8(y[i], multiplier);
140        let (t, carry2) = s.overflowing_sub(pl);
141        x[i] = t;
142        borrow = ph + carry1 as u8 + carry2 as u8;
143    }
144
145    (x, borrow)
146}
147
148/// Computes x += y where x and y is a slice.
149/// requires: len(x) >= len(y).
150pub fn add_slice(x: &[u8], y: &[u8]) -> (Vec<u8>, u8) {
151    let mut x = vec![0u8; x.len()];
152    let mut carry = false;
153    for i in 0..y.len() {
154        (x[i], carry) = x[i].overflowing_add(y[i] + carry as u8);
155    }
156    (x, carry as u8)
157}
158
159define!(
160    U24,
161    3,
162    "24-bit unsigned integer represented as little-endian byte order."
163);
164
165define!(
166    U40,
167    5,
168    "40-bit unsigned integer represented as little-endian byte order."
169);
170
171define!(
172    U48,
173    6,
174    "48-bit unsigned integer represented as little-endian byte order."
175);
176
177define!(
178    U56,
179    7,
180    "56-bit unsigned integer represented as little-endian byte order."
181);
182
183define!(
184    U72,
185    9,
186    "72-bit unsigned integer represented as little-endian byte order."
187);
188
189define!(
190    U80,
191    10,
192    "80-bit unsigned integer represented as little-endian byte order."
193);
194
195define!(
196    U88,
197    11,
198    "88-bit unsigned integer represented as little-endian byte order."
199);
200
201define!(
202    U96,
203    12,
204    "96-bit unsigned integer represented as little-endian byte order."
205);
206
207define!(
208    U104,
209    13,
210    "104-bit unsigned integer represented as little-endian byte order."
211);
212
213define!(
214    U112,
215    14,
216    "112-bit unsigned integer represented as little-endian byte order."
217);
218
219define!(
220    U120,
221    15,
222    "120-bit unsigned integer represented as little-endian byte order."
223);
224
225define!(
226    U136,
227    17,
228    "136-bit unsigned integer represented as little-endian byte order."
229);
230
231define!(
232    U144,
233    18,
234    "144-bit unsigned integer represented as little-endian byte order."
235);
236
237define!(
238    U152,
239    19,
240    "152-bit unsigned integer represented as little-endian byte order."
241);
242
243define!(
244    U160,
245    20,
246    "160-bit unsigned integer represented as little-endian byte order."
247);
248
249define!(
250    U168,
251    21,
252    "168-bit unsigned integer represented as little-endian byte order."
253);
254
255define!(
256    U176,
257    22,
258    "176-bit unsigned integer represented as little-endian byte order."
259);
260
261define!(
262    U184,
263    23,
264    "184-bit unsigned integer represented as little-endian byte order."
265);
266
267define!(
268    U192,
269    24,
270    "192-bit unsigned integer represented as little-endian byte order."
271);
272
273define!(
274    U200,
275    25,
276    "200-bit unsigned integer represented as little-endian byte order."
277);
278
279define!(
280    U208,
281    26,
282    "208-bit unsigned integer represented as little-endian byte order."
283);
284
285define!(
286    U216,
287    27,
288    "216-bit unsigned integer represented as little-endian byte order."
289);
290
291define!(
292    U224,
293    28,
294    "224-bit unsigned integer represented as little-endian byte order."
295);
296
297define!(
298    U232,
299    29,
300    "232-bit unsigned integer represented as little-endian byte order."
301);
302
303define!(
304    U240,
305    30,
306    "240-bit unsigned integer represented as little-endian byte order."
307);
308
309define!(
310    U248,
311    31,
312    "248-bit unsigned integer represented as little-endian byte order."
313);
314
315define!(
316    U256,
317    32,
318    "256-bit unsigned integer represented as little-endian byte order."
319);
320
321#[cfg(test)]
322mod test_un_prim {
323    use super::*;
324
325    #[test]
326    fn test_macro() {
327        define!(
328            U8,
329            1,
330            "8-bit unsigned integer represented as little-endian byte order."
331        );
332
333        let x: U8 = 200u8.into();
334        assert_eq!(200u8, x.into());
335    }
336}