Proof of Reserves

Bifubao’s Proof of Reserves

What are reserves?

Reserves refers to the funds held by a business. If a business holds funds on behalf of its customers, and its reserve ratio is 100%, this means that it holds 100% of its customer’s funds in reserve. If its reserve ratio is 10%, that means the business only holds 10%, and 90% of the funds are used elsewhere. This is the mechanism used by many banks - depositors give cash to the bank to hold, and the bank lends out a certain percentage while keeping enough in reserve to satisfy withdrawal requests.

Why does an off-chain wallet need to prove reserves?

In Bifubao’s case, our reserves refer to the bitcoins that Bifubao holds on behalf of our users. Our wallet is off-chain, which means that we hold bitcoins for you, with the data being stored on our database. This has many benefits, but one downside is that it is typically difficult to prove that the platform holds the funds that they say they do. This situation was pronounced in the case of Mt. Gox, and since its demise the bitcoin community has demanded accountability from exchanges and wallets that handle bitcoin deposits in an off-chain manner.

Method of Proof

The easiest method of proof is to publish a flat list of all user accounts, total deposits, and the platform’s deposit addresses. However, this method exposes a great deal of company information. The Merkle Tree technique makes it difficult for a company to falsify data while protecting privacy (although some information is necessarily revealed).

How We Implement Proof of Reserves

Our implementation is based on a method using Merkle Trees as proposed by Bitcoin developer Greg Maxwell, and as detailed here, with a few modifications. Using this method, a company would be able to prove to a user that its data was taken into account in calculating the total amount of funds held.

构建的树结构

单个用户看到的结构

Privacy

User Information

To protect user identities, we can’t very well directly publish a list of our user’s email addresses or ids along with their bitcoin holders. Instead, we create a hash using each user’s user_id. Combining the user_id with their balance and nonce makes the resulting hash value even harder to trace. The user_ids should be unique and immutable, so as to decrease the odds of two users choosing the same user_id. In pseudocode, this would look something like the following: hash_value = HASH(user_id + nonce + balance). Because we only display a hash digest, users can rest assured that their personal information won’t be exposed as part of this proof. Besides calculating a unique user_id for each user, we additionally calculate a new nonce each time.

Bifubao Information

This method exposes some of Bifubao's data. Users can see the total amount of bitcoins on our system and can estimate the total number of users on our system. However, we believe it is worth the tradeoff to verify to our users that we are operating transparently. We are also opening up our source code for the community to inspect.

Implementation Details

We build up the Merkle Tree by first obtaining the relevant data in our database, and then iteratively running the algorithm to construct the tree to the root node.

Example Data

User Email/ Mobile Phone Nonce Balance (Satoshi)
panzhibiao@bifubao.com 139853 100047062
support@bifubao.com 982361 88086042
13800138000 093823 3343103669

User Nodes

The hash of the user node is calculated according to this algorithm:

1
2
3
4
5
hexstr(
    first8bytes(
        sha256(str(user_id) + sprintf("%06d", nonce) + sprintf("%016lld", balance))
    )
)

We concatenate the user_id and the nonce to get the uid in the code below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef struct Node_ {
  long long         sum;
  unsigned char hash[8];
  
  bool operator < (const struct Node_ &right) const {
    return memcmp(this->hash, right.hash, 8) < 0 ? true : false;
  }
} Node;

// make_user_node
void make_user_node(const char *uid, long long balance, Node *node) {
  unsigned char hash[SHA256_DIGEST_LENGTH];
  char buf[17] = {0};
  node->sum = balance;
  sprintf(buf, "%016lld", balance);

  SHA256_CTX sha256;
  SHA256_Init(&sha256);
  SHA256_Update(&sha256, uid, strlen(uid));
  SHA256_Update(&sha256, buf, 16);
  SHA256_Final(hash, &sha256);
  
  memcpy(node->hash, hash, 8);
}

After constructing the hashes of all of the user nodes, we sort them according to the hash results.

Parent Nodes

Two adjacent nodes are added together to make a parent node. If the number of nodes is odd, we construct a padding node.

1
2
3
4
5
hexstr(
    first8bytes(
        sha256(_8bytes(left.sum + right.sum) + _8bytes(left.hash) + _8bytes(right.hash))
    )
)

The balance of the parent node is the sum of the balances of the child nodes.

1
2
3
4
5
6
7
8
9
10
11
12
// make_parent_node
void make_parent_node(const Node *l, const Node *r, Node *p) {
  unsigned char hash[SHA256_DIGEST_LENGTH];
  unsigned char buf[24]= {0};
  
  p->sum = l->sum + r->sum;
  memcpy(buf,    (unsigned char *)&(p->sum),  8);
  memcpy(buf+8,  (unsigned char *)l->hash, 8);
  memcpy(buf+16, (unsigned char *)r->hash, 8);
  SHA256(buf, 24, hash);
  memcpy(p->hash, hash, 8);
}

Merkle Tree

To build the merkle tree, we recursively use the algorithm above until we get to the root node.

Cold Storage Addresses

Our proof of reserves would not be complete without proving our control of assets. Below are our cold storage addresses, where you can see how much we hold in reserve. Because we hold some bitcoins in our hot wallet, the number indicated in the sum of the two addresses below will not be equal to the amount calculated above, but you can use the data to be sure that we at least hold a large percentage of user funds.

  1. 1PufBJk2c2HYq5wNap9yjmjSw6G3iD6mr5
  2. 1EQvpVvPVtZrwwrSoXY1mMrdVuCqaiVKEy

Signed Messages To prove we control these addresses, we’ve signed a message using their corresponding private keys:

1
2
3
4
5
6
7
8
# plain text
this address belongs to bifubao.com, 2014-03-04
 
# signature of 1PufBJk2c2HYq5wNap9yjmjSw6G3iD6mr5
HGcRqoJUq3iINmQ1jCA59KD6Iv0DzcaQxxtkIL9l/+wWo1bREPmh3h35IowYv0DU7lRT54O2wQtQ2rE7AVUxiVk=
 
# signature of 1EQvpVvPVtZrwwrSoXY1mMrdVuCqaiVKEy
G/AMpYGw6aW2gLHdHwkCh+PIHz6gwybXEostNCSmF8RBzEwAOYUFNBD5oI6XFkLRGvFrs58KRP/7Ok9GATZONW0=
  1. Source Code: https://github.com/bifubao/proof_of_reserves

示例树结构

References

  1. prove-how-(non)-fractional-your-Bitcoin-reserves-are scheme https://iwilcox.me.uk/2014/nofrac-orig]
  2. Proving Your Bitcoin Reserves https://iwilcox.me.uk/2014/proving-bitcoin-reserves]
  3. Pictures courtesy of Zak Wilcox at the above sites.

币付宝是什么?

币付宝是什么?

币付宝是个比特币钱包。带点广告的话就是简单、好用、安全的消费级钱包服务。

目前使用钱包实在是不够方便,大部分本地钱包需要经常特意去同步,实在太麻烦,硬盘坏了、电脑丢了还会损失币;在线钱包稍微改善一些,但依然不少问题,有的过于复杂、强迫用户学习很多非必须的概念,有的过于垃圾,保护不了用户的币不说,经常随意挪用客户资金,甚至跑路的都有。

这些都是要着力解决的痛点,总结起来就三个:简单、好用、安全。