ring/
limb.rs

1// Copyright 2016 David Judd.
2// Copyright 2016 Brian Smith.
3//
4// Permission to use, copy, modify, and/or distribute this software for any
5// purpose with or without fee is hereby granted, provided that the above
6// copyright notice and this permission notice appear in all copies.
7//
8// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHORS DISCLAIM ALL WARRANTIES
9// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY
11// SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
13// OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14// CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15
16//! Unsigned multi-precision integer arithmetic.
17//!
18//! Limbs ordered least-significant-limb to most-significant-limb. The bits
19//! limbs use the native endianness.
20
21use crate::{c, error};
22
23#[cfg(feature = "alloc")]
24use crate::bits;
25
26#[cfg(feature = "alloc")]
27use core::num::Wrapping;
28
29// XXX: Not correct for x32 ABIs.
30#[cfg(target_pointer_width = "64")]
31pub type Limb = u64;
32#[cfg(target_pointer_width = "32")]
33pub type Limb = u32;
34#[cfg(target_pointer_width = "64")]
35pub const LIMB_BITS: usize = 64;
36#[cfg(target_pointer_width = "32")]
37pub const LIMB_BITS: usize = 32;
38
39#[cfg(target_pointer_width = "64")]
40#[derive(Debug, PartialEq)]
41#[repr(u64)]
42pub enum LimbMask {
43    True = 0xffff_ffff_ffff_ffff,
44    False = 0,
45}
46
47#[cfg(target_pointer_width = "32")]
48#[derive(Debug, PartialEq)]
49#[repr(u32)]
50pub enum LimbMask {
51    True = 0xffff_ffff,
52    False = 0,
53}
54
55pub const LIMB_BYTES: usize = (LIMB_BITS + 7) / 8;
56
57#[inline]
58pub fn limbs_equal_limbs_consttime(a: &[Limb], b: &[Limb]) -> LimbMask {
59    extern "C" {
60        fn LIMBS_equal(a: *const Limb, b: *const Limb, num_limbs: c::size_t) -> LimbMask;
61    }
62
63    assert_eq!(a.len(), b.len());
64    unsafe { LIMBS_equal(a.as_ptr(), b.as_ptr(), a.len()) }
65}
66
67#[inline]
68pub fn limbs_less_than_limbs_consttime(a: &[Limb], b: &[Limb]) -> LimbMask {
69    assert_eq!(a.len(), b.len());
70    unsafe { LIMBS_less_than(a.as_ptr(), b.as_ptr(), b.len()) }
71}
72
73#[inline]
74pub fn limbs_less_than_limbs_vartime(a: &[Limb], b: &[Limb]) -> bool {
75    limbs_less_than_limbs_consttime(a, b) == LimbMask::True
76}
77
78#[inline]
79#[cfg(feature = "alloc")]
80pub fn limbs_less_than_limb_constant_time(a: &[Limb], b: Limb) -> LimbMask {
81    unsafe { LIMBS_less_than_limb(a.as_ptr(), b, a.len()) }
82}
83
84#[inline]
85pub fn limbs_are_zero_constant_time(limbs: &[Limb]) -> LimbMask {
86    unsafe { LIMBS_are_zero(limbs.as_ptr(), limbs.len()) }
87}
88
89#[cfg(feature = "alloc")]
90#[inline]
91pub fn limbs_are_even_constant_time(limbs: &[Limb]) -> LimbMask {
92    unsafe { LIMBS_are_even(limbs.as_ptr(), limbs.len()) }
93}
94
95#[cfg(feature = "alloc")]
96#[inline]
97pub fn limbs_equal_limb_constant_time(a: &[Limb], b: Limb) -> LimbMask {
98    unsafe { LIMBS_equal_limb(a.as_ptr(), b, a.len()) }
99}
100
101/// Returns the number of bits in `a`.
102//
103// This strives to be constant-time with respect to the values of all bits
104// except the most significant bit. This does not attempt to be constant-time
105// with respect to `a.len()` or the value of the result or the value of the
106// most significant bit (It's 1, unless the input is zero, in which case it's
107// zero.)
108#[cfg(feature = "alloc")]
109pub fn limbs_minimal_bits(a: &[Limb]) -> bits::BitLength {
110    for num_limbs in (1..=a.len()).rev() {
111        let high_limb = a[num_limbs - 1];
112
113        // Find the number of set bits in |high_limb| by a linear scan from the
114        // most significant bit to the least significant bit. This works great
115        // for the most common inputs because usually the most significant bit
116        // it set.
117        for high_limb_num_bits in (1..=LIMB_BITS).rev() {
118            let shifted = unsafe { LIMB_shr(high_limb, high_limb_num_bits - 1) };
119            if shifted != 0 {
120                return bits::BitLength::from_usize_bits(
121                    ((num_limbs - 1) * LIMB_BITS) + high_limb_num_bits,
122                );
123            }
124        }
125    }
126
127    // No bits were set.
128    bits::BitLength::from_usize_bits(0)
129}
130
131/// Equivalent to `if (r >= m) { r -= m; }`
132#[inline]
133pub fn limbs_reduce_once_constant_time(r: &mut [Limb], m: &[Limb]) {
134    assert_eq!(r.len(), m.len());
135    unsafe { LIMBS_reduce_once(r.as_mut_ptr(), m.as_ptr(), m.len()) };
136}
137
138#[derive(Clone, Copy, PartialEq)]
139pub enum AllowZero {
140    No,
141    Yes,
142}
143
144/// Parses `input` into `result`, reducing it via conditional subtraction
145/// (mod `m`). Assuming 2**((self.num_limbs * LIMB_BITS) - 1) < m and
146/// m < 2**(self.num_limbs * LIMB_BITS), the value will be reduced mod `m` in
147/// constant time so that the result is in the range [0, m) if `allow_zero` is
148/// `AllowZero::Yes`, or [1, m) if `allow_zero` is `AllowZero::No`. `result` is
149/// padded with zeros to its length.
150pub fn parse_big_endian_in_range_partially_reduced_and_pad_consttime(
151    input: untrusted::Input,
152    allow_zero: AllowZero,
153    m: &[Limb],
154    result: &mut [Limb],
155) -> Result<(), error::Unspecified> {
156    parse_big_endian_and_pad_consttime(input, result)?;
157    limbs_reduce_once_constant_time(result, m);
158    if allow_zero != AllowZero::Yes {
159        if limbs_are_zero_constant_time(&result) != LimbMask::False {
160            return Err(error::Unspecified);
161        }
162    }
163    Ok(())
164}
165
166/// Parses `input` into `result`, verifies that the value is less than
167/// `max_exclusive`, and pads `result` with zeros to its length. If `allow_zero`
168/// is not `AllowZero::Yes`, zero values are rejected.
169///
170/// This attempts to be constant-time with respect to the actual value *only if*
171/// the value is actually in range. In other words, this won't leak anything
172/// about a valid value, but it might leak small amounts of information about an
173/// invalid value (which constraint it failed).
174pub fn parse_big_endian_in_range_and_pad_consttime(
175    input: untrusted::Input,
176    allow_zero: AllowZero,
177    max_exclusive: &[Limb],
178    result: &mut [Limb],
179) -> Result<(), error::Unspecified> {
180    parse_big_endian_and_pad_consttime(input, result)?;
181    if limbs_less_than_limbs_consttime(&result, max_exclusive) != LimbMask::True {
182        return Err(error::Unspecified);
183    }
184    if allow_zero != AllowZero::Yes {
185        if limbs_are_zero_constant_time(&result) != LimbMask::False {
186            return Err(error::Unspecified);
187        }
188    }
189    Ok(())
190}
191
192/// Parses `input` into `result`, padding `result` with zeros to its length.
193/// This attempts to be constant-time with respect to the value but not with
194/// respect to the length; it is assumed that the length is public knowledge.
195pub fn parse_big_endian_and_pad_consttime(
196    input: untrusted::Input,
197    result: &mut [Limb],
198) -> Result<(), error::Unspecified> {
199    if input.is_empty() {
200        return Err(error::Unspecified);
201    }
202
203    // `bytes_in_current_limb` is the number of bytes in the current limb.
204    // It will be `LIMB_BYTES` for all limbs except maybe the highest-order
205    // limb.
206    let mut bytes_in_current_limb = input.len() % LIMB_BYTES;
207    if bytes_in_current_limb == 0 {
208        bytes_in_current_limb = LIMB_BYTES;
209    }
210
211    let num_encoded_limbs = (input.len() / LIMB_BYTES)
212        + (if bytes_in_current_limb == LIMB_BYTES {
213            0
214        } else {
215            1
216        });
217    if num_encoded_limbs > result.len() {
218        return Err(error::Unspecified);
219    }
220
221    for r in &mut result[..] {
222        *r = 0;
223    }
224
225    // XXX: Questionable as far as constant-timedness is concerned.
226    // TODO: Improve this.
227    input.read_all(error::Unspecified, |input| {
228        for i in 0..num_encoded_limbs {
229            let mut limb: Limb = 0;
230            for _ in 0..bytes_in_current_limb {
231                let b: Limb = input.read_byte()?.into();
232                limb = (limb << 8) | b;
233            }
234            result[num_encoded_limbs - i - 1] = limb;
235            bytes_in_current_limb = LIMB_BYTES;
236        }
237        Ok(())
238    })
239}
240
241pub fn big_endian_from_limbs(limbs: &[Limb], out: &mut [u8]) {
242    let num_limbs = limbs.len();
243    let out_len = out.len();
244    assert_eq!(out_len, num_limbs * LIMB_BYTES);
245    for i in 0..num_limbs {
246        let mut limb = limbs[i];
247        for j in 0..LIMB_BYTES {
248            out[((num_limbs - i - 1) * LIMB_BYTES) + (LIMB_BYTES - j - 1)] = (limb & 0xff) as u8;
249            limb >>= 8;
250        }
251    }
252}
253
254#[cfg(feature = "alloc")]
255pub type Window = Limb;
256
257/// Processes `limbs` as a sequence of 5-bit windows, folding the windows from
258/// most significant to least significant and returning the accumulated result.
259/// The first window will be mapped by `init` to produce the initial value for
260/// the accumulator. Then `f` will be called to fold the accumulator and the
261/// next window until all windows are processed. When the input's bit length
262/// isn't divisible by 5, the window passed to `init` will be partial; all
263/// windows passed to `fold` will be full.
264///
265/// This is designed to avoid leaking the contents of `limbs` through side
266/// channels as long as `init` and `fold` are side-channel free.
267///
268/// Panics if `limbs` is empty.
269#[cfg(feature = "alloc")]
270pub fn fold_5_bit_windows<R, I: FnOnce(Window) -> R, F: Fn(R, Window) -> R>(
271    limbs: &[Limb],
272    init: I,
273    fold: F,
274) -> R {
275    #[derive(Clone, Copy)]
276    #[repr(transparent)]
277    struct BitIndex(Wrapping<c::size_t>);
278
279    const WINDOW_BITS: Wrapping<c::size_t> = Wrapping(5);
280
281    extern "C" {
282        fn LIMBS_window5_split_window(
283            lower_limb: Limb,
284            higher_limb: Limb,
285            index_within_word: BitIndex,
286        ) -> Window;
287        fn LIMBS_window5_unsplit_window(limb: Limb, index_within_word: BitIndex) -> Window;
288    }
289
290    let num_limbs = limbs.len();
291    let mut window_low_bit = {
292        let num_whole_windows = (num_limbs * LIMB_BITS) / 5;
293        let mut leading_bits = (num_limbs * LIMB_BITS) - (num_whole_windows * 5);
294        if leading_bits == 0 {
295            leading_bits = WINDOW_BITS.0;
296        }
297        BitIndex(Wrapping(LIMB_BITS - leading_bits))
298    };
299
300    let initial_value = {
301        let leading_partial_window =
302            unsafe { LIMBS_window5_split_window(*limbs.last().unwrap(), 0, window_low_bit) };
303        window_low_bit.0 -= WINDOW_BITS;
304        init(leading_partial_window)
305    };
306
307    let mut low_limb = 0;
308    limbs
309        .iter()
310        .rev()
311        .fold(initial_value, |mut acc, current_limb| {
312            let higher_limb = low_limb;
313            low_limb = *current_limb;
314
315            if window_low_bit.0 > Wrapping(LIMB_BITS) - WINDOW_BITS {
316                let window =
317                    unsafe { LIMBS_window5_split_window(low_limb, higher_limb, window_low_bit) };
318                window_low_bit.0 -= WINDOW_BITS;
319                acc = fold(acc, window);
320            };
321            while window_low_bit.0 < Wrapping(LIMB_BITS) {
322                let window = unsafe { LIMBS_window5_unsplit_window(low_limb, window_low_bit) };
323                // The loop exits when this subtraction underflows, causing `window_low_bit` to
324                // wrap around to a very large value.
325                window_low_bit.0 -= WINDOW_BITS;
326                acc = fold(acc, window);
327            }
328            window_low_bit.0 += Wrapping(LIMB_BITS); // "Fix" the underflow.
329
330            acc
331        })
332}
333
334extern "C" {
335    #[cfg(feature = "alloc")]
336    fn LIMB_shr(a: Limb, shift: c::size_t) -> Limb;
337
338    #[cfg(feature = "alloc")]
339    fn LIMBS_are_even(a: *const Limb, num_limbs: c::size_t) -> LimbMask;
340    fn LIMBS_are_zero(a: *const Limb, num_limbs: c::size_t) -> LimbMask;
341    #[cfg(feature = "alloc")]
342    fn LIMBS_equal_limb(a: *const Limb, b: Limb, num_limbs: c::size_t) -> LimbMask;
343    fn LIMBS_less_than(a: *const Limb, b: *const Limb, num_limbs: c::size_t) -> LimbMask;
344    #[cfg(feature = "alloc")]
345    fn LIMBS_less_than_limb(a: *const Limb, b: Limb, num_limbs: c::size_t) -> LimbMask;
346    fn LIMBS_reduce_once(r: *mut Limb, m: *const Limb, num_limbs: c::size_t);
347}
348
349#[cfg(test)]
350mod tests {
351    use super::*;
352
353    const MAX: Limb = LimbMask::True as Limb;
354
355    #[test]
356    fn test_limbs_are_even() {
357        static EVENS: &[&[Limb]] = &[
358            &[],
359            &[0],
360            &[2],
361            &[0, 0],
362            &[2, 0],
363            &[0, 1],
364            &[0, 2],
365            &[0, 3],
366            &[0, 0, 0, 0, MAX],
367        ];
368        for even in EVENS {
369            assert_eq!(limbs_are_even_constant_time(even), LimbMask::True);
370        }
371        static ODDS: &[&[Limb]] = &[
372            &[1],
373            &[3],
374            &[1, 0],
375            &[3, 0],
376            &[1, 1],
377            &[1, 2],
378            &[1, 3],
379            &[1, 0, 0, 0, MAX],
380        ];
381        for odd in ODDS {
382            assert_eq!(limbs_are_even_constant_time(odd), LimbMask::False);
383        }
384    }
385
386    static ZEROES: &[&[Limb]] = &[
387        &[],
388        &[0],
389        &[0, 0],
390        &[0, 0, 0],
391        &[0, 0, 0, 0],
392        &[0, 0, 0, 0, 0],
393        &[0, 0, 0, 0, 0, 0, 0],
394        &[0, 0, 0, 0, 0, 0, 0, 0],
395        &[0, 0, 0, 0, 0, 0, 0, 0, 0],
396    ];
397
398    static NONZEROES: &[&[Limb]] = &[
399        &[1],
400        &[0, 1],
401        &[1, 1],
402        &[1, 0, 0, 0],
403        &[0, 1, 0, 0],
404        &[0, 0, 1, 0],
405        &[0, 0, 0, 1],
406    ];
407
408    #[test]
409    fn test_limbs_are_zero() {
410        for zero in ZEROES {
411            assert_eq!(limbs_are_zero_constant_time(zero), LimbMask::True);
412        }
413        for nonzero in NONZEROES {
414            assert_eq!(limbs_are_zero_constant_time(nonzero), LimbMask::False);
415        }
416    }
417
418    #[test]
419    fn test_limbs_equal_limb() {
420        for zero in ZEROES {
421            assert_eq!(limbs_equal_limb_constant_time(zero, 0), LimbMask::True);
422        }
423        for nonzero in NONZEROES {
424            assert_eq!(limbs_equal_limb_constant_time(nonzero, 0), LimbMask::False);
425        }
426        static EQUAL: &[(&[Limb], Limb)] = &[
427            (&[1], 1),
428            (&[MAX], MAX),
429            (&[1, 0], 1),
430            (&[MAX, 0, 0], MAX),
431            (&[0b100], 0b100),
432            (&[0b100, 0], 0b100),
433        ];
434        for &(a, b) in EQUAL {
435            assert_eq!(limbs_equal_limb_constant_time(a, b), LimbMask::True);
436        }
437        static UNEQUAL: &[(&[Limb], Limb)] = &[
438            (&[0], 1),
439            (&[2], 1),
440            (&[3], 1),
441            (&[1, 1], 1),
442            (&[0b100, 0b100], 0b100),
443            (&[1, 0, 0b100, 0, 0, 0, 0, 0], 1),
444            (&[1, 0, 0, 0, 0, 0, 0, 0b100], 1),
445            (&[MAX, MAX], MAX),
446            (&[MAX, 1], MAX),
447        ];
448        for &(a, b) in UNEQUAL {
449            assert_eq!(limbs_equal_limb_constant_time(a, b), LimbMask::False);
450        }
451    }
452
453    #[test]
454    #[cfg(feature = "alloc")]
455    fn test_limbs_less_than_limb_constant_time() {
456        static LESSER: &[(&[Limb], Limb)] = &[
457            (&[0], 1),
458            (&[0, 0], 1),
459            (&[1, 0], 2),
460            (&[2, 0], 3),
461            (&[2, 0], 3),
462            (&[MAX - 1], MAX),
463            (&[MAX - 1, 0], MAX),
464        ];
465        for &(a, b) in LESSER {
466            assert_eq!(limbs_less_than_limb_constant_time(a, b), LimbMask::True);
467        }
468        static EQUAL: &[(&[Limb], Limb)] = &[
469            (&[0], 0),
470            (&[0, 0, 0, 0], 0),
471            (&[1], 1),
472            (&[1, 0, 0, 0, 0, 0, 0], 1),
473            (&[MAX], MAX),
474        ];
475        static GREATER: &[(&[Limb], Limb)] = &[
476            (&[1], 0),
477            (&[2, 0], 1),
478            (&[3, 0, 0, 0], 1),
479            (&[0, 1, 0, 0], 1),
480            (&[0, 0, 1, 0], 1),
481            (&[0, 0, 1, 1], 1),
482            (&[MAX], MAX - 1),
483        ];
484        for &(a, b) in EQUAL.iter().chain(GREATER.iter()) {
485            assert_eq!(limbs_less_than_limb_constant_time(a, b), LimbMask::False);
486        }
487    }
488
489    #[test]
490    fn test_parse_big_endian_and_pad_consttime() {
491        const LIMBS: usize = 4;
492
493        {
494            // Empty input.
495            let inp = untrusted::Input::from(&[]);
496            let mut result = [0; LIMBS];
497            assert!(parse_big_endian_and_pad_consttime(inp, &mut result).is_err());
498        }
499
500        // The input is longer than will fit in the given number of limbs.
501        {
502            let inp = [1, 2, 3, 4, 5, 6, 7, 8, 9];
503            let inp = untrusted::Input::from(&inp);
504            let mut result = [0; 8 / LIMB_BYTES];
505            assert!(parse_big_endian_and_pad_consttime(inp, &mut result[..]).is_err());
506        }
507
508        // Less than a full limb.
509        {
510            let inp = [0xfe];
511            let inp = untrusted::Input::from(&inp);
512            let mut result = [0; LIMBS];
513            assert_eq!(
514                Ok(()),
515                parse_big_endian_and_pad_consttime(inp, &mut result[..])
516            );
517            assert_eq!(&[0xfe, 0, 0, 0], &result);
518        }
519
520        // A whole limb for 32-bit, half a limb for 64-bit.
521        {
522            let inp = [0xbe, 0xef, 0xf0, 0x0d];
523            let inp = untrusted::Input::from(&inp);
524            let mut result = [0; LIMBS];
525            assert_eq!(Ok(()), parse_big_endian_and_pad_consttime(inp, &mut result));
526            assert_eq!(&[0xbeeff00d, 0, 0, 0], &result);
527        }
528
529        // XXX: This is a weak set of tests. TODO: expand it.
530    }
531
532    #[test]
533    fn test_big_endian_from_limbs_same_length() {
534        #[cfg(target_pointer_width = "32")]
535        let limbs = [
536            0xbccddeef, 0x89900aab, 0x45566778, 0x01122334, 0xddeeff00, 0x99aabbcc, 0x55667788,
537            0x11223344,
538        ];
539
540        #[cfg(target_pointer_width = "64")]
541        let limbs = [
542            0x8990_0aab_bccd_deef,
543            0x0112_2334_4556_6778,
544            0x99aa_bbcc_ddee_ff00,
545            0x1122_3344_5566_7788,
546        ];
547
548        let expected = [
549            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
550            0xff, 0x00, 0x01, 0x12, 0x23, 0x34, 0x45, 0x56, 0x67, 0x78, 0x89, 0x90, 0x0a, 0xab,
551            0xbc, 0xcd, 0xde, 0xef,
552        ];
553
554        let mut out = [0xabu8; 32];
555        big_endian_from_limbs(&limbs[..], &mut out);
556        assert_eq!(&out[..], &expected[..]);
557    }
558
559    #[should_panic]
560    #[test]
561    fn test_big_endian_from_limbs_fewer_limbs() {
562        #[cfg(target_pointer_width = "32")]
563        // Two fewer limbs.
564        let limbs = [
565            0xbccddeef, 0x89900aab, 0x45566778, 0x01122334, 0xddeeff00, 0x99aabbcc,
566        ];
567
568        // One fewer limb.
569        #[cfg(target_pointer_width = "64")]
570        let limbs = [
571            0x8990_0aab_bccd_deef,
572            0x0112_2334_4556_6778,
573            0x99aa_bbcc_ddee_ff00,
574        ];
575
576        let mut out = [0xabu8; 32];
577
578        big_endian_from_limbs(&limbs[..], &mut out);
579    }
580
581    #[test]
582    fn test_limbs_minimal_bits() {
583        const ALL_ONES: Limb = LimbMask::True as Limb;
584        static CASES: &[(&[Limb], usize)] = &[
585            (&[], 0),
586            (&[0], 0),
587            (&[ALL_ONES], LIMB_BITS),
588            (&[ALL_ONES, 0], LIMB_BITS),
589            (&[ALL_ONES, 1], LIMB_BITS + 1),
590            (&[0, 0], 0),
591            (&[1, 0], 1),
592            (&[0, 1], LIMB_BITS + 1),
593            (&[0, ALL_ONES], 2 * LIMB_BITS),
594            (&[ALL_ONES, ALL_ONES], 2 * LIMB_BITS),
595            (&[ALL_ONES, ALL_ONES >> 1], 2 * LIMB_BITS - 1),
596            (&[ALL_ONES, 0b100_0000], LIMB_BITS + 7),
597            (&[ALL_ONES, 0b101_0000], LIMB_BITS + 7),
598            (&[ALL_ONES, ALL_ONES >> 1], LIMB_BITS + (LIMB_BITS) - 1),
599        ];
600        for (limbs, bits) in CASES {
601            assert_eq!(limbs_minimal_bits(limbs).as_usize_bits(), *bits);
602        }
603    }
604}