|
13 | 13 | #![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
|
14 | 14 | #![cfg_attr(feature = "nightly", deny(missing_docs))]
|
15 | 15 | #![doc(html_logo_url = "https://doc.dalek.rs/assets/dalek-logo-clear.png")]
|
16 |
| -#![doc(html_root_url = "https://docs.rs/subtle/2.3.0")] |
| 16 | +#![doc(html_root_url = "https://docs.rs/subtle/2.4.0")] |
17 | 17 |
|
18 | 18 | //! Note that docs will only build on nightly Rust until
|
19 | 19 | //! [RFC 1990 stabilizes](https://github.com/rust-lang/rust/issues/44732).
|
|
22 | 22 | #[macro_use]
|
23 | 23 | extern crate std;
|
24 | 24 |
|
| 25 | +#[cfg(test)] |
| 26 | +extern crate rand; |
| 27 | + |
25 | 28 | use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Neg, Not};
|
26 | 29 | use core::option::Option;
|
27 | 30 |
|
@@ -664,3 +667,136 @@ impl<T: ConstantTimeEq> ConstantTimeEq for CtOption<T> {
|
664 | 667 | (a & b & self.value.ct_eq(&rhs.value)) | (!a & !b)
|
665 | 668 | }
|
666 | 669 | }
|
| 670 | + |
| 671 | +/// A type which can be compared in some manner and be determined to be greater |
| 672 | +/// than another of the same type. |
| 673 | +pub trait ConstantTimeGreater { |
| 674 | + /// Determine whether `self > other`. |
| 675 | + /// |
| 676 | + /// The bitwise-NOT of the return value of this function should be usable to |
| 677 | + /// determine if `self <= other`. |
| 678 | + /// |
| 679 | + /// This function should execute in constant time. |
| 680 | + /// |
| 681 | + /// # Returns |
| 682 | + /// |
| 683 | + /// A `Choice` with a set bit if `self > other`, and with no set bits |
| 684 | + /// otherwise. |
| 685 | + /// |
| 686 | + /// # Example |
| 687 | + /// |
| 688 | + /// ``` |
| 689 | + /// # extern crate subtle; |
| 690 | + /// use subtle::ConstantTimeGreater; |
| 691 | + /// |
| 692 | + /// let x: u8 = 13; |
| 693 | + /// let y: u8 = 42; |
| 694 | + /// |
| 695 | + /// let x_gt_y = x.ct_gt(&y); |
| 696 | + /// |
| 697 | + /// assert_eq!(x_gt_y.unwrap_u8(), 0); |
| 698 | + /// |
| 699 | + /// let y_gt_x = y.ct_gt(&x); |
| 700 | + /// |
| 701 | + /// assert_eq!(y_gt_x.unwrap_u8(), 1); |
| 702 | + /// |
| 703 | + /// let x_gt_x = x.ct_gt(&x); |
| 704 | + /// |
| 705 | + /// assert_eq!(x_gt_x.unwrap_u8(), 0); |
| 706 | + /// ``` |
| 707 | + fn ct_gt(&self, other: &Self) -> Choice; |
| 708 | +} |
| 709 | + |
| 710 | +macro_rules! generate_unsigned_integer_greater { |
| 711 | + ($t_u: ty, $bit_width: expr) => { |
| 712 | + impl ConstantTimeGreater for $t_u { |
| 713 | + /// Returns Choice::from(1) iff x > y, and Choice::from(0) iff x <= y. |
| 714 | + /// |
| 715 | + /// # Note |
| 716 | + /// |
| 717 | + /// This algoritm would also work for signed integers if we first |
| 718 | + /// flip the top bit, e.g. `let x: u8 = x ^ 0x80`, etc. |
| 719 | + #[inline] |
| 720 | + fn ct_gt(&self, other: &$t_u) -> Choice { |
| 721 | + let gtb = self & !other; // All the bits in self that are greater than their corresponding bits in other. |
| 722 | + let mut ltb = !self & other; // All the bits in self that are less than their corresponding bits in other. |
| 723 | + let mut pow = 1; |
| 724 | + |
| 725 | + // Less-than operator is okay here because it's dependent on the bit-width. |
| 726 | + while pow < $bit_width { |
| 727 | + ltb |= ltb >> pow; // Bit-smear the highest set bit to the right. |
| 728 | + pow += pow; |
| 729 | + } |
| 730 | + let mut bit = gtb & !ltb; // Select the highest set bit. |
| 731 | + let mut pow = 1; |
| 732 | + |
| 733 | + while pow < $bit_width { |
| 734 | + bit |= bit >> pow; // Shift it to the right until we end up with either 0 or 1. |
| 735 | + pow += pow; |
| 736 | + } |
| 737 | + // XXX We should possibly do the above flattening to 0 or 1 in the |
| 738 | + // Choice constructor rather than making it a debug error? |
| 739 | + Choice::from((bit & 1) as u8) |
| 740 | + } |
| 741 | + } |
| 742 | + } |
| 743 | +} |
| 744 | + |
| 745 | +generate_unsigned_integer_greater!(u8, 8); |
| 746 | +generate_unsigned_integer_greater!(u16, 16); |
| 747 | +generate_unsigned_integer_greater!(u32, 32); |
| 748 | +generate_unsigned_integer_greater!(u64, 64); |
| 749 | +#[cfg(feature = "i128")] |
| 750 | +generate_unsigned_integer_greater!(u128, 128); |
| 751 | + |
| 752 | +/// A type which can be compared in some manner and be determined to be less |
| 753 | +/// than another of the same type. |
| 754 | +pub trait ConstantTimeLess: ConstantTimeEq + ConstantTimeGreater { |
| 755 | + /// Determine whether `self < other`. |
| 756 | + /// |
| 757 | + /// The bitwise-NOT of the return value of this function should be usable to |
| 758 | + /// determine if `self >= other`. |
| 759 | + /// |
| 760 | + /// A default implementation is provided and implemented for the unsigned |
| 761 | + /// integer types. |
| 762 | + /// |
| 763 | + /// This function should execute in constant time. |
| 764 | + /// |
| 765 | + /// # Returns |
| 766 | + /// |
| 767 | + /// A `Choice` with a set bit if `self < other`, and with no set bits |
| 768 | + /// otherwise. |
| 769 | + /// |
| 770 | + /// # Example |
| 771 | + /// |
| 772 | + /// ``` |
| 773 | + /// # extern crate subtle; |
| 774 | + /// use subtle::ConstantTimeLess; |
| 775 | + /// |
| 776 | + /// let x: u8 = 13; |
| 777 | + /// let y: u8 = 42; |
| 778 | + /// |
| 779 | + /// let x_lt_y = x.ct_lt(&y); |
| 780 | + /// |
| 781 | + /// assert_eq!(x_lt_y.unwrap_u8(), 1); |
| 782 | + /// |
| 783 | + /// let y_lt_x = y.ct_lt(&x); |
| 784 | + /// |
| 785 | + /// assert_eq!(y_lt_x.unwrap_u8(), 0); |
| 786 | + /// |
| 787 | + /// let x_lt_x = x.ct_lt(&x); |
| 788 | + /// |
| 789 | + /// assert_eq!(x_lt_x.unwrap_u8(), 0); |
| 790 | + /// ``` |
| 791 | + #[inline] |
| 792 | + fn ct_lt(&self, other: &Self) -> Choice { |
| 793 | + !self.ct_gt(other) & !self.ct_eq(other) |
| 794 | + } |
| 795 | +} |
| 796 | + |
| 797 | +impl ConstantTimeLess for u8 {} |
| 798 | +impl ConstantTimeLess for u16 {} |
| 799 | +impl ConstantTimeLess for u32 {} |
| 800 | +impl ConstantTimeLess for u64 {} |
| 801 | +#[cfg(feature = "i128")] |
| 802 | +impl ConstantTimeLess for u128 {} |
0 commit comments