# `Stevedore.Digest`
[🔗](https://github.com/oshlabs/stevedore/blob/v0.2.0/lib/stevedore/digest.ex#L1)

A content digest: an `algorithm:hex` pair identifying bytes by their hash.

Digests are the unit of content addressing throughout OCI — manifests, configs, and layers
are all referenced by digest, and the digest is always computed over the **raw bytes** as they
appear on the wire (never over a re-serialized form).

Spec: [OCI image-spec, descriptor "Digests"](https://github.com/opencontainers/image-spec/blob/main/descriptor.md#digests).

# `algorithm`

```elixir
@type algorithm() :: :sha256 | :sha512
```

# `t`

```elixir
@type t() :: %Stevedore.Digest{algorithm: algorithm(), hex: String.t()}
```

# `compute`

```elixir
@spec compute(iodata(), algorithm()) :: t()
```

Computes the digest of `data` with `algorithm` (default `:sha256`).

## Examples

    iex> Stevedore.Digest.compute("") |> to_string()
    "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

    iex> Stevedore.Digest.compute("hello", :sha256).hex
    "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"

# `parse`

```elixir
@spec parse(String.t()) :: {:ok, t()} | {:error, {:bad_input, term()}}
```

Parses an `"algorithm:hex"` string into a digest.

Rejects unknown algorithms, wrong hex length, and non-lowercase-hex — never converts the
algorithm with `String.to_atom/1` (it is matched against a fixed allowlist).

## Examples

    iex> {:ok, d} = Stevedore.Digest.parse("sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855")
    iex> {d.algorithm, byte_size(d.hex)}
    {:sha256, 64}

    iex> Stevedore.Digest.parse("sha256:nothex")
    {:error, {:bad_input, "invalid digest \"sha256:nothex\""}}

# `short`

```elixir
@spec short(t()) :: String.t()
```

Renders a short, display-only form — the algorithm with the hex truncated to 12 characters.

For logs and `Inspect`, not as an identifier: it is **not** collision-free. Use `to_string/1`
when you need the full, stable digest.

## Examples

    iex> Stevedore.Digest.short(Stevedore.Digest.compute(""))
    "sha256:e3b0c44298fc…"

# `to_path`

```elixir
@spec to_path(t()) :: String.t()
```

Returns the `"algorithm/hex"` path segment used by the OCI blob layout (`blobs/<algo>/<hex>`).

## Examples

    iex> Stevedore.Digest.compute("") |> Stevedore.Digest.to_path()
    "sha256/e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"

# `to_string`

```elixir
@spec to_string(t()) :: String.t()
```

Renders a digest as its canonical `"algorithm:hex"` string.

Also available via `Kernel.to_string/1` through `String.Chars`.

## Examples

    iex> Stevedore.Digest.to_string(%Stevedore.Digest{algorithm: :sha256, hex: "abc"})
    "sha256:abc"

# `verify`

```elixir
@spec verify(iodata(), t()) :: :ok | {:error, :digest_mismatch}
```

Verifies that `data` hashes to `digest`.

## Examples

    iex> Stevedore.Digest.verify("hello", Stevedore.Digest.compute("hello"))
    :ok

    iex> Stevedore.Digest.verify("tampered", Stevedore.Digest.compute("hello"))
    {:error, :digest_mismatch}

---

*Consult [api-reference.md](api-reference.md) for complete listing*
