Note:
rust-timing-shield
has not yet reached version 1.0. It may contain butterflies, unicorns, or a colourful assortment of small invertebrates.
The core idea behind rust-timing-shield
is to leverage Rust’s type system to
limit what operations can be performed on secret values.
The programmer marks which values require timing leak protection, and
rust-timing-shield
enforces those constraints at compile time.
To add timing protection to a program, indicate which variables require timing
protection by using one of the timing-protected (Tp
) types provided by
rust-timing-shield
:
Timing-protected types only allow operations that are possible to perform in constant-time (e.g. addition, subtraction, bit shifting). Other operations (e.g. division) will trigger a compile-time type error.
Operations on timing-protected values return values that are also timing-protected.
There’s an escape hatch. The expose()
method will recover the original unprotected value:
Be careful about using expose()
, since any code using the exposed value can
easily introduce a timing leak.
Typically, expose()
is used on public values (e.g. a ciphertext).
expose()
can also be used when a secret value must be provided to an
interface (e.g. networking, file I/O) that does not use rust-timing-shield
.
If you have to use expose()
, use it as late as possible in a computation, and
think carefully about what values you are exposing:
With rust-timing-shield
, if an input to an operator is timing-protected, then
the output will be timing-protected as well.
This is an important feature, since knowing the output of an operation will,
in most cases, easily reveal information about the inputs.
Rust does not yet have full support for overloading the ==
, !=
, <
, <=
,
>
, and >=
operators.
In particular, it requires the outputs of these operations to be an unprotected
bool
, which would violate the principle stated above.
Instead, timing-protected types implement the traits TpEq
and TpOrd
:
Some operations (e.g. addition, tp_eq
) do not require all inputs to be timing
protected. For example, it is legal to add a TpU32
to a u32
, or to
compare a u64
to a TpU64
using tp_eq
.
Operations are only required to protect inputs with Tp
types.
It is perfectly legal for an implementation of tp_eq
to leak information
about one of the inputs if that input is not a timing-protected type.
If a value requires protection, you must indicate this by using a protect
method from the corresponding Tp
type.
For convenience, the TpBool
type provides a method for conditionally swapping
two values without leaking whether the swap occurred:
Additionally, TpBool
provides a method for selecting one of two values
without leaking which value was selected:
rust-timing-shield
supports Vec
s and slices of Tp
types for some
operations such as tp_eq
:
Note that a Vec<TpU8>
is a vector of timing-protected bytes, not a timing-protected vector of bytes.
As a result, tp_eq
can (and will) leak information like the number of items
in the vector, since Vec
is not a timing-protected type.
The actual values in the vector, however, will remain protected because TpU8
is a timing-protected type.
Vector and slice support is a work in progress.
If there is a particular use case that would benefit from more comprehensive
support for collection types in rust-timing-shield
, I encourage you to open
an issue on GitHub to provide feedback.
In order to make code easier to read and audit,
it is recommended that users of rust-timing-shield
follow these conventions
for function signatures:
Tp
type as input if it provides full
timing leak protection for that argument (i.e. it leaks zero information
about the value).Tp
type if leaking the return value would
violate the protection promised for that function’s inputs (see previous
point).A function’s parameter types indicate what can be expected of the function. A function’s return type indicates what is expected of callers of the function.