# Crypto

> Hashes, MACs, and constant-time comparison.

```zig
const std = @import("std");
const expect = std.testing.expect;

test "sha256" {
    var digest: [32]u8 = undefined;
    std.crypto.hash.sha2.Sha256.hash("abc", &digest, .{});

    // The well-known SHA-256 of "abc".
    var hex: [64]u8 = undefined;
    const text = try std.fmt.bufPrint(&hex, "{x}", .{digest});
    try expect(std.mem.startsWith(u8, text, "ba7816bf"));
}

test "incremental hashing" {
    var hasher = std.crypto.hash.sha2.Sha256.init(.{});
    hasher.update("a");
    hasher.update("bc");

    var digest: [32]u8 = undefined;
    hasher.final(&digest);

    var one_shot: [32]u8 = undefined;
    std.crypto.hash.sha2.Sha256.hash("abc", &one_shot, .{});
    try expect(std.mem.eql(u8, &digest, &one_shot));
}

test "compare secrets in constant time" {
    const a = [_]u8{ 1, 2, 3 };
    const b = [_]u8{ 1, 2, 3 };
    // `std.mem.eql` short-circuits, which leaks how much matched via timing.
    try expect(std.crypto.timing_safe.eql([3]u8, a, b));
}

test "hmac" {
    const Hmac = std.crypto.auth.hmac.sha2.HmacSha256;
    var mac: [Hmac.mac_length]u8 = undefined;
    Hmac.create(&mac, "message", "key");
    try expect(mac.len == 32);
}

test "password hashing is deliberately slow" {
    // bcrypt/scrypt/argon2 are the right tools for passwords; a bare hash
    // is not. They are omitted from this runnable example precisely because
    // they are designed to take a long time.
    try expect(@hasDecl(std.crypto.pwhash, "argon2"));
}
```

*Runnable: compiled to WebAssembly and executed by CI against Zig master. (`03-standard-library.crypto`)*

Zig ships a substantial crypto library in `std.crypto` (hashes, AEADs, key
exchange, signatures) with no external dependency.

## One-shot and incremental

```zig
Sha256.hash(data, &digest, .{});          // one-shot

var hasher = Sha256.init(.{});            // incremental
hasher.update(part1);
hasher.update(part2);
hasher.final(&digest);
```

Both produce the same digest; use the incremental form when the input arrives
in pieces or is too large to hold at once.

## Constant-time comparison

```zig
std.crypto.timing_safe.eql([32]u8, a, b)
```

`std.mem.eql` returns as soon as it finds a difference, so how long it took
reveals how many bytes matched. For MACs, tokens, and password hashes that is a
real attack. Use the timing-safe form for anything secret.

## Passwords are a different problem

Do not hash passwords with SHA-256. `std.crypto.pwhash` provides argon2,
bcrypt, and scrypt, which are deliberately slow and salted. That slowness is
the feature: it is what makes an offline guessing attack expensive.
