Proof of Reserves

Proof that your funds are safe—anytime you want.

스냅샷 날짜

BTC icon

BTC

준비금 비율*

100.3%

ETH icon

ETH

준비금 비율*

101.3%

SOL icon

SOL

준비금 비율*

101.1%

USDC icon

USDC

준비금 비율*

105%+

USDT icon

USDT

준비금 비율*

105%+

XRP icon

XRP

준비금 비율*

100.6%

ADA icon

ADA

준비금 비율*

102.2%

책임, 정기적인 검토

Kraken은 최첨단 디지털 자산 거래 기능을 제공하는 데 그치지 않고, 디지털 자산이 운영되는 오픈 소스 블록체인의 투명성을 활용하기 위해 노력합니다.

당사는 정기적인 PoR 검토를 통해 고객이 자신의 계정에서 몇 번의 클릭만으로 자신이 보유한 잔액이 실물 자산으로 뒷받침되는지 쉽게 확인할 수 있도록 합니다.

신뢰할 수 있는 회계사가 정기적으로 수행하는 고급 암호화 회계 절차인 PoR을 통해 Kraken이 엄격한 책임 기준을 충족하고 기존 금융 회사가 제공하는 투명성을 뛰어넘는지 확인할 수 있습니다.

자주 묻는 질문

보유고 증명(PoR) 검토는 독립적인 제3자 회계사가 수행하는 절차입니다. 자산 관리자가 고객 대신 가지고 있다고 주장하는 자산을 실제로 가지고 있는지 확인하기 위해 수행됩니다. 회계사는 모든 보유 잔액의 익명화된 스냅샷을 생성하여 모든 고객 잔액을 캡슐화하는 개인정보 보호용 데이터 구조인 Merkle 트리로 모읍니다.

Merkle Root Hash

이를 통해 회계사는 스냅샷 생성 시점에 해당 잔액의 조합을 식별하는 고유 암호화 지문인 Merkle 루트를 얻습니다.

그리고 회계사는 Kraken이 생성한 디지털 서명을 수집합니다. 이는 공개적으로 인증 가능한 잔액을 가진 온체인 주소에 대한 소유권을 증명합니다. 마지막으로, 회계사는 이러한 잔액과 Merkle 트리에 표시된 고객 잔액을 비교하고 잔액이 같거나 초과하는지 확인하여 고객 자산이 Kraken의 통제 하에 있음을 확인합니다.

모든 고객은 선택된 데이터를 Merkle 루트와 비교하여 자신의 잔액이 PoR 절차에 포함되었는지 개별적으로 확인할 수 있습니다. 나머지 데이터에 변경 사항이 있으면 아무리 작은 변경 사항이더라도 루트에 영향을 미쳐 변조가 명백해집니다.

PoR 보고서는 여기서 보실 수 있습니다.

스팟 잔액

검토 대상에는 스냅샷 촬영 시점에 보유한 모든 대상 자산의 잔액이 포함됩니다. 최근 검토 기준으로, 대상 자산은 다음과 같습니다. Bitcoin(BTC), Ether(ETH), Solana(SOL), USD Coin(USDC), Tether(USDT), Ripple(XRP).

스테이킹 잔액

스냅샷 촬영 시점에 온체인 스테이킹에 할당된 잔액이 있었다면 스테이킹된 자산의 가치는 현물 잔액과 합산되어 하나의 잔액으로 표시됩니다.

마진 거래

그 시점에 마진 포지션이 있었다면 포지션의 양수 가치가 반영되어 조정된 총 잔액이 표시됩니다.

예시 1

만약 30,000 USD에 1 BTC/USD 마진 매수 포지션을 잡았는데 해당 포지션이 유지되고 있다면, BTC 잔액에 대한 +1 BTC의 양수 조정이 PoR 잔액에 반영됩니다. USD 잔액에 대한 음수 조정은 발생하지 않습니다. Kraken 수탁 하에 보유한 BTC 자산 잔액에는 당시의 BTC 잔액과 마진 포지션에 따른 +1 BTC의 양수 조정분이 포함됩니다. USD 자산 잔액은 동일하게 유지됩니다.

예시 2

만약 15 ETH에 1 BTC/ETH 마진 매수 포지션을 잡았는데 해당 포지션이 유지되고 있다면, ETH 잔액에 대한 +5 ETH의 양수 조정이 PoR 잔액에 반영됩니다. BTC 잔액에 대한 음수 조정은 발생하지 않습니다. Kraken 수탁 하에 보유한 ETH 자산 잔액에는 당시의 ETH 잔액과 마진 포지션에 따른 +15 ETH 양수 조정분이 포함됩니다. Kraken 수탁 하에 보유한 BTC 자산 잔액은 동일하게 유지됩니다.

