Skip to main content

Module secret

Module secret 

Source
Expand description

A transparent wrapper type, Secret, which is a wrapper that holds a secret value and guarantees it is securely zeroized on drop, and protected from accidintal logging by implementing redacting fmt::Debug and fmt::Display.

§Why write_volatile

Plain writes such as slice.fill(0) are ordinary, non-observable memory accesses. Under optimization the compiler may prove that a buffer is never read again after it is scrubbed – precisely the situation just before a drop – and elide the scrub as a dead store. To prevent that, Secret erases through core::ptr::write_volatile, whose accesses are defined by the language as observable side effects and therefore may not be elided or coalesced. Each scrub is followed by a compiler_fence with SeqCst ordering so the volatile writes are not reordered with respect to later memory operations.

§Why Sized?

The ZeroizablePrimitive is bounded on Sized, which explicitly forbids instantiating Secret<T> over something like Vec<T> whose size is not known at compile time.

The reason is that an implementation of .zeroize() that is guaranteed not be optimized away by the compiler requires the use of unsafe{ write_volatile() } to directly write the T::ZEROED byte pattern over top of the provided memory block. With a Sized type, this is a single line of unsafe code and it is easy to prove that it is writing the number of bytes that it should be. For a dynamically-sized value such as Vec<T>, this is substantially trickier. Taking Vec as an example, it is not a flat piece of memory that can be trivially over-written with a static value; Vec is actually a stack of structs that implement a smart-pointer that tracks both length and capacity of the memory referenced by the pointer. Properly zeroizing this means following the pointer, filling the referenced memory with 0x00 up to the capacity, then setting length=0 without changing capacity or the pointer. Zeroizing a Vec would require a substantial amount of unsafe code that is Vec-specific and tricky to prove the correctness of. Doing this for arbitrary heap-allocated objects (which may contain nested heap-allocated objects) sounds like a whole research project.

This is not to say that bc-rust will never attempt this challenge, but since bc-rust is a [no_std] library that keeps all of its secrets in stack-allocated variables, this is not a problem that needs to be solved for internal library use.

Structs§

Secret
A wrapper that holds a secret value of any primitive or fixed-size array type and guarantees it is securely zeroized on drop, and is protected from accidental logging by implementing redacting fmt::Debug and fmt::Display.

Traits§

ZeroizablePrimitive
A Copy type whose all-zero value is meaningful and valid, so that a Secret of it can be default-constructed in a zeroed state.