Skip to content

Commit

Permalink
Merge branch 'main' into okcoin
Browse files Browse the repository at this point in the history
  • Loading branch information
jiangjinyuan authored Aug 15, 2023
2 parents 5f749fa + d5caf8c commit eca88e8
Show file tree
Hide file tree
Showing 27 changed files with 2,185 additions and 871 deletions.
11 changes: 10 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,13 @@ userPathJson-*
venv/
origin/
package.sh
proof-of-reserves-*
proof-of-reserves-*
*.pyc
venv
zk_STARK/build/
zk_STARK/dist/
zk_STARK/inclusion_proof_data/*
zk_STARK/sum_proof_data/batches/*
zk_STARK/sum_proof_data/trunk/*
zk_STARK/user_data/*
.DS_Store
96 changes: 73 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,71 @@
# OKCoin Proof-of-Reserves
# OKX Proof-of-Reserves

## Background

OKCoin launches Proof of Reserves (PoR) to improve the security and transparency of user's assets. These tools will allow
you to independently audit OKCoin's Proof of Reserves and verify OKCoin's reserves exceed the exchange's known liabilities to
users, in order to confirm the solvency of OKCoin.
OKX launches [Proof of Reserves (PoR)](https://www.okx.com/proof-of-reserves) to improve the security and transparency
of user's assets. These tools will allow you to independently audit OKX's Proof of Reserves and verify OKX's reserves
exceed the exchange's known liabilities to users, in order to confirm the solvency of OKX.

## Introduction

### Building the source

Download the latest build for your operating system and architecture. Also, you can build the source by yourself.
#### Reserves part

Download the [latest build](https://github.com/okx/proof-of-reserves/releases/latest) for your operating system and
architecture. Also, you can build the source by yourself.

Building this open source tool requires Go (version >= 1.17).

Install dependencies

```shell
go mod tidy
```

Compile

```shell
make all
```
#### Liabilities part
Building this open source tool requires Python(version >=3.9)

Install dependencies
```shell
pip install pycryptodome
pip install pyinstaller
```

Compile
```shell
pyinstaller -F zk_STARK_Validator.py
```

### Executable

Proof-of-Reserves executable are in the cmd directory

| Command | Description |
| :-----------: | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `VerifyAddress` | We have signed a specific message with a private key to each address published by OKCoin. This tool can be used to verify OKCoin's signature and verify OKCoin's ownership of the address. |
| `CheckBalance` | Configure blockchain node RPC or OKLink API to use this tool, you can check the balance on the chain corresponding to the snapshot height of OKCoin, then compare it with the balance published by OKCoin, and query the total assets of OKCoin's wallet address on the chain. |
| `MerkleValidator` | OKCoin's PoR uses a Merkle tree, and you can use this tool to check whether your account assets are included in the Merkle tree published by OKCoin. |
| `VerifyAddress` | We have signed a specific message with a private key to each address published by OKX. This tool can be used to verify OKX's signature and verify OKX's ownership of the address. |
| `CheckBalance` | Configure blockchain node RPC or OKLink API to use this tool, you can check the balance on the chain corresponding to the snapshot height of OKX, then compare it with the balance published by OKX, and query the total assets of OKX's wallet address on the chain. |
| `zkSTARKValidator` | Current OKX's PoR uses zk-STARK(Zero-Knowledge Scalable Transparent Argument of Knowledge), a cryptographic proof technology, to verify data and prove the authenticity of our audits. |
| `MerkleValidator` | OKX's PoR uses a Merkle tree, and you can use this tool to check whether your account assets are included in the Merkle tree published by OKX. |

## Reserves

Download OKCoin's Proof of Reserves File, verify the ownership of the OKCoin's public address, and check whether the OKCoin
snapshot height balance is consistent with the published balance. Details here
Download OKX's [Proof of Reserves File](https://www.okx.com/proof-of-reserves/download), verify the ownership of the
OKX's public address, and check whether the OKX snapshot height balance is consistent with the published
balance. [Details here](https://www.okx.com/support/hc/en-us/articles/10781041719437-How-to-verify-OKX-s-ownership-and-balance-of-the-wallet-address-)

### VerifyAddress

OKCoin's public file contains address, message "I am an OKCoin address" and signature. You can use VerifyAddress to verify
OKCoin's ownership of published address.
OKX's public file contains address, message "I am an OKX address" and signature. You can use VerifyAddress to verify
OKX's ownership of published address.

```shell
./build/VerifyAddress --por_csv_filename ./example/okcoin_por_example.csv
./build/VerifyAddress --por_csv_filename ./example/okx_por_example.csv
```

At the same time, you can use third-party tools to verify the ownership
Expand All @@ -54,36 +74,66 @@ of [BTC single addresses](https://www.bitcoin.com/tools/verify-message/), [EVM](

### CheckBalance

You can use CheckBalance to verify the OKCoin wallet address balance with the corresponding block height snapshot. [Details here](./docs/checkbalance.md)
You can use CheckBalance to verify the OKX wallet address balance with the corresponding block height
snapshot. [Details here](./docs/checkbalance.md)

Sum of all address balances

```shell
./build/CheckBalance --rpc_json_filename="./example/rpc.json" --por_csv_filename ./example/okcoin_por_example.csv
./build/CheckBalance --rpc_json_filename="./example/rpc.json" --por_csv_filename ./example/okx_por_example.csv
```

Query the snapshot height balance on the chain

```shell
./build/CheckBalance --mode="single_coin" --coin_name="ETH" --rpc_json_filename="./example/rpc.json" --por_csv_filename="./example/okcoin_por_example.csv"
./build/CheckBalance --mode="single_coin" --coin_name="ETH" --rpc_json_filename="./example/rpc.json" --por_csv_filename="./example/okx_por_example.csv"
```

## Liabilities

OKCoin's PoR uses Merkle tree technology to allow each user to independently review OKCoin's digital asset reserve on the
basis of protecting user privacy. Details here
OKX's PoR uses Merkle tree technology to allow each user to independently review OKX's digital asset reserve on the
basis of protecting user
privacy. [Details here](https://www.okx.com/support/hc/en-us/articles/15165477403917)

### MerkleValidator
### zk-STARK Validator(From 04/27)
**Currently, zk-STARK PoR has been released. The following is the operation flow of the zk-STARK version.**
Verify the inclusion constraint

Log in to OKCoin, go to the Audits page to view audit details, download the Merkle tree path data, copy and save it as a
file merkle_proof_file.json, and run the following command to check whether your assets are included in the total user
assets of OKCoin.
1. To verify if your asset balance has been included as a Merkle leaf, navigate to ["Audits"](https://www.okx.com/balance/audit) and click **Details** to access your audit data.
2. Get the data you need for verification by clicking **Copy data** and pasting the JSON string as a file in a new folder.
3. Download [zk-STARKValidator](https://github.com/okx/proof-of-reserves/releases/tag/v3.0.0), the OKX open-source verification tool, and save it to the same folder containing the JSON file.
4. Open zk-STARKValidator to auto-run the JSON file you saved to check whether the inclusion constraint is satisfied.

Verify the total balance and non-negative constraints
1. Under ["Audit files"](https://www.okx.com/proof-of-reserves/download?tab=liabilities), download the zk-STARK file from the "Liability report" tab.
2. Unzip the file to reveal a "sum proof data" folder with branch and trunk folders containing "sum_proof.json," "sum_value.json" files.
3. Download [zk-STARKValidator](https://github.com/okx/proof-of-reserves/releases/tag/v3.0.0), the OKX open-source verification tool, and place it in the same root folder as the "sum proof data" folder.
4. Open zk-STARKValidator to auto-run the unzipped zk-STARK file to check whether the total balance and non-negative constraints are satisfied.



### MerkleValidator(From 11/22/2022 to 03/16)

**On 03/21, version v2 was released, which is compatible with v1. The following is the operation flow of the two versions**

Verification process for v1 version [Detail here](https://www.okx.com/support/hc/en-us/articles/10660988139661-How-to-verify-if-your-assets-are-included-in-the-OKX-Merkle-tree-)

1. Log in to OKX, go to the Audits page to view audit details, download the Merkle tree path data, copy and save it as a
file merkle_proof_file.json, and run the following command to check whether your assets are included in the total
user assets of OKX.

```shell
./build/MerkleValidator --merkle_proof_file ./example/merkle_proof_file.json
```

Verification process for v2 version [Detail here](https://www.okx.com/support/hc/en-us/articles/13747778159245-How-to-verify-if-your-assets-are-included-in-the-OKX-Merkle-tree-Merkle-Tree-V2-)

1. Visit [Full merkle tree file download page](https://okx.com/proof-of-reserves/download?tab=liabilities) to download
the full merkle tree file
2. Login to OKX and visit Audit page to copy and save the data as user_info_file.json
3. Run the following command to check whether your assets are included in the total user assets of OKX.


```shell
./build/MerkleValidator --merkle_file ./example/full-liabilities-merkle-tree.txt --user_info_file ./example/user_info_file.json
```

12 changes: 12 additions & 0 deletions common/coin.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ var (

// ALGO
"USDT-ALGO": "ALGO",

// FEVM
"FIL-EVM": "FIL",
}

PorCoinTypeMap = map[string]string{
Expand Down Expand Up @@ -152,6 +155,7 @@ var (
"PEOPLE": EvmCoinTye,
"OKB": EvmCoinTye,
"OPTIMISM": EvmCoinTye,
"FIL-EVM": EvmCoinTye,

// BETH
"BETH": BethCoinType,
Expand Down Expand Up @@ -234,6 +238,7 @@ var (
"PEOPLE": EthMessageSignatureHeader,
"OKB": EthMessageSignatureHeader,
"OPTIMISM": EthMessageSignatureHeader,
"FIL-EVM": EthMessageSignatureHeader,

// BETH
"BETH": EthMessageSignatureHeader,
Expand Down Expand Up @@ -359,6 +364,9 @@ var (

// ALGO
"USDT-ALGO": "USDT",

// FEVM
"FIL-EVM": "FIL",
}

PorCoinBaseUnitPrecisionMap = map[string]int{
Expand Down Expand Up @@ -446,6 +454,9 @@ var (

// ALGO
"USDT-ALGO": 6,

// FEVM
"FIL-EVM": 18,
}

CheckBalanceCoinBlackList = map[string]bool{
Expand All @@ -471,6 +482,7 @@ var (
"RIPPLE": true,

"USDT-ALGO": true,
"FIL-EVM": true,
}

VerifyAddressCoinBlackList = map[string]bool{
Expand Down
52 changes: 46 additions & 6 deletions common/crypto_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,28 @@ func TestVerifyUtxoCoinSignature(t *testing.T) {
script: "522102f5c9ab0dd178eb44cd6baae7c1698ae23caec399d58da93a32509665113152742103729f817997a0442e6a39ee0c15f0cd3a17e55ef768ae6f055b2c323a1cba9eb121021e6568b58ef452791f56d0ba2f2ea1200c730f114ab88701833a0a2cf77ef09e53ae",
},
{
coin: "BTC",
addr: "3Dqq8D5NNfH28RM2kEGzLnhPYRuXDL6bu6",
msg: "I am an Okcoin address",
sign1: "ILLlcEugYiWkge8aS7cQqhHIhk7iVZU5VpJWG830lch7I02Psg3SM/2s1/YY0aWHhNvtcA3QAK0Wnj8NWOTugKA=",
sign2: "IAhfztm0YG0yddgGanfbtA0XfB1kgp+UnHzKnfDyLn4BRnD5v6Q6vb/PgshH8i/gcfcgizdBbPUCIaFsXnP5Sag=",
script: "52210357df00444cf67ada94e25d6a6c6178b14beb6aa33147c74b43a629968d38b07521021922578fd9f4736d52effb0a2404b279557d8e442febd81b46d52eb17948b5462103f587f7297e4d5f8f58007a26cd5e7d83db4687421e08b97d3cbda9387959d6f453ae",
coin: "LTC",
addr: "MH7Qru4KFC6tLSiSq7bTWUDyiXERwzdqKp",
msg: "I am an OKX address",
sign1: "ID7R92j4VjjajZGAqRWyHVEAGLfbJZnIKD7uZVyMPYNqf3Cp0BxeFSuZ8c+weifZ8M3DBE8F2ftDV7s9XYTLPus=",
sign2: "H2wcYS+Osohhi06wr78H4Gn8zsB9Oqw9aTRo7OEdTJNaWNGwoo+6zwsywdfUXk6IgxY7hreo0I/s8fIjHJceFdQ=",
script: "522103c4a04606ac7b32924f0fc0b8aadbf925c139738701a09138bc7c42cb9a3609da21034b8b29e6f460e6293423173863a9cca093bbbd865a611abd984fd674d2537e5b210350ade45e21816652e9812bb39f55e0e8cad02a0884c3c024ab642a43cd8094a353ae",
},
{
coin: "LTC",
addr: "ltc1qzvcgmntglcuv4smv3lzj6k8szcvsrmvk0phrr9wfq8w493r096ssm2fgsw",
msg: "I am an OKX address",
sign1: "IGLtPax4D8T/a5YIfTjqT4hoy8j71gG+yFeKPUhH4xKTcgEFxLXrJF+2ZLgPoqKGBt+QSNH6l7RK7bIZzVIvzBA=",
sign2: "Hzs4gdaoFHT1hfVqyi2tvoIhGiUTP/vVETd2QPtg8Uu/eGzec6oK5DvVIK0oUMC8G0dfWgrEcJM4IE7MIHS4oBc=",
script: "5221024ae22b49865207865e57b5056abb1e9f6480a6621a246b7066ab84c3b7f9d2b5210255f79ad111076c25b3f6d5e2e99250b6150b1d1b6af10f860f41f63c68859704210247eb8b75b8e50a8a33a7d9ada81f3ecaa05228bfeec3274bc6520637f2eacbf553ae",
},
{
coin: "LTC",
addr: "LectSLekhkxEQBHofNFHa3pVHndnb4Z9fN",
msg: "I am an OKX address",
sign1: "ILEkfsIaFagDnMq0pY9qS4yIAjTFlpDknLCVm5dhMHbnZn0SXC+Op9jQfD4wbu+Rpxs1N5ut6c2349GEM8AFx0A=",
sign2: "",
script: "",
},
}

Expand Down Expand Up @@ -138,6 +154,18 @@ func TestVerifyEvmCoinSignature(t *testing.T) {
msg: "I am an Okcoin address",
sign: "0x462950c4dbbc0f2fb36002ba7e5c2a98dfae7d89203f4dbf152e03304edb444d670c8bbacb78072c4dc1184db245401c73ee1395715afbb8dd600ba6a63e3abc1b",
},
{
coin: "FIL-EVM",
addr: "f410fa7sh5u6fvd7vt625dx2akhbu3jt7yvkhgdp55ki",
msg: "hello world",
sign: "0x9c271461e5876fac4e5a02aee7a877831a91cee6a24b75cafd8650ac72b2a5e5147e2e90558d4e38d113ff54e734f041687f41268d55ff7850791e1e2833dc061b",
},
{
coin: "FIL-EVM",
addr: "f410f3py2r3kh22yh7ona3fyp2tyzhxo4p2okiwuqjza",
msg: "I am an OKX address",
sign: "0x05168f6ede2213bebae69256ad78cfcf4f3a99d4b11bacd4a24ec2171becb34e2f690c515e3b1227a52e7e7c4dd99dd0f307c167f768b2201bd82b69af5a112b1c",
},
}
for _, tt := range args {
err := VerifyEvmCoin(tt.coin, tt.addr, tt.msg, tt.sign)
Expand Down Expand Up @@ -247,6 +275,18 @@ func TestVerifyEcdsaCoinSignature(t *testing.T) {
msg: "I am an OKX address",
sign: "0xa181d622f9a1d1aac327c026a46d11c95a44fb8994a07d232a15b79c12d225a7059db547c0a79b67605f68930d8d0f93a9939589c4fc70041e66322efc61a2421b",
},
{
coin: "LTCK-OKC20",
addr: "0xeb196a61f9a1e35bf5053b65aaa57c5541dcba86",
msg: "I am an OKX address",
sign: "0xe8df58ec46822f86a0a2fb547260ac55caeeb256916a8c2aabcc01cbdfc13ff264992f2127f3e1cc8e45bf936947c50c8ea097602712e6868526d7fccd9273bc1c",
},
{
coin: "LTCK-OKC20",
addr: "0x4a11078a99b118bbfee78a5c187d98d264360433",
msg: "I am an OKX address",
sign: "0xee5e609b94842cca32b0f482351bbd2e76e6730dfb146337a077fd03dc6219b62ed1d4e4daf243cb2ba50a12ba47e5f76b8d22e91e8a9c7d228b22a2b236a0ad1b",
},
}
for _, tt := range args {
err := VerifyEcdsaCoin(tt.coin, tt.addr, tt.msg, tt.sign)
Expand Down
25 changes: 25 additions & 0 deletions common/ecdsa.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package common

import (
"bytes"
"crypto/sha256"
"encoding/base32"
"encoding/binary"
"encoding/hex"
"fmt"
"github.com/dchest/blake2b"
"github.com/filecoin-project/go-address"
builtintypes "github.com/filecoin-project/go-state-types/builtin"
"github.com/martinboehm/btcutil/base58"
)

Expand Down Expand Up @@ -72,3 +77,23 @@ func checksum(input []byte) (cksum [4]byte) {

return
}

var maskedIDPrefix = [20 - 8]byte{0xff}

func ConvertEthAddressToFilecoinAddress(ethHash []byte) (address.Address, error) {
address.CurrentNetwork = address.Mainnet
if bytes.HasPrefix(ethHash[:], maskedIDPrefix[:]) {
// This is a masked ID address.
id := binary.BigEndian.Uint64(ethHash[12:])
return address.NewIDAddress(id)
}

// Otherwise, translate the address into an address controlled by the
// Ethereum Address Manager.
addr, err := address.NewDelegatedAddress(builtintypes.EthereumAddressManagerActorID, ethHash[:])
if err != nil {
return address.Undef, fmt.Errorf("failed to translate supplied address (%s) into a "+
"Filecoin f4 address: %w", hex.EncodeToString(ethHash[:]), err)
}
return addr, nil
}
28 changes: 22 additions & 6 deletions common/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,18 +241,34 @@ func VerifyEvmCoin(coin, addr, msg, sign string) error {
}
hash := HashEvmCoinTypeMsg(msgHeader, msg)
s := MustDecode(sign)
pub, err := SigToPub(hash, s)
pub, err := sigToPub(hash, s)
if err != nil {
return ErrInvalidAddr
}

recoverAddr := PubkeyToAddress(*pub).String()
if strings.ToLower(addr) != strings.ToLower(recoverAddr) {
return fmt.Errorf("recovery address not match, coin:%s, recoverAddr:%s, addr:%s", coin, recoverAddr, addr)
pubToEcdsa := pub.ToECDSA()
recoverAddr := PubkeyToAddress(*pubToEcdsa).String()

addrType, exist := PorCoinAddressTypeMap[coin]
if !exist {
return fmt.Errorf("invalid coin type %s, addr:%s", coin, addr)
}
switch addrType {
case "FIL":
// convert eth address to fil address
filAddress, err := ConvertEthAddressToFilecoinAddress(PubkeyToAddress(*pubToEcdsa).Bytes())
if err != nil {
return fmt.Errorf("convert eth address to fil address failed, coin:%s, addr:%s, error:%v", coin, addr, err)
}
recoverAddr = filAddress.String()
case "ETH":
if !VerifySignAddr(HexToAddress(addr), hash, s) {
return ErrInvalidSign
}
}

if !VerifySignAddr(HexToAddress(addr), hash, s) {
return ErrInvalidSign
if strings.ToLower(addr) != strings.ToLower(recoverAddr) {
return fmt.Errorf("recovery address not match, coin:%s, recoverAddr:%s, addr:%s", coin, recoverAddr, addr)
}

return nil
Expand Down
Loading

0 comments on commit eca88e8

Please sign in to comment.