참고: 위에 설명된 선물 방법론은 2023년 5월 PoR 검토부터 유효합니다.

퓨처스 자산

검토 당시 선물 월렛에 잔액이 있었다면 선물 담보 잔액에 대한 별도의 PoR 기록이 존재합니다. 잔액은 단일 담보 선물 거래의 미실현 손익에 따라 조정됩니다. 여기에는 현물 및 마진 거래와 동일한 범위 내 자산들이 포함되며, 동일한 Merkle Tree(각자의 고유한 Merkle Leaf ID 보유)의 일부가 됩니다. 

예시 1

선물 지갑에 1 BTC를 보유한 상태에서 BTC 무기한 단일 담보 포지션을 오픈하여 -0.1 BTC의 미실현 손익이 발생했다면, Kraken 수탁 하의 BTC 잔액은 0.9 BTC(기존 1 BTC에서 미실현 손익 -0.1 BTC가 조정된 금액)로 표시됩니다.

예시 2

선물 지갑에 1 BTC를 보유한 상태에서 BTC 무기한 다중 담보 포지션을 오픈했는데, 해당 포지션에 -100.0 USD의 미실현 손익이 있다면, Kraken 수탁 하의 BTC 잔액은 1 BTC로 표시됩니다(이 경우 미실현 손익은 USD로 추적되는데 USD는 이 검토의 대상 자산이 아니므로, 1 BTC는 미실현 손익으로 조정되지 않습니다).

참고: 위에 설명된 선물 방법론은 2023년 5월 PoR 검토부터 유효합니다. 

간편 확인

다음 단계에 따라고객님의 Kraken 계정 잔액이 최근 PoR 검토에 포함되었는지 여부를 암호적으로 확인하세요.

참고: 이 확인에는 고객님 계정의 검토 당시 대상 자산 잔액만 반영됩니다. 이후의 거래는 반영되지 않으며, 대상이 아닌 자산의 잔액도 반영되지 않습니다.

1. Kraken 계정에 로그인하여 Kraken Pro 인터페이스(pro.kraken.com)의 PoR 페이지로 이동합니다(계정 아이콘 > PoR). 

Kraken Proof of Reserves review list

2. PoR 탭을 선택합니다. 이 탭에는 가장 최근의 준비금 비율과 계정 관련 정보가 포함됩니다. 계정 잔액이 확인된 최근 PoR 보고서가 고객님의 계정에 표시될 것입니다. 여기에는 보고서 날짜, 공급자, 평가 범위가 포함됩니다. 

Kraken Proof of Reserves review list

3. 날짜를 선택하고 직접 확인을 클릭합니다. 여기서는 검토 당시 보유한 잔액과 세부 정보 확인 방법 안내를 확인할 수 있습니다.

Kraken audit details

제3자 회계사를 통해 확인

  • Merkle Leaf ID 사용 - 앞 16자를 복사한 뒤 제3자 회계사 툴에 입력하여 잔액을 가져오고 Merkle Tree 경로에서 ID를 검토합니다. 제3자 회계사 툴이 별도의 창에서 열릴 것입니다. 

참고: 이 기능은 2023년 검토부터 제공되기 시작했습니다. 그 이전의 검토에 대해서는, 당사 파트너의 웹 페이지에서 확인 툴을 찾아보세요.

Kraken audit details

Kraken을 통해 확인

  • 레코드 ID 확인 - 계정 세부 정보를 식별하는 고유 레코드 ID와 검토 ID(각 보고서 날짜마다 고유함)를 단계에 따라 재생성하세요
  • Merkle Leaf ID 확인 - 계정과 검토 스냅샷 당시 잔액을 식별하는 고유 Merkle Leaf ID를 단계에 따라 재생성하세요 
  • Merkle Tree에서 Merkle Leaf ID 확인 - Merkle Tree에 속한 ID를 확인하고, 제3자 회계사에 의해 확인되어 모든 클라이언트에서 공유되는 Merkle Tree 루트 경로의 유효성을 검사합니다.

참고: 이 기능은 2023년 검토부터 제공되기 시작했습니다. 그 이전의 검토에 대해서는, 당사 파트너의 웹 페이지에서 확인 툴을 찾아보세요.

Kraken audit details
Kraken audit details
Kraken audit details

고급 확인

IT 활용에 능숙한 클라이언트는 Kraken 또는 제3자 회계사가 제공한 시각 도구를 사용하는 대신 독자적으로 특정 Merkle Tree 리프 노드 해시를 재구성하고 Merkle Tree에서 프로그래밍 방식으로 잔액 조회를 진행하고자 할 수 있습니다. 

