---
title: "@unikvs/checksum"
description: "バイト列のハッシュを計算して期待値と照合するミドルウェア @unikvs/checksum の使い方を説明します。"
---

## 概要 [#overview]

バイト列のハッシュを計算し、期待値と照合するミドルウェアです。Middleware

このミドルウェアはデータを変更せずに透過させ、チェックサム変数に期待ハッシュがある場合のみ検証します。MD5・SHA-1・SHA-224・SHA-256・SHA-384・SHA-512 の 6 種類があります。

- 具象クラスの `name` はクラス名と同じです (例: `"ChecksumSha256"`)。
- `isOpen` はつねに `true` です。

インストールは次のコマンドで行います。

```package-install
npm install @unikvs/checksum @noble/hashes@2.0.0
```

## 使い方 [#usage]

ChecksumSha256 は IMiddleware を実装しています。UniKvs には use() で渡します。

```ts
import { ChecksumSha256 } from "@unikvs/checksum";
```

他の 5 種類も同様に使います。コンストラクターの引数は次のとおりです。

| Prop | Type | Default | Description |
| - | - | - | - |
| `required?` | `[#checksum-required] boolean` | - | チェックサム変数がない場合にエラーを投げるかどうかです。省略時は `false` です。 |

以下は、SHA-256 の期待ハッシュを指定して保存し、読み取り時に照合する例です。

```ts
import { ChecksumSha256 } from "@unikvs/checksum";
import { Memory } from "@unikvs/memory";
import * as unikvs from "unikvs";

const kvs = new unikvs.Builder<{ file: unikvs.Value<Uint8Array> }>()
  .use(new ChecksumSha256())
  .persist(new Memory())
  .build();

await kvs.open();

const data = new TextEncoder().encode("abc");
const sha256 = "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad";

await kvs.set("file", data, {
  vars: { "@unikvs/checksum:sha256": sha256 },
});
const file = await kvs.get("file", {
  vars: { "@unikvs/checksum:sha256": sha256 },
});
await kvs.close();
```

### `Checksum` [#checksum]

6 種類の抽象基底クラスです。直接は使わず、具象クラスを経由して使います。

`CHECKSUM_ON_HASH_VAR_NAME` は、計算したハッシュを受け取るコールバック変数の名前です。値は `CHECKSUM_VAR_NAME` に `:onHash` を付けたものになります。

### `ChecksumMd5` [#checksum-md5]

MD5 で検証するミドルウェアです。チェックサム変数は `"@unikvs/checksum:md5"` です。

### `ChecksumSha1` [#checksum-sha1]

SHA-1 で検証するミドルウェアです。チェックサム変数は `"@unikvs/checksum:sha1"` です。

### `ChecksumSha224` [#checksum-sha224]

SHA-224 で検証するミドルウェアです。チェックサム変数は `"@unikvs/checksum:sha224"` です。

### `ChecksumSha256` [#checksum-sha256]

SHA-256 で検証するミドルウェアです。チェックサム変数は `"@unikvs/checksum:sha256"` です。

### `ChecksumSha384` [#checksum-sha384]

SHA-384 で検証するミドルウェアです。チェックサム変数は `"@unikvs/checksum:sha384"` です。

### `ChecksumSha512` [#checksum-sha512]

SHA-512 で検証するミドルウェアです。チェックサム変数は `"@unikvs/checksum:sha512"` です。

### `IHasher` [#ihasher]

逐次ハッシュ計算のインターフェースです。`@noble/hashes` のハッシャーに対応します。

| Prop | Type | Default | Description |
| - | - | - | - |
| `update` | `[#ihasher-update] (data: Uint8Array<ArrayBuffer>) => void` | - | データをハッシュ計算へ追加します。 |
| `digest` | `[#ihasher-digest] () => Uint8Array` | - | 計算結果のハッシュを返します。 |

### `IHash` [#ihash]

一括ハッシュ計算の関数と、ハッシャー生成の `create` を持つインターフェースです。

| Prop | Type | Default | Description |
| - | - | - | - |
| `create` | `[#ihash-create] () => IHasher` | - | 逐次計算用のハッシャーを作ります。 |

### `ChecksumOnHash` [#checksum-on-hash]

計算したハッシュを受け取るコールバックです。チェックサム変数とは別に、`"<CHECKSUM_VAR_NAME>:onHash"` という変数へ関数を渡します。たとえば SHA-256 では `"@unikvs/checksum:sha256:onHash"` です。

コールバックの `this` にはミドルウェアのインスタンスが割り当てられ、第一引数には実行コンテキスト、第二引数には計算したハッシュが渡されます。

コールバックは、ハッシュの計算と検証が成功したときに呼ばれます。期待値を指定せずにコールバックだけを指定した場合も、ハッシュを計算して呼び出します。`required` が `true` で期待値がない場合は `ChecksumRequiredError` を投げ、コールバックは呼びません。

以下は、SHA-256 の計算結果を受け取る例です。

