1- use subtle:: Choice ;
1+ use subtle:: { Choice , CtOption } ;
22
3- use crate :: Word ;
3+ use crate :: { NonZero , Uint , Word } ;
44
55/// A boolean value returned by constant-time `const fn`s.
66// TODO: should be replaced by `subtle::Choice` or `CtOption`
@@ -71,10 +71,19 @@ impl ConstChoice {
7171 /// Returns the truthy value if `x < y`, and the falsy value otherwise.
7272 #[ inline]
7373 pub ( crate ) const fn from_word_lt ( x : Word , y : Word ) -> Self {
74+ // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
7475 let bit = ( ( ( !x) & y) | ( ( ( !x) | y) & ( x. wrapping_sub ( y) ) ) ) >> ( Word :: BITS - 1 ) ;
7576 Self :: from_word_lsb ( bit)
7677 }
7778
79+ /// Returns the truthy value if `x > y`, and the falsy value otherwise.
80+ #[ inline]
81+ pub ( crate ) const fn from_word_gt ( x : Word , y : Word ) -> Self {
82+ // See "Hacker's Delight" 2nd ed, section 2-12 (Comparison predicates)
83+ let bit = ( ( ( !y) & x) | ( ( ( !y) | x) & ( y. wrapping_sub ( x) ) ) ) >> ( Word :: BITS - 1 ) ;
84+ Self :: from_word_lsb ( bit)
85+ }
86+
7887 /// Returns the truthy value if `x < y`, and the falsy value otherwise.
7988 #[ inline]
8089 pub ( crate ) const fn from_u32_lt ( x : u32 , y : u32 ) -> Self {
@@ -147,6 +156,7 @@ impl ConstChoice {
147156}
148157
149158impl From < ConstChoice > for Choice {
159+ #[ inline]
150160 fn from ( choice : ConstChoice ) -> Self {
151161 Choice :: from ( choice. to_u8 ( ) )
152162 }
@@ -164,11 +174,144 @@ impl PartialEq for ConstChoice {
164174 }
165175}
166176
177+ /// An equivalent of `subtle::CtOption` usable in a `const fn` context.
178+ #[ derive( Debug , Clone ) ]
179+ pub struct ConstCtOption < T > {
180+ value : T ,
181+ is_some : ConstChoice ,
182+ }
183+
184+ impl < T > ConstCtOption < T > {
185+ #[ inline]
186+ pub ( crate ) const fn new ( value : T , is_some : ConstChoice ) -> Self {
187+ Self { value, is_some }
188+ }
189+
190+ #[ inline]
191+ pub ( crate ) const fn some ( value : T ) -> Self {
192+ Self {
193+ value,
194+ is_some : ConstChoice :: TRUE ,
195+ }
196+ }
197+
198+ #[ inline]
199+ pub ( crate ) const fn none ( dummy_value : T ) -> Self {
200+ Self {
201+ value : dummy_value,
202+ is_some : ConstChoice :: FALSE ,
203+ }
204+ }
205+
206+ /// Returns a reference to the contents of this structure.
207+ ///
208+ /// **Note:** if the second element is `None`, the first value may take any value.
209+ #[ inline]
210+ pub ( crate ) const fn components_ref ( & self ) -> ( & T , ConstChoice ) {
211+ // Since Rust is not smart enough to tell that we would be moving the value,
212+ // and hence no destructors will be called, we have to return a reference instead.
213+ // See https://github.com/rust-lang/rust/issues/66753
214+ ( & self . value , self . is_some )
215+ }
216+
217+ /// Returns a true [`ConstChoice`] if this value is `Some`.
218+ #[ inline]
219+ pub const fn is_some ( & self ) -> ConstChoice {
220+ self . is_some
221+ }
222+
223+ /// Returns a true [`ConstChoice`] if this value is `None`.
224+ #[ inline]
225+ pub const fn is_none ( & self ) -> ConstChoice {
226+ self . is_some . not ( )
227+ }
228+
229+ /// This returns the underlying value but panics if it is not `Some`.
230+ #[ inline]
231+ pub fn unwrap ( self ) -> T {
232+ assert ! ( self . is_some. is_true_vartime( ) ) ;
233+ self . value
234+ }
235+ }
236+
237+ impl < T > From < ConstCtOption < T > > for CtOption < T > {
238+ #[ inline]
239+ fn from ( value : ConstCtOption < T > ) -> Self {
240+ CtOption :: new ( value. value , value. is_some . into ( ) )
241+ }
242+ }
243+
244+ // Need specific implementations to work around the
245+ // "destructors cannot be evaluated at compile-time" error
246+ // See https://github.com/rust-lang/rust/issues/66753
247+
248+ impl < const LIMBS : usize > ConstCtOption < Uint < LIMBS > > {
249+ /// This returns the underlying value if it is `Some` or the provided value otherwise.
250+ #[ inline]
251+ pub const fn unwrap_or ( self , def : Uint < LIMBS > ) -> Uint < LIMBS > {
252+ Uint :: select ( & def, & self . value , self . is_some )
253+ }
254+
255+ /// Returns the contained value, consuming the `self` value.
256+ ///
257+ /// # Panics
258+ ///
259+ /// Panics if the value is none with a custom panic message provided by
260+ /// `msg`.
261+ #[ inline]
262+ pub const fn expect ( self , msg : & str ) -> Uint < LIMBS > {
263+ assert ! ( self . is_some. is_true_vartime( ) , "{}" , msg) ;
264+ self . value
265+ }
266+ }
267+
268+ impl < const LIMBS : usize > ConstCtOption < ( Uint < LIMBS > , Uint < LIMBS > ) > {
269+ /// Returns the contained value, consuming the `self` value.
270+ ///
271+ /// # Panics
272+ ///
273+ /// Panics if the value is none with a custom panic message provided by
274+ /// `msg`.
275+ #[ inline]
276+ pub const fn expect ( self , msg : & str ) -> ( Uint < LIMBS > , Uint < LIMBS > ) {
277+ assert ! ( self . is_some. is_true_vartime( ) , "{}" , msg) ;
278+ self . value
279+ }
280+ }
281+
282+ impl < const LIMBS : usize > ConstCtOption < NonZero < Uint < LIMBS > > > {
283+ /// Returns the contained value, consuming the `self` value.
284+ ///
285+ /// # Panics
286+ ///
287+ /// Panics if the value is none with a custom panic message provided by
288+ /// `msg`.
289+ #[ inline]
290+ pub const fn expect ( self , msg : & str ) -> NonZero < Uint < LIMBS > > {
291+ assert ! ( self . is_some. is_true_vartime( ) , "{}" , msg) ;
292+ self . value
293+ }
294+ }
295+
167296#[ cfg( test) ]
168297mod tests {
169298 use super :: ConstChoice ;
170299 use crate :: Word ;
171300
301+ #[ test]
302+ fn from_word_lt ( ) {
303+ assert_eq ! ( ConstChoice :: from_word_lt( 4 , 5 ) , ConstChoice :: TRUE ) ;
304+ assert_eq ! ( ConstChoice :: from_word_lt( 5 , 5 ) , ConstChoice :: FALSE ) ;
305+ assert_eq ! ( ConstChoice :: from_word_lt( 6 , 5 ) , ConstChoice :: FALSE ) ;
306+ }
307+
308+ #[ test]
309+ fn from_word_gt ( ) {
310+ assert_eq ! ( ConstChoice :: from_word_gt( 4 , 5 ) , ConstChoice :: FALSE ) ;
311+ assert_eq ! ( ConstChoice :: from_word_gt( 5 , 5 ) , ConstChoice :: FALSE ) ;
312+ assert_eq ! ( ConstChoice :: from_word_gt( 6 , 5 ) , ConstChoice :: TRUE ) ;
313+ }
314+
172315 #[ test]
173316 fn select ( ) {
174317 let a: Word = 1 ;
0 commit comments