이 경우 코드에서 다음 확인 단계를 수행하면 됩니다.

  1. 아래 단계를 따라 계정의 Merkle Leaf 리프 ID 생성을 확인할 수 있습니다.  

  2. 다음으로 해당 Leaf ID에 대한 Merkle Tree 경로를 확인하고 포지션부터 루트 노드까지의 경로를 재구성할 수 있습니다. 저희는 완전한 투명성을 제공하며, 이웃 리프 ID도 포함합니다. 

계정 코드와 Kraken IIBAN, 검토 ID, 잔액 정보를 바탕으로 레코드 ID와 Merkle Leaf를 재구성하는 데 필요한 단계별 의사코드는 다음과 같습니다. 결과값은 잔액의 특정 문자열 형식과 PoR 페이지에 표시된 자산 검토 순서에 따라 달라질 수 있다는 점에 유의하세요.

  • Record ID = SHA256(concatenate(Account Code, Kraken IIBAN, Review ID))
  • Balances = ""
  • ForEach Asset:
    • Balances = concatenate(Asset, ":", AssetBalances[asset])
  • Merkle Hash = concatenate(Record ID, “,”, Balances)
  • Merkle Leaf = substring(SHA256(Merkle Hash), 0, 16)

Merkle Leaf가 식별되면 SHA256 확인을 HEX 값과 함께 사용하여 Merkle Tree 경로를 재구성할 수 있습니다.

아래 코드 조각에는 구체적인 예시도 포함되어 있습니다. 올바르게 재구성됐는지 확인하실 수 있도록 결과 Merkle Leaf도 검토 세부 정보에 표시됩니다.

python

Python

import hashlib

# Merkle Leaf ID calculation
account_code = "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
iiban = "AB12C34DEFG5KSQI"
review_id = "PR30SEP24"
record_id = hashlib.sha256((account_code + iiban + review_id).encode('utf-8')).hexdigest()

balances = "BTC:0.00093799,ETH:0.0422125592,SOL:0.0,USDC:0.0,USDT:6.72754,XRP:0.0"

print("Record ID: {}".format(record_id))
print("Merkle Hash: {}".format((record_id + "," + balances)))
hash_result = hashlib.sha256((record_id + "," + balances).encode('utf-8')).hexdigest()
print("SHA Result: {}".format(hash_result))
print("Merkle Leaf: {}".format(hash_result[0:16]))

#Merkle Tree Path function 
def mix(x, y):
    a = bytes.fromhex(x)
    b = bytes.fromhex(y)

    d = hashlib.sha256()
    d.update(a)
    d.update(b)
    return d.hexdigest()
rust

Rust

use sha2::{Digest, Sha256};

//Merkle Leaf ID calculation
const ACCOUNT_CODE: &str = "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1";
const IIBAN: &str = "AB12C34DEFG5KSQI";
const REVIEW_ID: &str = "PR30SEP24";
const BALANCES: &str = "BTC:0.00093799,ETH:0.0422125592,SOL:0.0,USDC:0.0,USDT:6.72754,XRP:0.0";

fn main() {
    let mut record_hasher: Sha256 = Default::default();

    record_hasher.update(ACCOUNT_CODE);
    record_hasher.update(IIBAN);
    record_hasher.update(REVIEW_ID);

    let record_id = format!("{:x}", record_hasher.finalize());
    let merkle_hash = format!("{},{}", record_id, BALANCES);

    let mut merkle_hasher: Sha256 = Default::default();
    merkle_hasher.update(&merkle_hash);
    let merkle_result = format!("{:x}", merkle_hasher.finalize());

    println!("Record ID: {}", record_id);
    println!("Merkle Hash: {}", merkle_hash);
    println!("SHA Result: {}", merkle_result);
    println!("Merkle Leaf: {}", &merkle_result[..16]);
}

//Merkle Tree Path function
fn mix(x: &str, y: &str) -> Result<String, hex::FromHexError> {
    let mut leaves_hasher: Sha256 = Default::default();
    let a = hex::decode(x)?;
    let b = hex::decode(y)?;
    leaves_hasher.update(&a);
    leaves_hasher.update(&b);
    Ok(hex::encode(leaves_hasher.finalize()))
}

fn main() {
    println!("{}", mix("f42372aeb1be7296", "dfcced6ec3235f5e").unwrap());
    assert_eq!(
        mix("f42372aeb1be7296", "dfcced6ec3235f5e").unwrap(),
        "ad86a5ee2f21347403ce07e365530604690454fa76787e76be9d2f6efdceeabf"
    );
}
go

Go

package main

import (
	"crypto/sha256"
	"fmt"
)

