diff --git a/.github/workflows/ctutils.yml b/.github/workflows/ctutils.yml index 2b253145..44741b26 100644 --- a/.github/workflows/ctutils.yml +++ b/.github/workflows/ctutils.yml @@ -64,6 +64,8 @@ jobs: with: toolchain: ${{ matrix.rust }} - run: cargo test + - run: cargo test --all-features + - run: cargo test --all-features --release # Test using `cargo careful` test-careful: diff --git a/Cargo.lock b/Cargo.lock index c1d90aa2..4684e2d9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,6 +81,7 @@ name = "ctutils" version = "0.0.0" dependencies = [ "cmov", + "subtle", ] [[package]] @@ -262,6 +263,12 @@ dependencies = [ "keccak", ] +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + [[package]] name = "syn" version = "2.0.111" diff --git a/ctutils/Cargo.toml b/ctutils/Cargo.toml index 4ac01f9f..0819767e 100644 --- a/ctutils/Cargo.toml +++ b/ctutils/Cargo.toml @@ -18,3 +18,6 @@ rust-version = "1.85" [dependencies] cmov = "0.4" + +# optional dependencies +subtle = { version = "2", optional = true, default-features = false } diff --git a/ctutils/src/choice.rs b/ctutils/src/choice.rs index 6163c69a..ff1a9374 100644 --- a/ctutils/src/choice.rs +++ b/ctutils/src/choice.rs @@ -159,6 +159,22 @@ impl From for bool { } } +#[cfg(feature = "subtle")] +impl From for Choice { + #[inline] + fn from(choice: subtle::Choice) -> Choice { + Choice(choice.unwrap_u8()) + } +} + +#[cfg(feature = "subtle")] +impl From for subtle::Choice { + #[inline] + fn from(choice: Choice) -> subtle::Choice { + subtle::Choice::from(choice.0) + } +} + impl Not for Choice { type Output = Choice; diff --git a/ctutils/src/ct_option.rs b/ctutils/src/ct_option.rs index c2c53a53..44bcf1ac 100644 --- a/ctutils/src/ct_option.rs +++ b/ctutils/src/ct_option.rs @@ -385,6 +385,31 @@ impl From> for Option { } } +/// NOTE: in order to be able to unwrap the `subtle::CtOption` we rely on a `Default` bound in +/// order to have a placeholder value, and `ConditionallySelectable` to be able to use `unwrap_or`. +#[cfg(feature = "subtle")] +impl From> for CtOption +where + T: subtle::ConditionallySelectable + Default, +{ + #[inline] + fn from(src: subtle::CtOption) -> CtOption { + let is_some = src.is_some(); + CtOption { + value: src.unwrap_or(Default::default()), + is_some: is_some.into(), + } + } +} + +#[cfg(feature = "subtle")] +impl From> for subtle::CtOption { + #[inline] + fn from(src: CtOption) -> subtle::CtOption { + subtle::CtOption::new(src.value, src.is_some.into()) + } +} + #[cfg(test)] mod tests { use crate::{Choice, CtEq, CtOption, CtSelect};