

 **このページは、ボールトと 2012 年リリース当時の REST API を使用する、Amazon Glacier サービスの既存のお客様のみを対象としています。**

アーカイブストレージソリューションをお探しの場合は、Amazon S3 の Amazon Glacier ストレージクラス (S3 Glacier Instant Retrieval、S3 Glacier Flexible Retrieval、S3 Glacier Deep Archive) を使用することをお勧めします。これらのストレージオプションの詳細については、「[Amazon Glacier ストレージクラス](https://aws.amazon.com/s3/storage-classes/glacier/)」を参照してください。

Amazon Glacier (元のスタンドアロンボールトベースのサービス) は、新規顧客を受け入れなくなりました。Amazon Glacier は、ボールトにデータを保存する独自の API を備えたスタンドアロンサービスであり、Amazon S3 および Amazon S3 Glacier ストレージクラスとは異なります。既存のデータは Amazon Glacier で無期限に安全性が確保され、引き続きアクセス可能です。移行は必要ありません。低コストの長期アーカイブストレージの場合、 は [Amazon S3 Glacier ストレージクラス](https://aws.amazon.com/s3/storage-classes/glacier/) AWS を推奨します。これにより、S3 バケットベースの APIs、低コスト、 AWS サービス統合で優れたカスタマーエクスペリエンスを実現できます。 AWS リージョン 拡張機能が必要な場合は、[Amazon Glacier ボールトから Amazon S3 Glacier ストレージクラスにデータを転送するためのAWS ソリューションガイダンス](https://aws.amazon.com/solutions/guidance/data-transfer-from-amazon-s3-glacier-vaults-to-amazon-s3/)を使用して、Amazon S3 Glacier ストレージクラスへの移行を検討してください。

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# チェックサムの計算
<a name="checksum-calculations"></a>

アーカイブをアップロードする場合は、`x-amz-sha256-tree-hash` ヘッダーと `x-amz-content-sha256` ヘッダーを両方とも含める必要があります。`x-amz-sha256-tree-hash` ヘッダーは、リクエストボディのペイロードのチェックサムです。このトピックでは、`x-amz-sha256-tree-hash` ヘッダーを計算する方法について説明します。`x-amz-content-sha256` ヘッダーはペイロード全体のハッシュであり、認可に必要です。詳細については、「[ストリーミング API の署名の計算例](amazon-glacier-signing-requests.md#example-signature-calculation-streaming)」を参照してください。

リクエストのペイロードは以下のようになります。

 
+ ** アーカイブ全体 -** アーカイブのアップロード API を使用して単一のリクエストでアーカイブをアップロードする場合は、リクエストボディでアーカイブ全体を送信します。この場合は、アーカイブ全体のチェックサムを含める必要があります。
+ ** アーカイブのパート -** マルチパートアップロード API を使用してアーカイブをパート単位でアップロードする場合は、リクエストボディでアーカイブのパートを 1 つのみ送信します。この場合は、アーカイブのパートのチェックサムを含めます。すべてのパートをアップロードしたら、マルチパートアップロードの完了リクエストを送信します。これにはアーカイブ全体のチェックサムを含める必要があります。

ペイロードのチェックサムは、SHA-256 木構造ハッシュです。チェックサムの計算中に SHA-256 ハッシュ値の木構造を計算することから、木構造ハッシュと呼ばれます。ルートのハッシュ値はアーカイブ全体のチェックサムです。

 

**注記**  
このセクションでは、SHA-256 木構造ハッシュを計算する方法を説明します。ただし、同じ結果になる限り、任意の方法を使用できます。

次のように、SHA-256 木構造ハッシュを計算します。

 

1. ペイロードデータの 1 MB のチャンクごとに、SHA-256 ハッシュを計算します。データの最後のチャンクは 1 MB を下回ることがあります。たとえば、3.2 MB のアーカイブをアップロードする場合、データの最初の 3 個の 1 MB のチャンクごとに SHA-256 ハッシュ値を計算してから、残りの 0.2 MB のデータの SHA-256 ハッシュを計算します。これらのハッシュ値は木構造の葉ノードを構成します。

1. 木構造の次のレベルを作成します。

   1. 2 つの連続した子ノードのハッシュ値を連結し、連結したハッシュ値の SHA-256 ハッシュを計算します。この連結と SHA-256 ハッシュの生成により、2 個の子ノードの親ノードが作成されます。

   1. 子ノードが 1 個だけ残った場合は、そのハッシュ値を木構造の次のレベルに昇格させます。

1. 結果の木構造にルートが含まれるまで、ステップ 2 を繰り返します。木構造のルートではアーカイブ全体のハッシュが提供され、サブツリーのルートではマルチパートアップロードの対応するパートのハッシュが提供されます。

**Topics**
+ [木構造ハッシュの例 1: 単一のリクエストでのアーカイブのアップロード](#checksum-calculations-upload-archive-in-single-payload)
+ [木構造ハッシュの例 2: マルチパートアップロードを使用したアーカイブのアップロード](#checksum-calculations-upload-archive-using-mpu)
+ [ファイルの木構造ハッシュの計算](#checksum-calculations-examples)
+ [データをダウンロードするときのチェックサムの受信](checksum-calculations-range.md)

## 木構造ハッシュの例 1: 単一のリクエストでのアーカイブのアップロード
<a name="checksum-calculations-upload-archive-in-single-payload"></a>

アーカイブのアップロード API を使用して単一のリクエストでアーカイブをアップロードする場合 (「[アーカイブのアップロード (POST archive)](api-archive-post.md)」を参照)、リクエストのペイロードにはアーカイブ全体が含まれます。このため、アーカイブ全体の木構造ハッシュを `x-amz-sha256-tree-hash` リクエストヘッダーに含める必要があります。6.5 MB のアーカイブをアップロードするとします。次の図は、アーカイブの SHA-256 ハッシュを作成するプロセスを示しています。アーカイブを読み取り、1 MB のチャンクそれぞれの SHA-256 ハッシュを計算します。残りの 0.5 MB のデータのハッシュも計算し、前の手順で説明したように木構造を作成します。

 

![\[単一のリクエストでアーカイブをアップロードする木構造ハッシュの例を示す図。\]](http://docs.aws.amazon.com/ja_jp/amazonglacier/latest/dev/images/TreeHash-ArchiveUploadSingleRequest.png)


## 木構造ハッシュの例 2: マルチパートアップロードを使用したアーカイブのアップロード
<a name="checksum-calculations-upload-archive-using-mpu"></a>

マルチパートアップロードでアーカイブをアップロードする場合の木構造ハッシュの計算のプロセスは、単一のリクエストでアーカイブをアップロードする場合と同じです。唯一の違いは、 ([パートのアップロード (PUT uploadID)](api-upload-part.md) API を使用して) 各リクエストでアーカイブのパートを 1 つのみアップロードする点です。したがって、そのパートのチェックサムのみを `x-amz-sha256-tree-hash` リクエストヘッダーに含めます。ただし、すべてのパートをアップロードした後で、 [マルチパートアップロードの完了 (POST uploadID)](api-multipart-complete-upload.md)リクエストヘッダーにアーカイブ全体の木構造ハッシュを含めたマルチパートアップロードの完了 (「`x-amz-sha256-tree-hash`」を参照) リクエストを送信する必要があります。

 

![\[マルチパートアップロードを使用してアーカイブをアップロードする木構造ハッシュの例を示す図。\]](http://docs.aws.amazon.com/ja_jp/amazonglacier/latest/dev/images/TreeHash-MPU.png)


## ファイルの木構造ハッシュの計算
<a name="checksum-calculations-examples"></a>

以下に示すアルゴリズムは、デモンストレーションのために選択したものです。実装シナリオでは、必要に応じてコードを最適化できます。Amazon Glacier で Amazon SDK を使用してプログラミングする場合は、木構造ハッシュの計算が自動的に行われるため、必要な作業はファイルの参照を指定することのみです。

**Example 1: Java の例**  
以下の例は、Java を使用してファイルの SHA256 木構造ハッシュを計算する方法を示しています。この例は、ファイルの場所を引数として指定するか、コードから直接 `TreeHashExample.computeSHA256TreeHash` メソッドを使用することで実行できます。  

```
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class TreeHashExample {

static final int ONE_MB = 1024 * 1024;

    /**
     * Compute the Hex representation of the SHA-256 tree hash for the specified
     * File
     * 
     * @param args
     *            args[0]: a file to compute a SHA-256 tree hash for
     */
    public static void main(String[] args) {

        if (args.length < 1) {
            System.err.println("Missing required filename argument");
            System.exit(-1);
        }

        File inputFile = new File(args[0]);
        try {

            byte[] treeHash = computeSHA256TreeHash(inputFile);
            System.out.printf("SHA-256 Tree Hash = %s\n", toHex(treeHash));

        } catch (IOException ioe) {
            System.err.format("Exception when reading from file %s: %s", inputFile,
                    ioe.getMessage());
            System.exit(-1);

        } catch (NoSuchAlgorithmException nsae) {
            System.err.format("Cannot locate MessageDigest algorithm for SHA-256: %s",
                    nsae.getMessage());
            System.exit(-1);
        }
    }

    /**
     * Computes the SHA-256 tree hash for the given file
     * 
     * @param inputFile
     *            a File to compute the SHA-256 tree hash for
     * @return a byte[] containing the SHA-256 tree hash
     * @throws IOException
     *             Thrown if there's an issue reading the input file
     * @throws NoSuchAlgorithmException
     */
    public static byte[] computeSHA256TreeHash(File inputFile) throws IOException,
            NoSuchAlgorithmException {

        byte[][] chunkSHA256Hashes = getChunkSHA256Hashes(inputFile);
        return computeSHA256TreeHash(chunkSHA256Hashes);
    }

    /**
     * Computes a SHA256 checksum for each 1 MB chunk of the input file. This
     * includes the checksum for the last chunk even if it is smaller than 1 MB.
     * 
     * @param file
     *            A file to compute checksums on
     * @return a byte[][] containing the checksums of each 1 MB chunk
     * @throws IOException
     *             Thrown if there's an IOException when reading the file
     * @throws NoSuchAlgorithmException
     *             Thrown if SHA-256 MessageDigest can't be found
     */
    public static byte[][] getChunkSHA256Hashes(File file) throws IOException,
            NoSuchAlgorithmException {

        MessageDigest md = MessageDigest.getInstance("SHA-256");

        long numChunks = file.length() / ONE_MB;
        if (file.length() % ONE_MB > 0) {
            numChunks++;
        }

        if (numChunks == 0) {
            return new byte[][] { md.digest() };
        }

        byte[][] chunkSHA256Hashes = new byte[(int) numChunks][];
        FileInputStream fileStream = null;

        try {
            fileStream = new FileInputStream(file);
            byte[] buff = new byte[ONE_MB];

            int bytesRead;
            int idx = 0;
            int offset = 0;

            while ((bytesRead = fileStream.read(buff, offset, ONE_MB)) > 0) {
                md.reset();
                md.update(buff, 0, bytesRead);
                chunkSHA256Hashes[idx++] = md.digest();
                offset += bytesRead;
            }

            return chunkSHA256Hashes;

        } finally {
            if (fileStream != null) {
                try {
                    fileStream.close();
                } catch (IOException ioe) {
                    System.err.printf("Exception while closing %s.\n %s", file.getName(),
                            ioe.getMessage());
                }
            }
        }
    }

    /**
     * Computes the SHA-256 tree hash for the passed array of 1 MB chunk
     * checksums.
     * 
     * This method uses a pair of arrays to iteratively compute the tree hash
     * level by level. Each iteration takes two adjacent elements from the
     * previous level source array, computes the SHA-256 hash on their
     * concatenated value and places the result in the next level's destination
     * array. At the end of an iteration, the destination array becomes the
     * source array for the next level.
     * 
     * @param chunkSHA256Hashes
     *            An array of SHA-256 checksums
     * @return A byte[] containing the SHA-256 tree hash for the input chunks
     * @throws NoSuchAlgorithmException
     *             Thrown if SHA-256 MessageDigest can't be found
     */
    public static byte[] computeSHA256TreeHash(byte[][] chunkSHA256Hashes)
            throws NoSuchAlgorithmException {

        MessageDigest md = MessageDigest.getInstance("SHA-256");

        byte[][] prevLvlHashes = chunkSHA256Hashes;

        while (prevLvlHashes.length > 1) {

            int len = prevLvlHashes.length / 2;
            if (prevLvlHashes.length % 2 != 0) {
                len++;
            }

            byte[][] currLvlHashes = new byte[len][];

            int j = 0;
            for (int i = 0; i < prevLvlHashes.length; i = i + 2, j++) {

                // If there are at least two elements remaining
                if (prevLvlHashes.length - i > 1) {

                    // Calculate a digest of the concatenated nodes
                    md.reset();
                    md.update(prevLvlHashes[i]);
                    md.update(prevLvlHashes[i + 1]);
                    currLvlHashes[j] = md.digest();

                } else { // Take care of remaining odd chunk
                    currLvlHashes[j] = prevLvlHashes[i];
                }
            }

            prevLvlHashes = currLvlHashes;
        }

        return prevLvlHashes[0];
    }

    /**
     * Returns the hexadecimal representation of the input byte array
     * 
     * @param data
     *            a byte[] to convert to Hex characters
     * @return A String containing Hex characters
     */
    public static String toHex(byte[] data) {
        StringBuilder sb = new StringBuilder(data.length * 2);

        for (int i = 0; i < data.length; i++) {
            String hex = Integer.toHexString(data[i] & 0xFF);

            if (hex.length() == 1) {
                // Append leading zero.
                sb.append("0");
            }
            sb.append(hex);
        }
        return sb.toString().toLowerCase();
    }
}
```

**Example 2: C\$1 .NET の例**  
以下の例は、ファイルの SHA256 木構造ハッシュを計算する方法を示しています。この例は、ファイルの場所を引数として指定して実行できます。  

```
using System;
using System.IO;

using System.Security.Cryptography;

namespace ExampleTreeHash
{
    class Program
    {
        static int ONE_MB = 1024 * 1024;

        /**
        * Compute the Hex representation of the SHA-256 tree hash for the
        * specified file
        * 
        * @param args
        *            args[0]: a file to compute a SHA-256 tree hash for
        */
        public static void Main(string[] args)
        {
            if (args.Length < 1)
            {
                Console.WriteLine("Missing required filename argument");
                Environment.Exit(-1);
            }
            FileStream inputFile = File.Open(args[0], FileMode.Open, FileAccess.Read);
            try
            {
                byte[] treeHash = ComputeSHA256TreeHash(inputFile);
                Console.WriteLine("SHA-256 Tree Hash = {0}", BitConverter.ToString(treeHash).Replace("-", "").ToLower());
                Console.ReadLine();
                Environment.Exit(-1);
            }
            catch (IOException ioe)
            {
                Console.WriteLine("Exception when reading from file {0}: {1}",
                    inputFile, ioe.Message);
                Console.ReadLine();
                Environment.Exit(-1);
            }
            catch (Exception e)
            {
                Console.WriteLine("Cannot locate MessageDigest algorithm for SHA-256: {0}",
                    e.Message);
                Console.WriteLine(e.GetType());
                Console.ReadLine();
                Environment.Exit(-1);
            }
            Console.ReadLine();
        }


        /**
         * Computes the SHA-256 tree hash for the given file
         * 
         * @param inputFile
         *            A file to compute the SHA-256 tree hash for
         * @return a byte[] containing the SHA-256 tree hash
         */
        public static byte[] ComputeSHA256TreeHash(FileStream inputFile)
        {
            byte[][] chunkSHA256Hashes = GetChunkSHA256Hashes(inputFile);
            return ComputeSHA256TreeHash(chunkSHA256Hashes);
        }


        /**
         * Computes a SHA256 checksum for each 1 MB chunk of the input file. This
         * includes the checksum for the last chunk even if it is smaller than 1 MB.
         * 
         * @param file
         *            A file to compute checksums on
         * @return a byte[][] containing the checksums of each 1MB chunk
         */
        public static byte[][] GetChunkSHA256Hashes(FileStream file)
        {
            long numChunks = file.Length / ONE_MB;
            if (file.Length % ONE_MB > 0)
            {
                numChunks++;
            }

            if (numChunks == 0)
            {
                return new byte[][] { CalculateSHA256Hash(null, 0) };
            }
            byte[][] chunkSHA256Hashes = new byte[(int)numChunks][];

            try
            {
                byte[] buff = new byte[ONE_MB];

                int bytesRead;
                int idx = 0;

                while ((bytesRead = file.Read(buff, 0, ONE_MB)) > 0)
                {
                    chunkSHA256Hashes[idx++] = CalculateSHA256Hash(buff, bytesRead);
                }
                return chunkSHA256Hashes;
            }
            finally
            {
                if (file != null)
                {
                    try
                    {
                        file.Close();
                    }
                    catch (IOException ioe)
                    {
                        throw ioe;
                    }
                }
            }

        }

        /**
         * Computes the SHA-256 tree hash for the passed array of 1MB chunk
         * checksums.
         * 
         * This method uses a pair of arrays to iteratively compute the tree hash
         * level by level. Each iteration takes two adjacent elements from the
         * previous level source array, computes the SHA-256 hash on their
         * concatenated value and places the result in the next level's destination
         * array. At the end of an iteration, the destination array becomes the
         * source array for the next level.
         * 
         * @param chunkSHA256Hashes
         *            An array of SHA-256 checksums
         * @return A byte[] containing the SHA-256 tree hash for the input chunks
         */
        public static byte[] ComputeSHA256TreeHash(byte[][] chunkSHA256Hashes)
        {
            byte[][] prevLvlHashes = chunkSHA256Hashes;
            while (prevLvlHashes.GetLength(0) > 1)
            {

                int len = prevLvlHashes.GetLength(0) / 2;
                if (prevLvlHashes.GetLength(0) % 2 != 0)
                {
                    len++;
                }

                byte[][] currLvlHashes = new byte[len][];

                int j = 0;
                for (int i = 0; i < prevLvlHashes.GetLength(0); i = i + 2, j++)
                {

                    // If there are at least two elements remaining
                    if (prevLvlHashes.GetLength(0) - i > 1)
                    {

                        // Calculate a digest of the concatenated nodes
                        byte[] firstPart = prevLvlHashes[i];
                        byte[] secondPart = prevLvlHashes[i + 1];
                        byte[] concatenation = new byte[firstPart.Length + secondPart.Length];
                        System.Buffer.BlockCopy(firstPart, 0, concatenation, 0, firstPart.Length);
                        System.Buffer.BlockCopy(secondPart, 0, concatenation, firstPart.Length, secondPart.Length);

                        currLvlHashes[j] = CalculateSHA256Hash(concatenation, concatenation.Length);

                    }
                    else
                    { // Take care of remaining odd chunk
                        currLvlHashes[j] = prevLvlHashes[i];
                    }
                }

                prevLvlHashes = currLvlHashes;
            }

            return prevLvlHashes[0];
        }

        public static byte[] CalculateSHA256Hash(byte[] inputBytes, int count)
        {
            SHA256 sha256 = System.Security.Cryptography.SHA256.Create();
            byte[] hash = sha256.ComputeHash(inputBytes, 0, count);
            return hash;
        }
    }
}
```

# データをダウンロードするときのチェックサムの受信
<a name="checksum-calculations-range"></a>

ジョブの開始 API を使用してアーカイブを取得する場合は (「[ジョブの開始 (ジョブの POST)](api-initiate-job-post.md)」を参照)、オプションでアーカイブの取得範囲を指定できます。同様に、ジョブの出力の取得 API を使用してデータをダウンロードする場合は (「[ジョブの出力の取得 (GET output)](api-job-output-get.md)」を参照)、オプションでダウンロードするデータの範囲を指定できます。これらの範囲には、アーカイブのデータを取得およびダウンロードする際に理解していることが重要な 2 つの特性があります。取得する範囲は、アーカイブに対して*メガバイト単位に調整*する必要があります。データをダウンロードしたときにチェックサム値を受け取るには、取得する範囲とダウンロードする範囲が両方とも*木構造ハッシュ可能*である必要があります。この 2 つのタイプの範囲の調整は、次のように定義されています。

 
+ メガバイト単位調整 – 範囲 [*StartByte*,*EndBytes*] は、*StartBytes* が 1 MB で割り切れ、かつ *EndBytes* に 1 を足した値 が 1 MB で割り切れるか、指定されたアーカイブの末尾 (アーカイブのバイトサイズから 1 を引いた値) と等しい場合、メガバイト (1024\$11024) 単位調整されています。ジョブの開始 API で使用する範囲 (指定した場合) は、メガバイト単位に調整する必要があります。
+ 木構造ハッシュ可能 - 範囲 [*StartBytes*, *EndBytes*] は、その範囲で構築された木構造ハッシュのルートがアーカイブ全体の木構造ハッシュ内のノードに相当する場合のみ、アーカイブに対して木構造ハッシュ可能です。ダウンロードしたデータのチェックサム値を受け取るには、取得する範囲とダウンロードする範囲が両方とも木構造ハッシュ可能である必要があります。範囲の例およびアーカイブ木構造ハッシュとの関係については、「[木構造ハッシュの例: 木構造ハッシュ可能なアーカイブの範囲を取得する](#checksum-calculations-upload-archive-with-ranges)」を参照してください。

  木構造ハッシュ可能な範囲は、メガバイト単位にも調整できることに注意してください。ただし、メガバイト単位に調整された範囲が木構造ハッシュ可能であるとは限りません。

以下は、アーカイブデータをダウンロードしたときにチェックサムを受け取る場合を示しています。

 
+ ジョブの開始リクエストで取得する範囲を指定せず、ジョブの取得リクエストでアーカイブ全体をダウンロードした場合。
+ ジョブの開始リクエストで取得する範囲を指定せず、ジョブの取得リクエストでダウンロードする木構造ハッシュ可能な範囲を指定した場合。
+ ジョブの開始リクエストで取得する木構造ハッシュ可能な範囲を指定し、ジョブの取得リクエストでその範囲全体をダウンロードした場合。
+ ジョブの開始リクエストで取得する木構造ハッシュ可能な範囲を指定し、ジョブの取得リクエストでダウンロードする木構造ハッシュ可能な範囲を指定した場合。

ジョブの開始リクエストで取得する範囲を指定し、その範囲が木構造ハッシュ可能ではない場合は、ジョブの取得リクエストでデータをダウンロードしたときにアーカイブデータを取得できますが、チェックサム値は返されません。

## 木構造ハッシュの例: 木構造ハッシュ可能なアーカイブの範囲を取得する
<a name="checksum-calculations-upload-archive-with-ranges"></a>

ボールト内に 6.5 MB のアーカイブがあり、アーカイブの 2 MB 分を取得するとします。ジョブの開始リクエストで 2 MB の範囲を指定する方法によって、データのダウンロード時にデータチェックサム値を受け取るかどうかが決定されます。次の図は、6.5 MB のアーカイブに対してダウンロードできる 2 つの 2 MB の範囲を示しています。両方ともメガバイト単位に調整されていますが、木構造ハッシュ可能な範囲は 1 つのみです。

 

![\[木構造ハッシュにアラインされたアーカイブ範囲の取得を示す図。\]](http://docs.aws.amazon.com/ja_jp/amazonglacier/latest/dev/images/TreeHash-ArchiveWithRanges.png)


## 木構造ハッシュ可能な範囲の指定
<a name="tree-hash-algorithm"></a>

このセクションでは、木構造ハッシュ可能な範囲の正確な指定について説明します。木構造ハッシュ可能な範囲は、アーカイブの一部分をダウンロードするときに、取得する範囲のデータと、取得したデータからダウンロードする範囲を指定する場合に重要です。これらの範囲が両方とも木構造ハッシュ可能である場合は、データをダウンロードしたときにチェックサムデータを受け取ります。

範囲 [*A*,*B*] がアーカイブに関して木構造ハッシュ可能なのは、新しい*木構造ハッシュ*が [*A*,*B*] の上に構築されるとき、その範囲の木構造ハッシュのルートがアーカイブ全体の木構造ハッシュ内のノードに相当する場合に限られます。これについては、「[木構造ハッシュの例: 木構造ハッシュ可能なアーカイブの範囲を取得する](#checksum-calculations-upload-archive-with-ranges)」の図に示されています。このセクションでは、木構造ハッシュ可能な範囲の指定について説明します。

[*P*, *Q*] を、*N* メガバイト (MB) のアーカイブの範囲クエリとします。*P* および *Q* は 1 MB の倍数です。実際に含まれる範囲は [*P* MB,*Q* MB 1 バイト] ですが、単純化のために、[*P*, *Q*) と表しています。これらの前提に立つと、次のようになります。

 
+ *​P* が奇数の場合、木構造ハッシュ可能な範囲は 1 つのみ、つまり [*P*, *P* \$1 1 MB) です。
+ *P* が偶数で *k* が最大数です。*P*は、2*k* \$1 *X* とすると、*P* で始まる木構造ハッシュ可能な範囲は最大で *k* です。*X*は、0 より大きい整数です。木構造ハッシュ可能な範囲は、次のカテゴリに含まれます。
  + それぞれの *i* に対して、(0 <= *i* <= *k*) で、*P* \$1 2*i* < *N* の場合、[*P*, *Q* \$1 2*i*) は木構造ハッシュ可能な範囲です。
  + *P* = 0 は、*A* = 2[lgN]\$10 である特殊なケースです。