dalek-cryptography / subtle Goto Github PK
View Code? Open in Web Editor NEWPure-Rust traits and utilities for constant-time cryptographic implementations.
License: BSD 3-Clause "New" or "Revised" License
Pure-Rust traits and utilities for constant-time cryptographic implementations.
License: BSD 3-Clause "New" or "Revised" License
Hi, has there been any interest in creating some tooling for verified crypto? I think the rust crypto community will welcome this. Prusti seems like it might be the right tool for the job, but it could leverage some extra help to ensure constant-time ops, although I am not sure if it can down to the assembly level, which Vale manages to do. I think tooling approaching what Evercrypt or something like Cryptol+C has might be nice. For additional context, here is the query I made to the project Everest team.
I also wonder what the interest of Zcash or other organisations might be in supporting such a project.
In code elsewhere, I keep repeating variants of the following pattern:
match orig.ct_eq(&check).unwrap_u8() {
0 => Err(MacError::AuthenticationError),
1 => Ok(mac.message.clone()),
_ => unsafe { ::core::hint::unreachable_unchecked() },
}
It would be nice to have a convenience wrapper to do this, except rather than errors return true
or false
.
Currently, working with bls12_381
we have functions like Scalar::from_bytes()
which returns a CtOption
.
This is fine since it's "marking" the function as a const_time fn. The problem is that the type is really unflexible since you don't have any way to transform the CtOption
to Result<T, Error>
appart of doing something like:
if ct_opt.is_some() {
return ct_opt.unwrap()
} else {
return Err(....)
}
Is there any reason why ok_or()
it's not implemented for CtOption
? Or any workarround to that?
For now, if one wants to convert a CtOption
to an Option
(say, at the end of a computation, when constant-time doesn't matter anymore) they need to manually write an if ... else
block.
let foo: CtOption<T> = ...
let bar: Option<T> = if foo.is_some().into() {
foo.unwrap()
} else {
None
};
Would it make sense to expose an unwrap_option
method?
?
such as let bar: T = foo.unwrap_option()?;
.if ... else
block is more explicit, which allows to more easily spot the variable-timeness of it.For now, the library only supports constant-time equality comparison.
Could it be extended to support constant-time ordering comparisons (https://doc.rust-lang.org/std/cmp/trait.Ord.html)? In particular for slices of the same length (using lexicographical comparison).
One application would be private key generation for curves like P-256 using rejection sampling, where the rejection requires an ordering comparison between the generated secret and the curve order.
I'm not sure whether it would make sense to extend the Choice
type to support three states, or to just expose a less-than API returning a boolean choice.
I remember watching many Chandler Carruth talks in my past life as a C++ developer. Chandler Carruth is a major contributor to llvm.
I found a choice moment from one of his talks (watch for about 1 min)
https://www.youtube.com/watch?v=nXaxk27zwlk&=&t=40m40s
"The two scariest tokens for the optimizer are asm volatile
"
here's the black box function at current revision
/// This function is a best-effort attempt to prevent the compiler
/// from knowing anything about the value of the returned `u8`, other
/// than its type.
///
/// Uses inline asm when available, otherwise it's a no-op.
#[cfg(all(feature = "nightly", not(any(target_arch = "asmjs", target_arch = "wasm32"))))]
#[inline(always)]
fn black_box(mut input: u8) -> u8 {
debug_assert!((input == 0u8) | (input == 1u8));
// Move value through assembler, which is opaque to the compiler, even though we don't do anything.
unsafe { asm!("" : "=r"(input) : "0"(input) ) }
input
}
I suspect that the asm
block should actually have the volatile
token here for llvm to see.
Moreover, I think that this code comment:
// Move value through assembler, which is opaque to the compiler, even though we don't do anything.
is not correct -- the compiler CAN pull out your inline assembly and start optimizing it, UNLESS you mark it volatile
. This is based largely on my understanding of Chandler Carruth's talks, and informal discussions with my boss at my previous job who had earlier been a core developer of clang and a major contributor to llvm.
Note that, I am not an expert on compilers or llvm, and I'm not claiming to be one, but I wonder if you would be interested in a patch to make this like:
unsafe { asm!("" : "=r"(input) : "0"(input) : : "volatile" ) }
or if you know a good reason not to do this, cause then I would learn something :)
I'm working on an embedded versions of ed25519, and considering whether to use your library, or roll my own. I'd like to have more control over what is copied.
On the one hand, I think ConditionallySelectable
could use Clone
as trait bound, and then later in the provided method conditional_swap
explicitly clone (instead of the implict copy in the derefence). AFAIK, Copy types would always implement Clone in the same way, so this would strictly extend applicability of the trait. If you agree, I can PR this, it's just two changed lines.
On the other hand, the implementation I am currently using, which is a transliteration of the TweetNaCl code, does not use any copy or clone at all:
type Limbs = [i64; 16];
#[derive(Clone,Debug,Default)]
pub struct FieldElement(pub Limbs);
pub fn conditional_swap(p: &mut FieldElement, q: &mut FieldElement, b: i64) {
let mask: i64 = !(b - 1);
for (pi, qi) in p.0.iter_mut().zip(q.0.iter_mut()) {
let t = mask & (*pi ^ *qi);
*pi ^= t;
*qi ^= t;
}
}
Therefore, I'm not sure I agree with deriving conditional swap from select. What is the rationale here, besides minimal implementation cost?
EDIT: I see you overwrite the provided implementation for integral types, so I guess the idea is for users to do so as well for their own types?
not sure if it's supposed to compile on non nighly:
error[E0554]: #![feature] may not be used on the stable release channel
--> /home/aep/.cargo/registry/src/github.com-1ecc6299db9ec823/subtle-0.3.0/src/lib.rs:20:34
|
20 | #![cfg_attr(feature = "nightly", feature(i128_type))]
| ^^^^^^^^^^^^^^^^^^^
When I build with the latest nightly now I get the following error
error: the legacy LLVM-style asm! syntax is no longer supported
--> /home/vsts/.cargo/registry/src/github.com-1ecc6299db9ec823/subtle-2.2.2/src/lib.rs:150:14
|
150 | unsafe { asm!("" : "=r"(input) : "0"(input) ) }
| ----^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| |
| help: replace with: `llvm_asm!`
|
= note: consider migrating to the new asm! syntax specified in RFC 2873
= note: alternatively, switch to llvm_asm! to keep your code working as it is
Not sure why I get this in 2.2.3 either. Is this the right place to put this?
This is a feature request to support the trait ConditionallySelectable
for types that are not Copy
.
I have large types (e.g. polynomials of high degree) that I'd like to be conditionally selectable.
The comments in the code itself state the license as a CC0 public domain dedication, but Cargo.toml
and LICENSE
give the license as 3-clause BSD. Which one is the code licensed under?
I have been testing subtle using dudect, provided by dudect-bencher.
From what I can tell, there is a short-circuit in both black_box
functions and the From<Choice> for bool
trait implementation for Choice
. This affects both stable and nightly, but in debug-mode only.
I have only tested ct_eq
.
The asserts that seem to short-circuit are:
Line 79 in 558316b
Line 147 in 558316b
Line 163 in 558316b
Commit bf3888e changes the debug_assert OR to a strict evaluation.
Before applying commit bf3888e in #42, these were the t-tests that dudect-bencher reported
running 1 bench
bench test_secure_cmp seeded with [0xc8437c3f, 0x1ebd6d87, 0x4143a2d8, 0xd9e40fe5]
bench test_secure_cmp ... : n == +0.334M, max t = +747.27294, max tau = +1.29251, (5/tau)^2 = 14
running 1 bench
bench test_secure_cmp seeded with [0xdd26324, 0xb0cd6929, 0x38345f3b, 0xe33981da]
bench test_secure_cmp ... : n == +0.861M, max t = -2.28511, max tau = -0.00246, (5/tau)^2 = 4121111
running 1 bench
bench test_secure_cmp seeded with [0x8de2c6f6, 0xef48ef86, 0x1331bfd1, 0x6318f891]
bench test_secure_cmp ... : n == +0.663M, max t = +955.01525, max tau = +1.17311, (5/tau)^2 = 18
bench test_secure_cmp seeded with [0x88de063f, 0xa3944eaa, 0xa16ddc08, 0x4860f51b]
bench test_secure_cmp ... : n == +0.997M, max t = -1.68096, max tau = -0.00168, (5/tau)^2 = 8821035
After applying commit bf3888e:
running 1 bench
bench test_secure_cmp seeded with [0xf66c77e4, 0xb6ad3111, 0x3fc3413b, 0x957ba0f4]
bench test_secure_cmp ... : n == +0.997M, max t = +1.55842, max tau = +0.00156, (5/tau)^2 = 10261010
running 1 bench
bench test_secure_cmp seeded with [0x1a77a729, 0x7de4a2f2, 0x55470f7a, 0xa4a18553]
bench test_secure_cmp ... : n == +0.247M, max t = -1.39785, max tau = -0.00281, (5/tau)^2 = 3155259
running 1 bench
bench test_secure_cmp seeded with [0x47063cc9, 0x66d3dc0e, 0x20ece803, 0xad3363ae]
bench test_secure_cmp ... : n == +0.994M, max t = +2.07018, max tau = +0.00208, (5/tau)^2 = 5796406
running 1 bench
bench test_secure_cmp seeded with [0x8587213f, 0xfb937a4f, 0xaab1fee2, 0x88f71c10]
bench test_secure_cmp ... : n == +0.983M, max t = +2.50388, max tau = +0.00253, (5/tau)^2 = 3919187
The tests can be found here: https://github.com/brycx/orion-dudect/tree/subtle-short-circuit/ct-bencher.
Travis is broken and hasn't been running in about a year. They claim they support open source projects, but they've told me for the past year that I need to buy credits from them for $69 (not nice) per month. :(
The CI is failing due to xargo tooling for ARM builds; I'm not sure how to fix it, so I'm going to remove it temporarily, if someone wants to reconfigure it and add it back they're welcome to do so.
When looking at https://doc.dalek.rs/src/subtle/lib.rs.html (linked from the "docs" badge in the README), the code seems quite outdated compared to the GitHub repository. For example, the implementation of ct_eq
computes the and of all the bits, which was changed 4 months ago to a shorter & more efficient implementation in 92451be.
The version referenced in the Cargo.toml snippet at https://doc.dalek.rs/subtle/ is also 2.1 whereas there has already been multiple 2.2.x versions.
On the contrary, https://docs.rs/subtle/ generated by https://crates.io/crates/subtle is always pointing to the latest version of the library. Does it make sense to duplicate documentation in https://doc.dalek.rs/ given that docs.rs is automatically up-to-date? It's especially confusing that the "documentation" link in the header of the crates.io page differs from the "docs badge" link.
Line 223 in b4b070c
I am working on a project that has a policy to avoid BSD 2- and 3-clause licenses due to the complexity of satisfying the attribution clause:
Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
Would you consider dual-licensing this project? Eg with MIT and/or Apache 2.0 licenses?
After checking that the API we have is the one we want, we should publish a 1.0.0-pre.0
release.
I am trying to implement check for <=
, but as far as I can tell I can only check for equality with this crate. Is this something that could be added here?
As described in #98, the Signal client crypto implementation wants to use subtle
to filter and sort PrivateKey
structs with constant-time operations, but goes through a hacky two-step process to achieve this by first serializing the PrivateKey
struct to a byte slice (which often incurs a heap allocation for legacy reasons with the Signal code), then calling the .ct_eq()
implementation predefined for byte slices. #98 proposes a method with a lookup table to process Ordering
-like results without branching.
I'm not deeply familiar with the problem space of constant-time operations, but I saw that someone else had already worked out how to accumulate sequences of constant-time logical operations in that .ct_eq()
implementation for byte slices, so in #99 I exposed the IteratedOperation
trait and related structs for specific iterated logical comparisons.
I created a proc macro crate at https://github.com/cosmicexplorer/subtle-derive. Example doctest from that crate:
use subtle::ConstantTimeOrd;
use subtle_derive::{ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, ConstEq, ConstPartialOrd, ConstOrd};
#[derive(Debug, ConstantTimeEq, ConstantTimeGreater, ConstantTimeLess, ConstEq, ConstPartialOrd, ConstOrd)]
pub struct S(pub u8);
impl ConstantTimeOrd for S {}
assert!(S(0) == S(0));
assert!(S(0) < S(1));
assert!(S(0) <= S(1));
If the current maintainers think it fits, I could instead convert my subtle-derive
crate into a PR against this repo instead (and we could hide the proc macro dependency behind a "derive"
feature flag the way serde
does: https://serde.rs/derive.html).
When generic-impls
is not selected, Conditionally{Assign, Negate, Swap}
are not implemented for the integer types. The traits also can't be implemented by downstream traits because of the orphan rules. Therefore, I think it makes sense to have impls of these traits for the integer types behind a #[cfg(not(feature = "generic-impls"))]
flag.
From taking a look at the documentation the Choice
type is meant to be a wrapper around a 0u8
or a 1u8
. This invariant is upheld while running in debug mode (since debug_asserts are used) but isn't upheld when running in release mode.
This simple example illustrates the behavior:
fn main() {
let c: Choice = 3u8.into();
println!("{:?}", c);
}
> cargo run
thread 'main' panicked at 'assertion failed: (input == 0u8) | (input == 1u8)'
> cargo run --release
Choice(3)
Currently, when taking a variable-time function that returns Option<T>
and making it constant-time, you need to return (Choice, T)
and then require that the caller checks the Choice
before using the result. It would be safer to wrap this as CTOption<T>(Choice, T)
, and then provide equivalent is_none()
, is_some()
functions that check the Choice
, and an unwrap()
function that panics if the Choice
is false.
This could also possibly provide CTOption<T>::ct_map()
, by computing the map function over the internal T
regardless of the value of Choice
(with the result still being restricted by the API).
The foundation of ConditionallySelectable
is bitwise masking of values + XOR, using the input Choice
to generate a conditional mask, such that the mask erases one of the two values from the XOR output:
https://github.com/dalek-cryptography/subtle/blob/b4b070c/src/lib.rs#L477-L503
This seems fine for now (and is the best thing possible in a portable implementation), but may have issues with future LLVM versions which are able to deduce how to rewrite such code with a branch.
CPUs provide predication intrinsics such as x86's conditional move (a.k.a. CMOV) family of instructions. Intel has guaranteed that the CMOV family operates in constant time on all extant Intel CPUs. ARM provides conditional select (a.k.a. CSEL) instructions which perform a similar function.
Within the @RustCrypto project, we've made a cmov
crate which provides a portable abstraction for this based on the now stable inline assembly support added to Rust 1.59: https://github.com/RustCrypto/utils/tree/master/cmov
...however its implementation is simple and could be copied into subtle
to avoid a dependency.
Lines 332 to 338 in 6b6a81a
Doesn't really rule out a simple if x == 0 goto end
optimization. I assume the assembly was inspected but that should probably be annotated because it would have to be repeated when the compiler does smarter things.
Current implementation
pub fn arrays_equal(a: &[u8], b: &[u8]) -> Mask {
assert_eq!(a.len(), b.len());
let mut x: u8 = 0;
for i in 0 .. a.len() {
x |= a[i] ^ b[i];
}
bytes_equal(x, 0)
}
Compiler might optimize the for loop like so without changing the non-CT program's behavior:
for i in 0 .. a.len() {
x |= a[i] ^ b[i];
if x == !0 {
break;
}
}
Hello,
first of all, I am not sure if this is a bug or something that results from my bad understanding of rusts no_std
environments, so please bear with me.
If I understand it correctly subtle
is meant to work in no_std
envs. If not, this issue can be closed.
Problem Description
I have subtle
as a transitive dependency in my project, namely from the schnorrkel
crate that I use. When I am compiling my project I get the following error:
Blocking waiting for file lock on package cache
Compiling sp-io v4.0.0-dev (https://github.com/centrifuge/substrate?branch=master#32b0fa55)
error[E0152]: found duplicate lang item `panic_impl`
--> /Users/frederik/.cargo/git/checkouts/substrate-c08550cb428dbcc9/32b0fa5/primitives/io/src/lib.rs:1424:1
|
1424 | pub fn panic(info: &core::panic::PanicInfo) -> ! {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the lang item is first defined in crate `std` (which `subtle` depends on)
= note: first definition in `std` loaded from /Users/frederik/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/wasm32-unknown-unknown/lib/libstd-17199824ef310338.rlib
= note: second definition in the local crate (`sp_io`)
error[E0152]: found duplicate lang item `oom`
--> /Users/frederik/.cargo/git/checkouts/substrate-c08550cb428dbcc9/32b0fa5/primitives/io/src/lib.rs:1435:1
|
1435 | pub fn oom(_: core::alloc::Layout) -> ! {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: the lang item is first defined in crate `std` (which `subtle` depends on)
= note: first definition in `std` loaded from /Users/frederik/.rustup/toolchains/nightly-x86_64-apple-darwin/lib/rustlib/wasm32-unknown-unknown/lib/libstd-17199824ef310338.rlib
= note: second definition in the local crate (`sp_io`)
For more information about this error, try `rustc --explain E0152`.
error: could not compile `sp-io` due to 2 previous errors
warning: build failed, waiting for other jobs to finish...
error: build failed
This error led me to the conclusion that subtle
for some reason integrates rusts std
lib.
Can you help me out, if this could be the case? So far my research only showed me that rust's compiler is not able to detect no_std
incompatibilities in dependencies here. Although, I am not aware if this is still the case.
Thank you in advance for your help!
The subtle "root traits" are supposed to be ConditionallySelectable
and ConstantTimeEq
, and all other traits are supposed to be implemented based on those. Clarify that this should be the case in the docs.
This should help prevent situations where a struct implements ConditionallyAssignable
, for instance, but not ConditionallySelectable
, such as here:
dalek-cryptography/curve25519-dalek#200
Several users have expressed that they dislike that the trait name Equal
doesn't tell you how it's supposed to differ to Eq
. Originally in subtle
, it was called CTEq
, and many other things were prefixed with CT
, and I argued that because it was coming from subtle
, it should already be understood to be constant time. However, this doesn't really help someone unfamiliar with crypto implementations when they're reading some higher level code with understanding why a type might have both an Eq
and an Equal
implementation.
I propose naming it ConstantTimeEq
, since "CT" doesn't really help people who aren't as familiar with crypto code. (Even some of my coworkers didn't know what "CT" meant when I said it in IRC at one point, and that's kind of the target audience for crypto code readability/understandability.)
Works but should probably be x
.
Lines 61 to 62 in 6b6a81a
The asymmetry between unwrap_u8
and From<u8> for Choice
bothers my OCD.
Similarly, the statement "[Choice] (...) is a wrapper around a u8, which should have the value either 1 (true) or 0 (false)" together with the debug_assert
ions on this.
Finally, there is some vagueness about the compiler "seeing through" wrapped bool
s, which I'd wager is equivalent to its power to see through wrapped u8
s.
And given that all primitive integral types can be converted to bool via x != 0
, I'd like to suggest removing u8
completely from the public API, including the unwrap_u8
method, and replacing with paired From<bool> for Choice
and From<Choice> for bool
.
Thoughts?
This kind of implementation seems fairly natural for big-int libraries (for example curve25519-dalek essentially does this for the specific type [u64; 5]
). Now that min-const-generics are stabilized, it would nice to have a general implementation of this.
I am imagining a straightforward generalization of the curve25519-dalek technique:
impl<const N: usize> ConditionallySelectable for [T; N] where T : Copy + Default {
fn conditional_select(
a: &[T; N],
b: &[T; N],
choice: Choice,
) -> [T; N] {
let mut output = [T::default(); N];
for i in 0..N {
output[i] = T::conditionally_selectable(&a[i], &b[i], choice);
}
output
}
I don't know if the trait bound I give for T
is precisely what is required though. It's not fully clear to me currently why ConditionallySelectable
requires T
to be Copy
.
For my particular use case, I have a simple wrapper type around a [u64; N]
that is not Copy (I want to write some constant-time bigint arithmetic that minimizes stack allocations. As a theorist who is trying to learn Rust I have no clue how actually useful this is, but it is the project I chose). If the above was implemented for [T; N]
, I could implement ConditionallySelectable
. It could also potentially replace the code in curve25519-dalek, but as you probably want the loop unrolled that might not be worth it (although hopefully the compiler would unroll it of course).
Tracking issue: rust-lang/rfcs#2360
Previous suggestions for black_box
(like volatile read/write) wouldn't work, because we want to be able to use Choice
s in hot loops, and adding overhead makes that harder. However, the proposed hint::black_box
should work for us and will let us have timing protections on stable Rust (if/when it's stabilized).
struct C(A, B);
fn create_c(a: &[u8], b: &[u8]) -> CtOption<C> {
let a: CtOption<A> = A::from_bytes(a);
let b: CtOption<B> = B::from_bytes(b);
// ???
}
impl<T,U> CtOption<T> {
pub fn merge<U>(self, other: CtOption<U>) -> CtOption<(T,U)> {
CtOption {
value: (self.value, other.value),
is_some: self.is_some & other.is_some,
}
}
}
let c = a.merge(b).map(|(a, b)| C(a,b));
May I prepare a PR? Or do you have any better idea?
Given that the ct_eq
implementations are currently implemented as an is_zero
under the hood (by xor-ing the compared values), would it make sense to expose an ct_is_zero
method in the ConstantTimeEq
trait? Some implementations could then derive ct_eq
from ct_is_zero
.
If one needs to check whether a value is zero, it should be more efficient to do directly with an ct_is_zero
method rather than constructing a temporary zero value for the purpose of comparing it.
I'm packaging subtle for debian and the .deb got flagged with these warnings:
W: librust-subtle-dev: description-too-long
W: librust-subtle-dev: privacy-breach-generic usr/share/cargo/registry/subtle-0.9.0/docs/assets/rustdoc-include-katex-header.html [<link rel="stylesheet" href="https://doc.dalek.rs/assets/katex/katex.min.css">] (https://doc.dalek.rs/assets/katex/katex.min.css)
W: librust-subtle-dev: privacy-breach-generic usr/share/cargo/registry/subtle-0.9.0/docs/assets/rustdoc-include-katex-header.html [<script src="https://doc.dalek.rs/assets/katex/katex.min.js">] (https://doc.dalek.rs/assets/katex/katex.min.js)
W: librust-subtle-dev: privacy-breach-generic usr/share/cargo/registry/subtle-0.9.0/docs/assets/rustdoc-include-katex-header.html [<script src="https://doc.dalek.rs/assets/katex/contrib/auto-render.min.js">] (https://doc.dalek.rs/assets/katex/contrib/auto-render.min.js)
I'm not very familiar with the docs system, but is there a way to include those js files in the repo itself so it's not including scripts from remote origins?
Thanks!
I plan to use subtle
instead of constant_time_eq
in RustCrypto. But I would like to keep to support Rust 1.21 for now. So it would be nice if you'll add enabled-by-default i128
feature gate.
P.S.: CI tests for MSRV would be nice as well.
(I believe @str4d originally suggested this)
When implementing functions that don't need to be constant time (i.e. that work on public values), but when doing so using functions which are designed to work on values that are potentially secret and therefore return CtOption
, it'd be nice to be able to explicitly opt into a CtOption
-> Option
conversion within the non-constant-time code.
I'd suggest adding a From<CtOption<_>> for Option
impl similar to the existing Choice
-> bool
conversion for these cases.
Should subtle
provide generic-impls at all? I'm trying to use subtle
in a library of my own at the moment, and it's creating issues. For example, if I have the following type:
#[derive(Copy)]
pub struct Thing<T>(pub T)
Then I can impl ConditionallySelectable
for it, but to impl ConditionallySwappable
, I have to have my own feature generic-impls2
(different name for disambiguation) and then do:
#[cfg(not(feature = "generic-impls2"))]
impl<T: ConditionallySwappable> ConditionallySwappable for Thing<T> {
fn conditional_swap(...) {
self.0.conditional_swap(&mut other.0, choice);
}
}
Now, I could impl ConditionallySwappable
for Thing
with an additional Copy
bound on T
, but that's unnecessarily restrictive and also, IMO, not correct: swapping Thing
should only require the inner type to also be ConditionallySwappable
.
Using the above type is thus problematic because invoking Thing::conditional_swap
would involve having conditional trait bounds that depend on generic-impls2
:
#[cfg(feature = "generic-impls2")]
fn do_stuff<T: ConditionallySwappable + Copy>(val: T) {
let something = Thing(T);
something.conditional_swap(...);
}
#[cfg(not(feature = "generic-impls2"))]
fn do_stuff<T: ConditionalSwap>(val: T) {
let something = Thing(T);
something.conditional_swap(...);
}
PS: Apologies for the burst of issues I've filed over the past couple of days!
From what I understand, this line doesn't require Copy
at all:
Line 395 in 285d276
Removing the copy bound still compiles and all tests pass.
Right now, we have impl<T> ConditionallySelectable for T where T: Copy + ConditionallyAssignable
, but instead we should have a generic implementation of impl<T> ConditionallyAssignable for T where T: Copy + ConditionallySelectable
.
Choice
doesn't provide a const fn
for constructing the Choice
, since you must use From
to construct it. It might be nice to provide a from_u8
const constructor for users that need it.
In an abstract situation, I am more likely to come up with a bool (e.g. number != 0
) that I would like to turn into a Choice
, rather than a u8
.
For now, CtOption::map
requires a Default
type.
This is especially problematic for types which require some constant-time validation of the input in their public constructors, say with the following API.
impl T {
pub fn from_bytes(bytes: &[u8; N]) -> CtOption<T> { ... }
}
In that case, exposing a Default
for T
would allow the caller to bypass from_bytes
validation by creating a Default
.
Could there be a variant of map
with an explicitly provided dummy value? Same question for CtOption::and_then
.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.