```ts
const hashes: string[] = [];

await kvs.set("file", data, {
  vars: {
    "@unikvs/checksum:sha256:onHash": function (
      this: ChecksumSha256,
      c: IPipelineContext,
      hash: string,
    ): void {
      hashes.push(hash);
    },
  },
});
```

コールバックが関数でない場合は `ChecksumInvalidOnHashError` を投げます。コールバックが投げた例外や拒否は、操作の失敗としてそのまま伝播します。

:::note[呼び出しタイミング]
コールバックはハッシュの計算が完了した時点で呼ばれます。ストレージへの書き込み完了を保証するものではありません。ストリームではストリームの終了時に呼ばれます。
:::

## データ型 [#data-types]

| メソッド       | 入力                      | 出力                      |
| -------------- | ------------------------- | ------------------------- |
| `encode`       | `Uint8Array<ArrayBuffer>` | `Uint8Array<ArrayBuffer>` |
| `decode`       | `Uint8Array<ArrayBuffer>` | `Uint8Array<ArrayBuffer>` |
| `encodeStream` | `Uint8Array<ArrayBuffer>` | `Uint8Array<ArrayBuffer>` |
| `decodeStream` | `Uint8Array<ArrayBuffer>` | `Uint8Array<ArrayBuffer>` |

- `encode` と `decode` はデータを変更せず、そのまま通します。
- このミドルウェアは対応するチェックサム変数に文字列がある場合、または `onHash` コールバックが指定されている場合に、ハッシュ (16 進小文字) を計算します。
- 期待値と一致しない場合はエラーを投げます。
- チェックサム変数がなく `required` が `true` の場合は、`onHash` コールバックが指定されていてもエラーを投げます。
- `onHash` コールバックの `this` にはミドルウェアのインスタンスが割り当てられ、第一引数に実行コンテキスト、第二引数に計算したハッシュ (16 進小文字) が渡されます。コールバックが `Promise` を返す場合は完了を待ちます。
- `encodeStream` と `decodeStream` はチャンクをそのまま下流へ流しながらハッシュを更新し、終了時に照合して `onHash` コールバックを呼びます。

## エラー [#errors]

このパッケージが投げるエラーは次のとおりです。

### `ChecksumMismatchError` [#error-checksum-mismatch]

計算したハッシュと期待値が一致しないときに、このエラーが投げられます。

| Prop | Type | Default | Description |
| - | - | - | - |
| `actual` | `[#checksum-mismatch-actual] string` | - | 計算したハッシュ (16 進小文字) です。 |
| `expected` | `[#checksum-mismatch-expected] string` | - | チェックサム変数で指定された期待ハッシュです。 |

#### 意味

データか期待値のどちらかが正しくありません。

#### 対処方法

データと期待ハッシュのどちらが正しいか確認してください。

### `ChecksumRequiredError` [#error-checksum-required]

#### 意味

`required` が `true` なのにチェックサム変数が指定されなかったときに、このエラーが投げられます。

#### 対処方法

対応するチェックサム変数に期待ハッシュを指定するか、`required` を `false` にしてください。

### `ChecksumInvalidVarNameError` [#error-checksum-invalid-var-name]

チェックサム変数の名前が文字列でないときに、このエラーが投げられます。

| Prop | Type | Default | Description |
| - | - | - | - |
| `actual` | `[#checksum-invalid-var-name-actual] unknown` | - | 指定された変数名の値です。 |

#### 意味

使い方の誤りのため、`InvalidUsageErrorBase` を継承します。`meta.actual` に指定値をそのまま保持します。

#### 対処方法

公開されている具象クラスをそのまま使う場合は発生しません。自作のサブクラスでは `CHECKSUM_VAR_NAME` に文字列を設定してください。

### `ChecksumInvalidOnHashError` [#error-checksum-invalid-on-hash]

`"<CHECKSUM_VAR_NAME>:onHash"` の値が関数でないときに、このエラーが投げられます。

| Prop | Type | Default | Description |
| - | - | - | - |
| `actual` | `[#checksum-invalid-on-hash-actual] unknown` | - | 指定されたコールバックの値です。 |

#### 意味

使い方の誤りのため、`InvalidUsageErrorBase` を継承します。`meta.actual` に指定値をそのまま保持します。

#### 対処方法

`onHash` 変数に関数を指定するか、変数自体を省略してください。

### `ChecksumInvalidRequiredError` [#error-checksum-invalid-required]

`required` オプションに真偽値以外を指定すると、このエラーが投げられます。

| Prop | Type | Default | Description |
| - | - | - | - |
| `actual` | `[#checksum-invalid-required-actual] unknown` | - | 指定された `required` の値です。 |

#### 意味

使い方の誤りのため、`InvalidUsageErrorBase` を継承します。`meta.actual` に指定値をそのまま保持します。

#### 対処方法

`required` に `true` か `false` を指定してください。省略時は `false` です。
