

 **이 페이지는 볼트와 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는 데이터를 볼트에 저장하고 Amazon S3 및 Amazon S3 Glacier 스토리지 클래스와 구별되는 자체 API를 갖춘 독립 실행형 서비스입니다. 기존 데이터는 Amazon Glacier에서 무기한으로 안전하게 보관되며 액세스 가능합니다. 마이그레이션은 필요하지 않습니다. 저비용 장기 아카이브 스토리지의 경우는 [S3 버킷 기반 API, 전체 가용성, 저렴한 비용 및 서비스 통합을 통해 우수한 고객 경험을 제공하는 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를 사용하여 아카이브를 여러 파트로 나누어 업로드할 때는 요청 본문에서 아카이브 파트만 전송합니다. 이때는 아카이브 파트의 체크섬이 본문에 포함되어야 합니다. 모든 파트를 업로드한 후 멀티파트 업로드 완료 요청을 전송할 때는 전체 아카이브의 체크섬이 포함되어야 합니다.

페이로드 체크섬은 SHA256 트리-해시입니다. 트리-해시라고 불리는 이유는 체크섬을 계산하는 과정에서 SHA256 해시 값으로 이루어진 트리를 계산하기 때문입니다. 루트에 존재하는 해시 값이 전체 아카이브의 체크섬입니다.

 

**참고**  
이 섹션에서는 SHA256 트리-해시를 계산하는 방법에 대해서 다루지만 결과만 동일하다면 어떤 절차를 사용해도 상관없습니다.

SHA256 트리-해시의 계산 방법은 다음과 같습니다.

 

1. 1MB 청크 단위마다 페이로드 데이터의 SHA256 해시를 계산합니다. 마지막 청크 데이터는 1MB보다 작을 수 있습니다. 예를 들어 3.2MB 아카이브를 업로드할 경우 처음 1MB 청크 단위 3개에 대해 각각 SHA256 해시 값을 계산한 후 나머지 0.2MB 데이터의 SHA256 해시 값을 계산합니다. 이러한 해시 값들이 트리의 리프 노드를 형성합니다.

1. 트리에서 다음 계층을 만듭니다.

   1. 이어지는 하위 노드 해시 값 2개를 연결하고 연결된 해시 값의 SHA256 해시를 계산합니다. 이렇게 SHA256 해시를 연결 및 생성하여 하위 노드 2개에 대한 상위 노드를 만듭니다.

   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.5MB 아카이브를 업로드한다고 가정하겠습니다. 다음 다이어그램은 아카이브의 SHA256 해시를 구하는 프로세스입니다. 아카이브를 읽고 1MB 청크씩 SHA256 해시 값을 계산합니다. 나머지 0.5MB 데이터의 해시 값도 계산한 후 이전 절차에서 설명한 대로 트리를 만듭니다.

 

![\[단일 요청으로 아카이브를 업로드하는 트리 해시 예제를 보여주는 다이어그램입니다.\]](http://docs.aws.amazon.com/ko_kr/amazonglacier/latest/dev/images/TreeHash-ArchiveUploadSingleRequest.png)


## 트리-해시 예제 2: 아카이브의 멀티파트 업로드
<a name="checksum-calculations-upload-archive-using-mpu"></a>

멀티파트 업로드를 사용해 아카이브를 업로드할 경우 트리-해시의 계산 과정도 단일 요청으로 아카이브를 업로드할 때와 동일합니다. 멀티파트 업로드는 각 요청([파트 업로드(PUT uploadID)](api-upload-part.md) API 사용)마다 아카이브 파트만 업로드한다는 점만 유일하게 다릅니다. 따라서 각 파트에 해당하는 체크섬만 `x-amz-sha256-tree-hash` 요청 헤더에 입력합니다. 하지만 모든 파트를 업로드한 후에는 `x-amz-sha256-tree-hash` 요청 헤더에 전체 아카이브의 트리-해시를 입력하여 멀티파트 업로드 완료([멀티파트 업로드 완료(POST uploadID)](api-multipart-complete-upload.md) 참조) 요청을 전송해야 합니다.

 

![\[멀티파트 업로드를 사용하여 아카이브를 업로드하는 트리 해시 예제를 보여주는 다이어그램입니다.\]](http://docs.aws.amazon.com/ko_kr/amazonglacier/latest/dev/images/TreeHash-MPU.png)


## 파일의 트리-해시 계산
<a name="checksum-calculations-examples"></a>

여기에서 소개하는 알고리즘은 설명을 목적으로 선택되었습니다. 구현 시나리오에 따라 코드를 알맞게 최적화할 수 있습니다. 예를 들어 Amazon Glacier(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 jobs)](api-initiate-job-post.md) 참조)를 사용하여 아카이브를 가져올 때는 옵션으로 아카이브를 가져오는 범위를 지정할 수 있습니다. 마찬가지로 작업 출력 가져오기 API([작업 출력 가져오기(GET output)](api-job-output-get.md) 참조)를 사용하여 데이터를 다운로드할 때도 옵션으로 다운로드할 데이터 범위를 지정할 수 있습니다. 이러한 범위에는 아카이브 데이터를 가져오거나 다운로드할 때 반드시 알고 있어야 할 두 가지 특성이 있습니다. 가져오기 범위는 아카이브에 대해 *메가바이트 정렬*로 이루어져야 합니다. 또한 데이터를 다운로드할 때 체크섬 값을 수신하려면 가져오기 범위와 다운로드 범위 모두 *트리-해시 정렬*로 이루어져야 합니다. 이러한 두 가지 유형의 범위 정렬은 아래와 같이 정의할 수 있습니다.

 
+ 메가바이트 정렬: **StartBytes를 1MB로 나눌 수 있고 **EndBytes에 1을 더한 값을 1MB로 나눌 수 있거나 지정된 아카이브의 끝(아카이브 바이트 크기에서 1을 뺀 값)과 같을 때만 범위[**StartByte, **EndBytes]가 메가바이트(1024\$11024) 로 정렬됩니다. 작업 시작 API에서 사용하는 범위는 지정하는 경우에 한해 메가바이트 정렬로 이루어져야 합니다.
+ 트리-해시 정렬: 범위에서 만들어진 트리-해시의 루트가 전체 아카이브의 트리-해시 노드에 해당할 경우, 그리고 이러한 경우일 때만 아카이브에 대한 범위 [*StartBytes*, *EndBytes*]가 트리-해시로 정렬됩니다. 데이터를 다운로드하면서 체크섬 값을 수신하려면 가져오기 범위와 다운로드 범위 모두 트리-해시 정렬로 이루어져야 합니다. 아카이브 트리-해시에 대한 범위 및 범위 관계 예는 [트리-해시 예제: 트리-해시로 정렬하여 아카이브 범위 가져오기](#checksum-calculations-upload-archive-with-ranges) 섹션을 참조하세요.

  트리-해시로 정렬되는 범위는 메가바이트로도 정렬됩니다. 하지만 메가바이트로 정렬된 범위가 꼭 트리-해시로 정렬될 필요는 없습니다.

다음은 아카이브 데이터를 다운로드하면서 체크섬 값을 수신하는 경우에 대한 설명입니다.

 
+ 작업 시작 요청에서 가져오기 범위를 지정하지 않고 작업 가져오기 요청에서 전체 아카이브를 다운로드하는 경우 
+ 작업 시작 요청에서 가져오기 범위를 지정하지 않고 작업 가져오기 요청에서 다운로드할 트리-해시 정렬 범위를 지정하는 경우
+ 작업 시작 요청에서 가져올 트리-해시 정렬 범위를 지정하고 작업 가져오기 요청에서 전체 범위를 다운로드하는 경우 
+ 작업 시작 요청에서 가져올 트리-해시 정렬 범위를 지정하고 작업 가져오기 요청에서 다운로드할 트리-해시 정렬 범위를 지정하는 경우 

작업 시작 요청에서 트리-해시로 정렬하지 않고 가져올 범위를 지정하더라도 아카이브 데이터를 가져올 수는 있지만 작업 가져오기 요청에서 데이터를 다운로드할 때 체크섬 값은 반환되지 않습니다.

## 트리-해시 예제: 트리-해시로 정렬하여 아카이브 범위 가져오기
<a name="checksum-calculations-upload-archive-with-ranges"></a>

볼트에 6.5MB의 아카이브가 저장되어 있으며 여기에서 2MB를 가져온다고 가정하겠습니다. 이때는 작업 시작하기 요청에서 2MB 범위의 지정 방식에 따라 데이터 다운로드 시 데이터 체크섬 값의 수신 여부가 결정됩니다. 다음은 6.5MB 아카이브에서 다운로드할 수 있는 두 가지 2MB 범위를 설명한 다이어그램입니다. 두 범위 모두 메가바이트로 정렬되지만 하나만 트리-해시로 정렬됩니다.

 

![\[트리 해시가 정렬된 아카이브 범위 가져오기를 보여주는 다이어그램입니다.\]](http://docs.aws.amazon.com/ko_kr/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*는 1MB의 승수라고 가정합니다. 이때 실제로 포함되는 범위는 [**PMB, **QMB-1바이트]이지만, 여기에서는 간단명료하게 [**P, **Q)로 나타냈습니다. 이를 감안하여 다음 내용을 살펴보십시오.

 
+ **P가 홀수인 경우 가능한 트리 해시 정렬 범위는 한 가지, 즉 [**P, **P\$11MB)가 유일합니다.
+ **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인 특수한 경우입니다.