---
title: "SHA-256"
description: "The SHA-2 hash everything agrees on. 32 bytes with HMAC and the default when nobody told you otherwise"
canonical_url: "https://hashes.agntn.dev/algorithms/sha256"
---
# SHA-256

> The SHA-2 hash everything agrees on. 32 bytes with HMAC and the default when nobody told you otherwise

<algorithm-facts name="sha256">



</algorithm-facts>

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](https://hashes.agntn.dev/algorithms/hash256). Under RIPEMD-160 it becomes [HASH160](https://hashes.agntn.dev/algorithms/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](https://hashes.agntn.dev/guide/extend) only do whole bytes, and say so.


## Sitemap

See the full [sitemap](https://hashes.agntn.dev/sitemap.md) for all pages.
