nettrash-a 0.1.29

Algorithms in pure Rust with no dependencies: 23 sorting algorithms and a default sort; arbitrary-precision integers with Karatsuba, Toom-Cook and NTT multiplication, Newton division, GCD, roots, modular powers, primes and modular square roots; elliptic curves over prime fields with secp256k1, P-256, P-384, P-521, Curve25519 and Ed25519; complex numbers; matrices of floats, complex numbers or integers with LU, QR, Cholesky, SVD, Schur and eigendecompositions, exp, sqrt and log, and exact integer determinants and inverses. Not constant-time.
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
use super::ByteOrder;
use core::fmt;

/// An integer of any size, stored as its sign and the bytes of its absolute value.
///
/// `value` holds the absolute value (the magnitude) of the integer as bytes, in the order
/// `byte_order` names: the most significant byte first for [`ByteOrder::BigEndian`], the
/// least significant first for [`ByteOrder::LittleEndian`]. `negative` holds the sign. This
/// is the sign-and-magnitude form most big-integer libraries use: `-2` is `[2]` with
/// `negative` set, not the two's-complement byte `[0xFE]`.
///
/// The constructors keep the shortest form: they drop the zero bytes above the most
/// significant non-zero byte and keep one byte for zero, so `1` and `-1` are `[1]`, and `0` is
/// `[0]`, in either order. An empty `value` is zero as well; the constructors keep an empty
/// vector empty. Zero is never negative: there is one zero, not a positive and a negative one.
///
/// The fields are public, so a `Number` can also be built directly; it is then stored exactly
/// as given, zero bytes and the sign of zero included.
///
/// # Examples
///
/// ```
/// use a::math::numbers::{ByteOrder, Number};
///
/// let big = Number::new_from_i32(-0x0001_0203, ByteOrder::BigEndian);
/// assert_eq!(big.value, [0x01, 0x02, 0x03]);
/// assert!(big.is_negative());
///
/// let little = Number::new_from_u32(0x0001_0203, ByteOrder::LittleEndian);
/// assert_eq!(little.value, [0x03, 0x02, 0x01]);
/// assert!(!little.is_negative());
/// ```
pub struct Number {
    /// The bytes of the absolute value of the number, in the order of `byte_order`.
    pub value: Vec<u8>,
    /// Whether the number is below zero; `false` for zero.
    pub negative: bool,
    /// The order of the bytes in `value`.
    pub byte_order: ByteOrder,
}

impl Number {
    /// Creates a non-negative number from its bytes in `byte_order`, dropping the zero bytes
    /// above the most significant non-zero byte: the leading zeros in big-endian order, the
    /// trailing zeros in little-endian order.
    ///
    /// Zero bytes below the most significant non-zero byte are part of the number and stay.
    /// A number whose bytes are all zero keeps one of them, `[0]`; an empty vector stays
    /// empty.
    ///
    /// Takes `O(n)` time for `n` bytes and reuses the allocation of `value`. For a negative
    /// number, see [`new_signed`](Self::new_signed).
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// let n = Number::new(vec![0, 0, 1, 0, 2], ByteOrder::BigEndian);
    /// assert_eq!(n.value, [1, 0, 2]);
    ///
    /// let n = Number::new(vec![2, 0, 1, 0, 0], ByteOrder::LittleEndian);
    /// assert_eq!(n.value, [2, 0, 1]);
    ///
    /// let zero = Number::new(vec![0, 0, 0], ByteOrder::BigEndian);
    /// assert_eq!(zero.value, [0]);
    /// ```
    pub fn new(mut value: Vec<u8>, byte_order: ByteOrder) -> Self {
        match byte_order {
            // The most significant byte comes first: drop everything before the first
            // non-zero byte, or all but the last byte when every byte is zero.
            ByteOrder::BigEndian => {
                let start = value
                    .iter()
                    .position(|&b| b != 0)
                    .unwrap_or(value.len().saturating_sub(1));
                value.drain(..start);
            }
            // The most significant byte comes last: cut everything after the last non-zero
            // byte, or all but the first byte when every byte is zero.
            ByteOrder::LittleEndian => {
                let end = value.iter().rposition(|&b| b != 0).map_or(1, |i| i + 1);
                value.truncate(end);
            }
        }
        Self {
            value,
            negative: false,
            byte_order,
        }
    }

    /// Creates a number from the bytes of its absolute value in `byte_order` and its sign,
    /// dropping the high zero bytes as [`new`](Self::new) does.
    ///
    /// The number is negative when `negative` is set and the bytes are not all zero: zero is
    /// never negative.
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// let n = Number::new_signed(vec![0, 1, 0], true, ByteOrder::BigEndian);
    /// assert_eq!(n.value, [1, 0]);
    /// assert!(n.is_negative());
    ///
    /// let zero = Number::new_signed(vec![0, 0], true, ByteOrder::BigEndian);
    /// assert_eq!(zero.value, [0]);
    /// assert!(!zero.is_negative());
    /// ```
    pub fn new_signed(value: Vec<u8>, negative: bool, byte_order: ByteOrder) -> Self {
        let number = Self::new(value, byte_order);
        // Once trimmed, zero is `[0]` or `[]` in either order: it keeps the sign of `new`.
        let negative = negative && !matches!(number.value.as_slice(), [] | [0]);
        Self { negative, ..number }
    }

