准备金证明
我们对透明度的追求
在Kraken,客户除了可以交易最尖端的数字资产,同时我们正努力最大限度地发掘公开源代码的区块链其透明度。
我们的定期准备金证明审计让客户可以随时核查个人账户内的余额是否由真实资产所支持,而查对的完整过程只需几个简单的步骤便可完成。
准备金证明是一种针对加密交易的高阶会计方式,由委托的审计师每半年进行一次核算。准备金证明让您检查Kraken是否满足严格的问责标准,并超越传统金融机构的透明度。
什么是准备金证明?
准备金证明 (PoR) 是由第三方独立完成的审计,目的为确保监管方保管的资产总额与客户的账面余额吻合。审计师对所有余额进行匿名快照,然后将其汇总至Merkle tree -- 一个封装了所有账户余额的隐秘数据架构。
从Merkle tree审计师获得Merkle root:一个能识别快照内所有余额的加密指纹。
随后审计师将收集由Kraken生成的数字签名,证明链上地址的所有权,以及可公开核对的余额。最后,审计师对比并核实余额是否和Merkle Tree所提供的数目一致。由此证明客户的资产是以全额准备金所支持。
客户可将选定数据与Merkle toot自行核对,查看账户余额是否在准备金证明的审计内。任何数据上的差额,无论多小,将使Merkle root受到影响,从而曝露篡改的痕迹。
核实您的账户是否已纳入审计
请按照以下步骤,通过加密方式核实您的Kraken账户余额是否已纳入当前的准备金证明内。
注意:审计验证只反映您的账户在审计中所涵盖的资产余额。不包括任何后续的交易,也不会反映审计范围之外的资产余额。
1. 登录您的Kraken账户,并导航到您的账户设置 (设置 > 账户)。
2. 点击审计。您的账户将显示近期的账户余额审计,审计ID和日期,负责审计的公司名称,以及审计类型。 审计ID由一系列以识别特定审计的字符串显示。由于Kraken将进行定期的准备金证明审计,因此每个审计ID将由独一无二的字符串组成。
3. 选择审计的日期。 在此处您可查看审计类型确认,记录ID (针对您的账户及指定的审计),所涵盖的资产,以及审计时的资产余额。
记录ID让您通过第三方审计机构独立验证您的账户余额是否已包括在审计其中。
通过审计师验证您的记录。
简易方法:
以最快捷的方式验证账户记录 -- 在第三方审计机构的门户网站核查您的记录ID:
1. 复制与您的账户和指定审计相对应的记录ID (如何查找ID请参考上一节)。
2. 访问负责本次准备金证明审计的第三方审计师的网站。
3. 在网站输入您的记录ID。审计方将使用此ID查询您的账户在链上的加密货币于审计过程中的记录。
4. 验证您的余额。
高阶方法:
技术达人或更愿意独自重建个人的Merkle Tree叶子节点的哈希值,并通过该哈希值在第三方审计工具中查询账户余额,而非仅使用记录ID。
客户由此可以验证他们的记录ID (以及审计时账户的相关余额) 是否已涵盖在Merkle Tree结构中,结果可根据审计师公布的根哈希值查看:
1. kraken.com的审计详情内也为您提供一个账户代码 -- 为识别您的账户和特定审计的唯一代码,以避免代码在其他审计中被重复使用。
2. 您还会看到一个Merkle Hash可供您直接使用,或通过账户和审计的细节重建 (如下)。在审计工具上查找Merkle Leaf请输入该Merkle Hash -- SHA256的前16个字符。
3. 由您的账户代码重建记录ID和Merkle Leaf的必要步骤 (以伪代码的形式),Kraken IIBAN,审计ID以及余额均概述如下。请注意,为确保计算结果的准确性,请务必使用和审计页面显示的完全相同的余额字符串格式。
- Record ID = SHA256(concatenate(Account Code, Kraken IIBAN, Audit ID))
- Balances = concatenate(“BTC:”, balBTC)
- Balances = concatenate(Balances, “,BTC.M:”, balBTCM)
- Balances = concatenate(Balances, “,ETH:”, balETH)
- Balances = concatenate(Balances, “,ETH2.S:”, balETH2S)
- Merkle Hash = concatenate(Record ID, “,”, Balances)
- Merkle Leaf = substring(SHA256(Merkle Hash), 0, 16)
具体例子将在以下代码段中呈现,由此生成的Merkle Leaf可在审计细节中查看,以确认您的重建过程准确无误。
Python
import hashlib
account_code = "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
iiban = "AB12C34DEFG5KSQI"
audit_id = "PR30JUN22"
record_id = hashlib.sha256((account_code + iiban + audit_id).encode('utf-8')).hexdigest()
balances = "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,BTC.M:1.25,DOT:50.0,DOT.S:20.5,DOT.P:0.0,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"
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]))
Rust
use sha2::{Digest, Sha256};
const ACCOUNT_CODE: &str = "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1";
const IIBAN: &str = "AB12C34DEFG5KSQI";
const AUDIT_ID: &str = "PR30JUN22";
const BALANCES: &str = "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,BTC.M:1.25,DOT:50.0,DOT.S:20.5,DOT.P:0.0,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002";
fn main() {
let mut record_hasher: Sha256 = Default::default();
record_hasher.update(ACCOUNT_CODE);
record_hasher.update(IIBAN);
record_hasher.update(AUDIT_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]);
}
Go
package main
import (
"crypto/sha256"
"fmt"
)
func main() {
accountCode := "8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
iiban := "AB12C34DEFG5KSQI"
auditId := "PR30JUN22"
secret := accountCode + iiban + auditId
data := []byte(secret)
hash := sha256.Sum256(data)
recordId := string(hash[:])
fmt.Printf("Record ID: %x\n", recordId)
balances := "ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,BTC.M:1.25,DOT:50.0,DOT.S:20.5,DOT.P:0.0,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"
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])
}
Bash
#!/bin/bash
ACCOUNT_CODE="8dc20f34da8cea8dd0f46b001694f5123ecd30d786c5eb92ad1a013703a4f8d1"
IIBAN="AB12C34DEFG5KSQI"
AUDIT_ID="PR30JUN22"
RECORD_ID=$(echo -n "${ACCOUNT_CODE}${IIBAN}${AUDIT_ID}" | sha256sum | head -c 64)
BALANCES="ADA:15129.4,ADA.S:0.0,BTC:0.2600852178,BTC.M:1.25,DOT:50.0,DOT.S:20.5,DOT.P:0.0,ETH:5.27518778,ETH2.S:10.123,USDC:50000.0,USDT:0.0,XRP:0.000002"
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)"
不足之处以及今后的改善
为了倡导透明度,我们想在此分享在准备金证明审计过程中发现的不足之处。
- 准备金证明只能落实在审计期间内链上资金的所有人,但无法证明私钥是否被窃取,以及我们是私钥的唯一持有人。
- 审计结果无法确定任何隐藏的债权或证明资金没有被借用以通过审计。同样地,自上一次审核后,私钥可能丢失或资金被盗。
- 审计师必须有相当的能力和保持中立,为尽量避免来自被审计方的不实性或串通舞弊的风险。
我们力求通过与具有公信力的独立第三方合作进行准备金证明,并定期审计,尽可能地避免上述弊端。
*注意:目前仍未有一套统一规范化的程序和规则以制定准备金证明审计。我们通过聘请一家独立的会计事务所,根据美国注册会计师协会规定的标准进行鉴证业务,出具一份独立会计师的商定程序报告。该报告包括执行的具体程序以及审计结果。