Skip to content

Commit 09de9c9

Browse files
committed
[WIP] ctutils: CtOption methods for crypto-bigint
Adds the methods needed to replace `ConstCtOption` in `crypto-bigint` with `ctutils::CtOption`.
1 parent 93870ce commit 09de9c9

File tree

1 file changed

+89
-1
lines changed

1 file changed

+89
-1
lines changed

ctutils/src/ct_option.rs

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,17 @@
11
use crate::{Choice, CtEq, CtSelect};
22
use core::ops::{Deref, DerefMut};
33

4+
/// Helper macro for providing behavior like the `unwrap_or` combinator that works in a `const fn`
5+
/// context.
6+
///
7+
/// Requires a provided selector function to do the constant-time selection.
8+
#[macro_export]
9+
macro_rules! unwrap_or {
10+
($opt:expr, $default:expr, $select:path) => {
11+
$select(&$default, $opt.as_inner_unchecked(), $opt.is_some())
12+
};
13+
}
14+
415
/// Equivalent of [`Option`] but predicated on a [`Choice`] with combinators that allow for
516
/// constant-time operations which always perform the same sequence of instructions regardless of
617
/// the value of `is_some`.
@@ -23,6 +34,21 @@ impl<T> CtOption<T> {
2334
Self { value, is_some }
2435
}
2536

37+
/// Construct a new [`CtOption`] where `self.is_some()` is [`Choice::TRUE`].
38+
#[inline]
39+
pub const fn some(value: T) -> CtOption<T> {
40+
Self::new(value, Choice::TRUE)
41+
}
42+
43+
/// Construct a new [`CtOption`] with the [`Default`] value, and where `self.is_some()` is
44+
/// [`Choice::FALSE`].
45+
pub fn none() -> CtOption<T>
46+
where
47+
T: Default,
48+
{
49+
Self::new(Default::default(), Choice::FALSE)
50+
}
51+
2652
/// Convert from a `&mut CtOption<T>` to `CtOption<&mut T>`.
2753
#[inline]
2854
pub const fn as_mut(&mut self) -> CtOption<&mut T> {
@@ -99,7 +125,7 @@ impl<T> CtOption<T> {
99125
pub const fn expect_ref(&self, msg: &str) -> &T {
100126
// TODO(tarcieri): use `self.is_some().to_bool()` when MSRV is 1.86
101127
assert!(self.is_some.to_bool_vartime(), "{}", msg);
102-
&self.value
128+
self.as_inner_unchecked()
103129
}
104130

105131
/// Convert the [`CtOption`] wrapper into an [`Option`], depending on whether
@@ -146,6 +172,13 @@ impl<T> CtOption<T> {
146172
optb
147173
}
148174

175+
/// Apply an additional [`Choice`] requirement to `is_some`.
176+
#[inline]
177+
pub const fn and_choice(mut self, is_some: Choice) -> Self {
178+
self.is_some = self.is_some.and(is_some);
179+
self
180+
}
181+
149182
/// Calls the provided callback with the wrapped inner value, returning the resulting
150183
/// [`CtOption`] value in the event that `self.is_some()` is [`Choice::TRUE`], or if not
151184
/// returns a [`CtOption`] with `self.is_none()`.
@@ -164,6 +197,34 @@ impl<T> CtOption<T> {
164197
ret
165198
}
166199

200+
/// Obtain a reference to the inner value without first checking that `self.is_some()` is
201+
/// [`Choice::TRUE`].
202+
///
203+
/// This method is primarily intended for use in `const fn` scenarios where it's not yet
204+
/// possible to use the safe combinator methods, and returns a reference to avoid issues with
205+
/// `const fn` destructors.
206+
///
207+
/// <div class="warning">
208+
/// <b>Use with care!</b>
209+
///
210+
/// This method does not ensure the `value` is actually valid. Callers of this method should
211+
/// take great care to ensure that `self.is_some()` is checked elsewhere.
212+
/// </div>
213+
#[inline]
214+
pub const fn as_inner_unchecked(&self) -> &T {
215+
&self.value
216+
}
217+
218+
/// DEPRECATED: legacy compatibility method for `crypto-bigint`
219+
// TODO(tarcieri): deprecate this!
220+
#[inline]
221+
pub const fn components_ref(&self) -> (&T, Choice) {
222+
// Since Rust is not smart enough to tell that we would be moving the value,
223+
// and hence no destructors will be called, we have to return a reference instead.
224+
// See https://github.com/rust-lang/rust/issues/66753
225+
(&self.value, self.is_some)
226+
}
227+
167228
/// Calls the provided callback with the wrapped inner value, which computes a [`Choice`],
168229
/// and updates `self.is_some()`.
169230
///
@@ -247,6 +308,27 @@ impl<T> CtOption<T> {
247308
}
248309
}
249310

311+
/// Obtain a copy of the inner value without first checking that `self.is_some()` is
312+
/// [`Choice::TRUE`].
313+
///
314+
/// This method is primarily intended for use in `const fn` scenarios where it's not yet
315+
/// possible to use the safe combinator methods, and uses a `Copy` bound to avoid issues with
316+
/// `const fn` destructors.
317+
///
318+
/// <div class="warning">
319+
/// <b>Use with care!</b>
320+
///
321+
/// This method does not ensure the `value` is actually valid. Callers of this method should
322+
/// take great care to ensure that `self.is_some()` is checked elsewhere.
323+
/// </div>
324+
#[inline]
325+
pub const fn to_inner_unchecked(&self) -> T
326+
where
327+
T: Copy,
328+
{
329+
self.value
330+
}
331+
250332
/// Return the contained value, consuming the `self` value.
251333
///
252334
/// Use of this function is discouraged due to panic potential. Instead, prefer non-panicking
@@ -400,6 +482,12 @@ impl<T: CtSelect> CtSelect for CtOption<T> {
400482
}
401483
}
402484

485+
impl<T: Default> Default for CtOption<T> {
486+
fn default() -> Self {
487+
Self::none()
488+
}
489+
}
490+
403491
/// Convert the [`CtOption`] wrapper into an [`Option`], depending on whether
404492
/// [`CtOption::is_some`] is a truthy or falsy [`Choice`].
405493
///

0 commit comments

Comments
 (0)