std/digest/lib

std/digest/src/lib.trb

Message digests: Sha256 and Sha512 (FIPS 180-4), Sha1 (FIPS 180-4 / RFC 3174) and Md5 (RFC 1321, legacy - see its own doc comment), and the Digest all four answer. SHA-256 is what the package manager pins a package by (docs/design/RELEASE.md section 7.2) and what a download is checked against; SHA-512 is what Ed25519 hashes with (std/signature).

Hmac (RFC 2104) is written once, over the Hasher trait every one of the four implements, and Hmac.pbkdf2 is PBKDF2 (RFC 8018) over it: SCRAM's password hash, and everything else that stretches a password or a key.

Ordinary TorbScript with no native. SHA-256, SHA-1 and MD5 work over Int, every word kept below 2^32 by a mask, so nothing overflows; SHA-512 over UInt64 and its wrapping sum. The same bytes give the same digest in both back ends.

Examples

print Sha256.of("abc".bytes()).hex()
// prints ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

var hasher = Sha256()
hasher.add "ab".bytes()
hasher.add "c".bytes()
print hasher.finished().hex()
// prints ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad

const expected = Sha256.of "abc".bytes()
const received = Sha256.of "abc".bytes()
print expected.equalsConstantTime(received)
// prints true

type Digest

type Digest with Show

What a hash function answers: its bytes, most significant first, shown as lowercase hexadecimal.

field bytes

bytes: Bytes

The bytes of the digest, most significant first: 32 for Sha256, 64 for Sha512, 20 for Sha1, 16 for Md5.

fn hex

fn hex(): String

Two lowercase hexadecimal digits per byte: the spelling of sha256sum and of a lock file.

fn show

fn show(): String

The lowercase hexadecimal spelling, the same as Digest.hex.

fn equalsConstantTime

fn equalsConstantTime(other: Digest): Bool

Whether other has the same bytes, answered without the running time depending on where they first differ: every byte pair is read and the differences are combined by XOR and OR, with no early exit. Use it, not ==, to check a Hmac result against a MAC, a token or a digest that came from outside. Digests of different lengths are not equal; the lengths themselves are not secret and are compared first.

The source has no data-dependent branch or early exit; a compiler or a CPU may still introduce a timing effect, and nothing here promises otherwise.

fn constantTimeEqual

fn constantTimeEqual(a: Bytes, b: Bytes): Bool

Digest.equalsConstantTime over two plain byte sequences: a thin wrapper for a caller that holds Bytes, not a Digest. Prefer the method where a Digest is at hand.

trait Hasher

trait Hasher

A hash function fed in pieces, the shape Sha256, Sha512, Sha1 and Md5 share: a fresh value starts empty, Hasher.add feeds the next bytes, and Hasher.finished answers the Digest of everything fed so far without changing the hasher itself; Hasher.of is the one-call shortcut. Hasher.blockSize and Hasher.digestLength are what Hmac needs to pad a key and to size a PBKDF2 block, and never anything a caller reads for its own sake.

A hash function's own equality-hashing (with Hash, std/core) is a different trait entirely - this one is named after the cryptographic sense of the word, the one HMAC and PBKDF2 are generic over.

fn empty

static fn empty(): Self

A hasher with nothing fed yet, equivalent to Self(): what a generic caller starts from without naming the type.

fn of

static fn of(bytes: Bytes): Digest

The digest of bytes in one call.

fn add

var fn add(bytes: Bytes)

Feeds the next bytes.

fn finished

fn finished(): Digest

The digest of everything added so far. The hasher itself is unchanged and may be fed more.

fn blockSize

static fn blockSize(): Int

The block size HMAC pads a key to and splits a key longer than it by hashing: 64 for every hash here but SHA-512.

fn digestLength

static fn digestLength(): Int

How many bytes a digest of this hash is.

type Sha256

type Sha256 with Hasher

SHA-256, fed in pieces: Sha256.add takes the next bytes and Sha256.finished answers the digest of everything added so far without changing the hasher, so a hasher can be read, fed more, and read again.

fn empty

static fn empty(): Self

A hasher with nothing fed yet, the same as Self().

fn of

static fn of(bytes: Bytes): Digest

The digest of bytes in one call.

fn blockSize

static fn blockSize(): Int

64: SHA-256 works in blocks of sixteen 32-bit words.

fn digestLength

static fn digestLength(): Int

32: a SHA-256 digest is 256 bits.

fn add

var fn add(bytes: Bytes)

Feeds the next bytes.

fn finished

fn finished(): Digest

The digest of everything added so far. The hasher itself is unchanged and may be fed more.