//Merkle Leaf ID Calculation
func main() {

	accountCode := "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
	iiban := "AB12C34DEFG5KSQI"
	reviewId := "PR30SEP24"

	secret := accountCode + iiban + reviewId

	data := []byte(secret)
	hash := sha256.Sum256(data)
	recordId := string(hash[:])
	fmt.Printf("Record ID: %x\n", recordId)

	balances := "BTC:0.00093799,ETH:0.0422125592,SOL:0.0,USDC:0.0,USDT:6.72754,XRP:0.0"

	merkleHash := fmt.Sprintf("%x%s%s", recordId, ",", balances)
	fmt.Printf("Merkle Hash: %s\n", merkleHash)

	hashResult := sha256.Sum256([]byte(merkleHash))
	hashResultStr := string(hashResult[:])
	fmt.Printf("SHA Result: %x\n", hashResultStr)
	fmt.Printf("Merkle Leaf: %x\n", hashResultStr[0:8])

}

//Merkle Tree path hashing
func mix(x, y string) (string, error) {
        // Convert the hex strings to bytes
        a, err := hex.DecodeString(x)
        if err != nil {
                return "", err
        }

        b, err := hex.DecodeString(y)
        if err != nil {
                return "", err
        }

        h := sha256.New()

        h.Write(a)
        h.Write(b)

        // Get the final hash value as a byte slice
        hashed := h.Sum(nil)

        // Convert the hash to a hex string and return it
        return hex.EncodeToString(hashed), nil
}

func main() {
        result, _ := mix("f42372aeb1be7296", "dfcced6ec3235f5e")
        fmt.Println(result)
}
bash

Bash

#!/bin/bash

#Merkle Leaf ID calculation
ACCOUNT_CODE="8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
IIBAN="AB12C34DEFG5KSQI"
REVIEW_ID="PR30SEP24"
RECORD_ID=$(echo -n "${ACCOUNT_CODE}${IIBAN}${REVIEW_ID}" | sha256sum | head -c 64)
BALANCES="BTC:0.00093799,ETH:0.0422125592,SOL:0.0,USDC:0.0,USDT:6.72754,XRP:0.0"
MERKLE_HASH="${RECORD_ID},${BALANCES}"
HASH_RESULT=$(echo -n ${MERKLE_HASH} | sha256sum | head -c 64)

echo "Record ID: ${RECORD_ID}"
echo "Merkle Hash: ${MERKLE_HASH}"
echo "SHA Result: ${HASH_RESULT}"
echo "Merkle Leaf: $(echo -n ${HASH_RESULT} | head -c 16)"

#Merkle Tree Path function
hex_string1="f42372aeb1be7296"
hex_string2="dfcced6ec3235f5e"

# convert hex strings to binary, concatenate them and then hash
hash_result=$(echo -n "$(echo -n $hex_string1 | xxd -r -p)$(echo -n $hex_string2 | xxd -r -p)" | sha256sum | awk '{ print $1 }')

echo $hash_result

투명성을 중시하는 차원에서 지금까지 파악된 PoR 절차상의 몇 가지 미흡한 점을 공유하고자 합니다.

  • PoR은 검토 시점에 온체인 자금에 대한 통제권을 입증하는 과정을 포함하지만, 비공개 키를 독점적으로 소유하고 있다는 사실까지는 증명할 수 없습니다. 이론적으로 이를 공격자가 복제했을 가능성이 있기 때문입니다.
  • 이 절차는 숨겨진 채무 부담을 식별하거나, 검토를 통과하기 위해 자금을 일시적으로 빌려오지 않았다는 사실을 증명할 수는 없습니다. 마찬가지로 마지막 검토 이후 키가 손실되거나 자금이 도난당했을 수 있습니다.
  • 회계사는 피검토자의 기만 행위나 당사자 간의 결탁 위험을 최소화하기 위한 역량을 갖추고 독립성을 유지해야 합니다.
  • 저희는 PoR을 위해 공신력 있는 독립적 제3자 기관과 협력하고 이러한 검토를 정기적으로 실시함으로써 앞서 언급한 한계점들을 완화하고자 노력하고 있습니다. 또한 클라이언트 플랫폼 내에서 해당 데이터에 대한 투명성도 직접 제공하고 있습니다. 

위의 별표(*)로 표시된 준비금 비율은 Kraken의 PoR 보고서와 비교 시 실질적으로 변동될 수 있습니다. 이는 시간 경과에 따른 상품 변경과 커스터디 인프라 개선 등으로 해당 월렛에 보유 중인 특정 자산의 분류가 영향을 받을 수 있기 때문입니다. 현재 관행과 마찬가지로, 정확한 PoR 방법론에 대한 설명이 모든 보고서에 포함되어 있습니다.