    /// Creates a number from a `u8`, its only byte. Zero is kept as `[0]`.
    pub fn new_from_u8(value: u8, byte_order: ByteOrder) -> Self {
        Self::new(vec![value], byte_order)
    }

    /// Creates a number from the bytes of a `u16` in `byte_order`, without the high zero
    /// bytes (see [`new`](Self::new)).
    pub fn new_from_u16(value: u16, byte_order: ByteOrder) -> Self {
        let bytes = match byte_order {
            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
        };
        Self::new(bytes, byte_order)
    }

    /// Creates a number from the bytes of a `u32` in `byte_order`, without the high zero
    /// bytes (see [`new`](Self::new)).
    pub fn new_from_u32(value: u32, byte_order: ByteOrder) -> Self {
        let bytes = match byte_order {
            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
        };
        Self::new(bytes, byte_order)
    }

    /// Creates a number from the bytes of a `u64` in `byte_order`, without the high zero
    /// bytes (see [`new`](Self::new)).
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// let n = Number::new_from_u64(0x0A0B_0C0D, ByteOrder::BigEndian);
    /// assert_eq!(n.value, [0x0A, 0x0B, 0x0C, 0x0D]);
    ///
    /// let n = Number::new_from_u64(0x0A0B_0C0D, ByteOrder::LittleEndian);
    /// assert_eq!(n.value, [0x0D, 0x0C, 0x0B, 0x0A]);
    ///
    /// let zero = Number::new_from_u64(0, ByteOrder::LittleEndian);
    /// assert_eq!(zero.value, [0]);
    /// ```
    pub fn new_from_u64(value: u64, byte_order: ByteOrder) -> Self {
        let bytes = match byte_order {
            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
        };
        Self::new(bytes, byte_order)
    }

    /// Creates a number from the bytes of a `u128` in `byte_order`, without the high zero
    /// bytes (see [`new`](Self::new)).
    pub fn new_from_u128(value: u128, byte_order: ByteOrder) -> Self {
        let bytes = match byte_order {
            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
        };
        Self::new(bytes, byte_order)
    }

    /// Creates a number from the bytes of a `usize` in `byte_order`, without the high zero
    /// bytes (see [`new`](Self::new)).
    ///
    /// `usize` is as wide as a pointer, but as the high zero bytes are dropped, a value has
    /// the same bytes on every target.
    pub fn new_from_usize(value: usize, byte_order: ByteOrder) -> Self {
        let bytes = match byte_order {
            ByteOrder::BigEndian => value.to_be_bytes().to_vec(),
            ByteOrder::LittleEndian => value.to_le_bytes().to_vec(),
        };
        Self::new(bytes, byte_order)
    }

    /// Creates a non-negative number from bytes given as `i8`s in `byte_order`, without the
    /// high zero bytes (see [`new`](Self::new)).
    ///
    /// The `i8`s are only how the bytes are given, not signed digits: each one is the byte
    /// with the same bits (`-1` is `0xFF`, `-128` is `0x80`), and the number is never
    /// negative.
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// let n = Number::new_from_i8_vec(vec![0, -1, 1], ByteOrder::BigEndian);
    /// assert_eq!(n.value, [0xFF, 0x01]);
    /// assert!(!n.is_negative());
    /// ```
    pub fn new_from_i8_vec(value: Vec<i8>, byte_order: ByteOrder) -> Self {
        Self::new(value.iter().map(|&x| x as u8).collect(), byte_order)
    }

    /// Creates a number from an `i8`: its sign, and its absolute value as the only byte.
    /// `i8::MIN` becomes `[0x80]` with `negative` set. Zero is kept as `[0]`.
    pub fn new_from_i8(value: i8, byte_order: ByteOrder) -> Self {
        // `unsigned_abs` is exact for every value, `MIN` included, whose absolute value does
        // not fit in the signed type; the same holds for the wider types below.
        Self {
            negative: value < 0,
            ..Self::new_from_u8(value.unsigned_abs(), byte_order)
        }
    }

    /// Creates a number from an `i16`: its sign, and the bytes of its absolute value in
    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// let n = Number::new_from_i16(-2, ByteOrder::BigEndian);
    /// assert_eq!(n.value, [0x02]);
    /// assert!(n.is_negative());
    ///
    /// let n = Number::new_from_i16(i16::MIN, ByteOrder::BigEndian);
    /// assert_eq!(n.value, [0x80, 0x00]);
    /// assert!(n.is_negative());
    /// ```
    pub fn new_from_i16(value: i16, byte_order: ByteOrder) -> Self {
        Self {
            negative: value < 0,
            ..Self::new_from_u16(value.unsigned_abs(), byte_order)
        }
    }

    /// Creates a number from an `i32`: its sign, and the bytes of its absolute value in
    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
    pub fn new_from_i32(value: i32, byte_order: ByteOrder) -> Self {
        Self {
            negative: value < 0,
            ..Self::new_from_u32(value.unsigned_abs(), byte_order)
        }
    }

