Algorithms

SHA-256

The SHA-2 hash everything agrees on. 32 bytes with HMAC and the default when nobody told you otherwise
IDsha25601 / 46SHA · 256-bit
Hash / Cryptographic

SHA-256

The default. Certificates, signatures, Bitcoin.

Digest
256-bit · 32 bytes
HMAC
takes a key
Security
128-bit collision resistance
Family
12 in SHA
5 options, 0 required

Sample

hex
b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
base64
uU0nuZNNPgilLlLX2n2r+sSE7+N6U4DukIj3rOLvzek=

Options

encodingstring
default hex
Output encoding: hex, base64, base64url, binary
keystring
optional
HMAC key; enables HMAC mode
bitLengthnumber
optional
Message length in bits when the last byte is partial: the message fills each byte from the top bit, the unused bits are zero
roundsnumber
default 1
How many times to hash, each round hashing the previous digest
chainstring
default bytes
What each round after the first hashes: bytes of the digest, or its lowercase hex

Access

Createcreate("sha256")
CLIhashes sha256 'hello world'
Tryplayground with the sample above
Kinsha384, sha512, sha224, sha512-224 +7

The default, and for good reason. Certificates, signatures, Git's next object format, Bitcoin's proof of work, half the checksum files on the internet. If two systems have to agree on a digest and nobody said which, it's this one.

ts
create("sha256").hash("abc").digest;
// "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
create("sha256").hash("").digest;
// "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
create("sha256").hash("The quick brown fox jumps over the lazy dog", { key: "key" }).digest;
// "f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8"

The first two are the FIPS 180 vector and the empty string, the third is the HMAC one Wikipedia quotes. If a SHA-256 of "" doesn't start with e3b0c442, something upstream added a newline.

Bitcoin runs it twice, that's HASH256. Under RIPEMD-160 it becomes HASH160.

Messages that stop inside a byte

SHA-256 is defined on bits, not bytes. You almost never notice. Then a test vector shows up with a message of 5 bits. How do you hash that?

Pack the bits from the top of the first byte and zero the rest of the last one. Then say how many bits count:

ts
import { sha256Bits } from "@agntn/hashes";

sha256Bits(Uint8Array.of(0x68), 5).toHex();
// "d6d3e02a31a84a8caa9718ed6c2057be09db45e7823eb5079ce7a573a3760f95"
create("sha256").hash(Uint8Array.of(0xfe), { bitLength: 7 }).digest;
// "7bbca3be22fe9d6a58cb656c5a3ab902aac8fba77c7b464eb94c2c50eba0e1d1"

The first is RFC 6234 test 5, the bits 01101. The second is seven ones. Not the byte 7f, not ff, and definitely not the text 1111111. Four different digests.

A stray bit after the message is an error, never quietly dropped. So is a bit length that doesn't fit the bytes. Whole bytes hash exactly like plain sha256.

The CLI takes --bit-length with a hex input, the tools take bitLength in parameters. HMAC and length extension only do whole bytes, and say so.