Block operations v0.1.0

Source
Copying, filling, clearing, comparing and searching blocks of bytes.

ZeroizeBlock

pub func ZeroizeBlock(buffer: *var opaque, length: uint)

Clears length bytes at buffer, and is not removed however unread those bytes are afterwards. buffer is borrowed and written. A length of zero writes nothing and accepts a null pointer. This is what Zero is not. Clearing a secret is a write nothing reads back, which dead-store elimination is entitled to delete, and ordinary source cannot say "and mean it" — so this is a compiler guarantee rather than a library one. The guarantee is Core::Zeroize's; this adds the empty-case contract the rest of this module has and takes the *var opaque and uint every other block operation here takes. Cannot fail. Runs in time proportional to length and allocates nothing. buffer must be writable for length bytes. It clears the storage it is given and nothing else. A copy the caller made beforehand, a value the compiler spilled to the stack, or bytes a reallocation left behind are all still there — so a secret has to be kept in one place from the start for this to be the whole of its erasure.

Source

Parameters

NameTypeDescription
buffer*var opaquethe bytes to clear
lengthuinthow many bytes; zero writes nothing and accepts a null pointer

Copy

pub func Copy(
    destination: *var opaque,
    source: *opaque,
    length: uint
)

Copies length bytes from source to destination, which must not overlap. source is borrowed and read; destination is borrowed and written. Nothing is returned and nothing takes ownership. A length of zero copies nothing and accepts null for either pointer. Cannot fail. Runs in time proportional to length and allocates nothing. destination must be writable for length bytes and source readable for length, and the two ranges must not overlap. Use Move when they might: this one is free to copy in whichever order suits the machine.

Source

Parameters

NameTypeDescription
destination*var opaquewhere the bytes go; must not overlap source
source*opaquewhere the bytes come from
lengthuinthow many bytes to copy

Move

pub func Move(
    destination: *var opaque,
    source: *opaque,
    length: uint
)

Copies length bytes from source to destination, correctly even when the two overlap. source is borrowed and read; destination is borrowed and written. A length of zero moves nothing and accepts null for either pointer. The result is what copying through a temporary would give: every source byte reaches its destination as it was before the move began. Sliding a run forward within one buffer therefore works, which is what an insertion into the middle of an array needs. Cannot fail. Runs in time proportional to length and allocates nothing — the temporary is notional, and the direction of the copy is what actually makes it right. destination must be writable for length bytes and source readable for length. They may overlap in any way, including exactly.

Source

Parameters

NameTypeDescription
destination*var opaquewhere the bytes go; may overlap source
source*opaquewhere the bytes come from
lengthuinthow many bytes to move

Set

pub func Set(
    destination: *var opaque,
    value: byte,
    length: uint
)

Writes value to each of length bytes at destination. destination is borrowed and written. A length of zero writes nothing and accepts a null pointer. Cannot fail. Runs in time proportional to length and allocates nothing. destination must be writable for length bytes. This is not the call for clearing a secret: a write nothing reads back may be deleted, and Core::Zeroize is the one that may not be.

Source

Parameters

NameTypeDescription
destination*var opaquethe bytes to write
valuebytethe byte to write to each
lengthuinthow many bytes to write

Zero

pub func Zero(destination: *var opaque, length: uint)

Writes zero to each of length bytes at destination. destination is borrowed and written. A length of zero writes nothing and accepts a null pointer. Cannot fail. Runs in time proportional to length and allocates nothing. destination must be writable for length bytes. For a secret, use Core::Zeroize, which the compiler may not delete however unread the bytes are afterwards.

Source

Parameters

NameTypeDescription
destination*var opaquethe bytes to clear
lengthuinthow many bytes to clear

MismatchOffset

pub func MismatchOffset(
    left: *opaque,
    right: *opaque,
    length: uint
) -> uint

The offset at which two blocks first differ, or length when they do not. Both pointers are borrowed and read. A length of zero reports zero and accepts null for either pointer, which is the same answer two equal empty blocks give. The answer is a position rather than an ordering, so it says where the blocks diverge and not which one sorts first. Compare answers that. Cannot fail. Runs in time proportional to the shared prefix and allocates nothing. Both pointers must be readable for length bytes. Not constant-time: it stops at the first difference, so it must not be used on a secret.

Source

Parameters

NameTypeDescription
left*opaqueone of the two blocks
right*opaquethe other
lengthuinthow many bytes to compare

Returns: the offset of the first differing byte, or length when none differs

Compare

pub func Compare(
    left: *opaque,
    right: *opaque,
    length: uint
) -> Ordering

Orders two blocks lexicographically, byte by byte. Both pointers are borrowed and read. Returns Less when left sorts first, Greater when right does, and Equal when the two ranges hold the same bytes. A length of zero reports Equal and accepts null for either pointer. Bytes are compared as unsigned, so the answer does not depend on whether the platform's plain char is signed, and it matches the order the bytes would sort in as a string. Cannot fail. Runs in time proportional to the shared prefix and allocates nothing. Both pointers must be readable for length bytes. Not constant-time: it stops at the first difference, so a secret compared this way leaks where it differs. Rux/Crypto is where a constant-time comparison belongs.

Source

Parameters

NameTypeDescription
left*opaqueone of the two blocks
right*opaquethe other
lengthuinthow many bytes to compare

Returns: how left orders against right

Equal

pub func Equal(
    left: *opaque,
    right: *opaque,
    length: uint
) -> bool

Whether two blocks hold the same bytes. Both pointers are borrowed and read. A length of zero reports true and accepts null for either pointer: two empty blocks are equal. Cannot fail. Runs in time proportional to the shared prefix and allocates nothing. Both pointers must be readable for length bytes. Not constant-time.

Source

Parameters

NameTypeDescription
left*opaqueone of the two blocks
right*opaquethe other
lengthuinthow many bytes to compare

Returns: whether every byte matches

Find

pub func Find(
    haystack: *opaque,
    length: uint,
    value: byte
) -> uint

The offset of the first byte equal to value, or length when there is none. haystack is borrowed and read. A length of zero reports zero and accepts a null pointer, which is also what a search that found nothing reports — an empty block contains nothing to find either way. Cannot fail. Runs in time proportional to the offset returned and allocates nothing. haystack must be readable for length bytes.

Source

Parameters

NameTypeDescription
haystack*opaquethe bytes to search
lengthuinthow many bytes to search
valuebytethe byte to look for

Returns: the offset of the first occurrence, or length when there is none