    /// Creates a number from an `i64`: its sign, and the bytes of its absolute value in
    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
    pub fn new_from_i64(value: i64, byte_order: ByteOrder) -> Self {
        Self {
            negative: value < 0,
            ..Self::new_from_u64(value.unsigned_abs(), byte_order)
        }
    }

    /// Creates a number from an `i128`: its sign, and the bytes of its absolute value in
    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
    pub fn new_from_i128(value: i128, byte_order: ByteOrder) -> Self {
        Self {
            negative: value < 0,
            ..Self::new_from_u128(value.unsigned_abs(), byte_order)
        }
    }

    /// Creates a number from an `isize`: its sign, and the bytes of its absolute value in
    /// `byte_order` without the high zero bytes (see [`new`](Self::new)).
    ///
    /// As for [`new_from_usize`](Self::new_from_usize), a value has the same bytes on every
    /// target.
    pub fn new_from_isize(value: isize, byte_order: ByteOrder) -> Self {
        Self {
            negative: value < 0,
            ..Self::new_from_usize(value.unsigned_abs(), byte_order)
        }
    }

    /// Creates a non-negative number from the UTF-8 bytes of a string, read in `byte_order`,
    /// without the high zero bytes (see [`new`](Self::new)).
    ///
    /// The string is not parsed as digits: its bytes are the number, the way textbook RSA
    /// turns a message into an integer, so a leading `'-'` is the byte `0x2D`, not a sign.
    /// In big-endian order the first byte of the string is the most significant one, and
    /// leading `'\0'` characters are dropped as zero bytes; in little-endian order the first
    /// byte is the least significant one, and trailing `'\0'` characters are dropped. An empty
    /// string gives an empty `value`.
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// // 0x31_32_33 = 3,224,115, not 123.
    /// let n = Number::new_from_str("123", ByteOrder::BigEndian);
    /// assert_eq!(n.value, [0x31, 0x32, 0x33]);
    /// ```
    pub fn new_from_str(value: &str, byte_order: ByteOrder) -> Self {
        Self::new(value.as_bytes().to_vec(), byte_order)
    }

    /// Returns whether the number is below zero.
    ///
    /// It reads `negative`, as the constructors and the operators keep it: never set for zero. A
    /// number built directly from its fields is stored as given, and a zero magnitude with
    /// `negative` set says it is negative here, though it is zero to the comparisons and the
    /// arithmetic, and to [`is_zero`](Self::is_zero) and [`signum`](Self::signum).
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// assert!(Number::new_from_i32(-7, ByteOrder::BigEndian).is_negative());
    /// assert!(!Number::new_from_i32(7, ByteOrder::BigEndian).is_negative());
    /// assert!(!Number::new_from_i32(0, ByteOrder::BigEndian).is_negative());
    /// ```
    pub fn is_negative(&self) -> bool {
        self.negative
    }

    /// Returns the order of the bytes in `value`.
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// let n = Number::new_from_u8(7, ByteOrder::LittleEndian);
    /// assert!(n.byte_order() == ByteOrder::LittleEndian);
    /// ```
    pub fn byte_order(&self) -> ByteOrder {
        self.byte_order
    }
}

impl Clone for Number {
    /// Returns a copy of the number, its bytes exactly as they are stored, high zero bytes
    /// included, in a new vector of their length.
    #[inline]
    fn clone(&self) -> Self {
        Number {
            value: self.value.clone(),
            negative: self.negative,
            byte_order: self.byte_order,
        }
    }

    /// Makes `self` a copy of `source`, in the vector of `self` when it has room.
    #[inline]
    fn clone_from(&mut self, source: &Self) {
        self.value.clone_from(&source.value);
        self.negative = source.negative;
        self.byte_order = source.byte_order;
    }
}

impl Default for Number {
    /// Returns zero, little-endian, with an empty vector, which allocates nothing: `mem::take` of
    /// a number leaves this behind. Little-endian is the order of the limbs of the arithmetic on
    /// every target this crate has kernels for: the kernels read and write its bytes as limbs as
    /// they are, where big-endian bytes are turned around.
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// let zero = Number::default();
    /// assert!(zero.is_zero());
    /// assert!(zero.byte_order() == ByteOrder::LittleEndian);
    /// assert_eq!(zero.value.capacity(), 0);
    /// ```
    #[inline]
    fn default() -> Self {
        Number {
            value: Vec::new(),
            negative: false,
            byte_order: ByteOrder::LittleEndian,
        }
    }
}

impl fmt::Debug for Number {
    /// Writes the number in decimal, as [`Display`](fmt::Display) does, so that numbers that are
    /// equal look alike; the bytes are in the public fields.
    ///
    /// # Examples
    ///
    /// ```
    /// use a::math::numbers::{ByteOrder, Number};
    ///
    /// let n = Number::new_from_i32(-1000, ByteOrder::BigEndian);
    /// assert_eq!(format!("{n:?}"), "-1000");
    /// assert_eq!(format!("{:?}", [n]), "[-1000]");
    /// ```
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(self, f)
    }
}