├── .gitignore ├── merkle-tree-contracts ├── .gitignore ├── hardhat.config.ts ├── tsconfig.json ├── README.md ├── package.json ├── contracts │ └── StandardMerkleTree.sol └── test │ └── StandardMerkleTree.ts ├── go.mod ├── standard_merkle_tree ├── solidity_utils.go ├── solidity_types.go ├── openzeppelin_utils.go ├── openzeppelin_standard_tree.go ├── openzeppelin_standard_tree_test.go └── solidity_value.go ├── docs ├── dump_tree.json ├── dump_proof.json └── main_run.txt ├── go.sum ├── main.go ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ -------------------------------------------------------------------------------- /merkle-tree-contracts/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | coverage 4 | coverage.json 5 | typechain 6 | typechain-types 7 | 8 | # Hardhat files 9 | cache 10 | artifacts 11 | 12 | -------------------------------------------------------------------------------- /merkle-tree-contracts/hardhat.config.ts: -------------------------------------------------------------------------------- 1 | import { HardhatUserConfig } from "hardhat/config"; 2 | import "@nomicfoundation/hardhat-toolbox"; 3 | 4 | const config: HardhatUserConfig = { 5 | solidity: "0.8.18", 6 | }; 7 | 8 | export default config; 9 | -------------------------------------------------------------------------------- /merkle-tree-contracts/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "skipLibCheck": true, 9 | "resolveJsonModule": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /merkle-tree-contracts/README.md: -------------------------------------------------------------------------------- 1 | # Sample Hardhat Project 2 | 3 | This project demonstrates a basic Hardhat use case. It comes with a sample contract, a test for that contract, and a script that deploys that contract. 4 | 5 | Try running some of the following tasks: 6 | 7 | ```shell 8 | npx hardhat help 9 | npx hardhat test 10 | REPORT_GAS=true npx hardhat test 11 | npx hardhat node 12 | npx hardhat run scripts/deploy.ts 13 | ``` 14 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/FantasyJony/openzeppelin-merkle-tree-go 2 | 3 | go 1.19 4 | 5 | require ( 6 | github.com/ethereum/go-ethereum v1.11.6 7 | github.com/json-iterator/go v1.1.12 8 | github.com/pkg/errors v0.9.1 9 | golang.org/x/crypto v0.9.0 10 | ) 11 | 12 | require ( 13 | github.com/btcsuite/btcd/btcec/v2 v2.2.0 // indirect 14 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect 15 | github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c // indirect 16 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect 17 | github.com/modern-go/reflect2 v1.0.2 // indirect 18 | golang.org/x/sys v0.8.0 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /standard_merkle_tree/solidity_utils.go: -------------------------------------------------------------------------------- 1 | package standard_merkle_tree 2 | 3 | import ( 4 | "github.com/ethereum/go-ethereum/accounts/abi" 5 | "golang.org/x/crypto/sha3" 6 | ) 7 | 8 | func Keccak256(value []byte) ([]byte, error) { 9 | hash := sha3.NewLegacyKeccak256() 10 | hash.Write(value) 11 | return hash.Sum(nil), nil 12 | } 13 | 14 | func AbiPack(types []string, values ...interface{}) ([]byte, error) { 15 | values = abiArgConvert(types, values...) 16 | var args abi.Arguments 17 | for _, v := range types { 18 | typ, err := abi.NewType(v, "string", nil) 19 | if err != nil { 20 | return nil, err 21 | } 22 | args = append(args, abi.Argument{ 23 | Type: typ, 24 | }) 25 | } 26 | packed, err := args.Pack(values...) 27 | return packed, err 28 | } 29 | -------------------------------------------------------------------------------- /merkle-tree-contracts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "devDependencies": { 3 | "@ethersproject/abi": "^5.4.7", 4 | "@ethersproject/providers": "^5.4.7", 5 | "@nomicfoundation/hardhat-chai-matchers": "^1.0.0", 6 | "@nomicfoundation/hardhat-network-helpers": "^1.0.0", 7 | "@nomicfoundation/hardhat-toolbox": "^2.0.0", 8 | "@nomiclabs/hardhat-ethers": "^2.0.0", 9 | "@nomiclabs/hardhat-etherscan": "^3.0.0", 10 | "@typechain/ethers-v5": "^10.1.0", 11 | "@typechain/hardhat": "^6.1.2", 12 | "@types/chai": "^4.2.0", 13 | "@types/mocha": ">=9.1.0", 14 | "@types/node": ">=12.0.0", 15 | "chai": "^4.2.0", 16 | "ethers": "^5.4.7", 17 | "hardhat": "^2.14.0", 18 | "hardhat-gas-reporter": "^1.0.8", 19 | "solidity-coverage": "^0.8.0", 20 | "ts-node": ">=8.0.0", 21 | "typechain": "^8.1.0", 22 | "typescript": ">=4.5.0" 23 | }, 24 | "dependencies": { 25 | "@openzeppelin/contracts": "^4.9.0", 26 | "@openzeppelin/merkle-tree": "^1.0.4" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /merkle-tree-contracts/contracts/StandardMerkleTree.sol: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | pragma solidity ^0.8.9; 4 | 5 | import "@openzeppelin/contracts/utils/cryptography/MerkleProof.sol"; 6 | 7 | contract StandardMerkleTree { 8 | 9 | function verify(bytes32[] calldata proof, bytes32 root, address account, uint256 amount) external pure returns (bool) { 10 | return MerkleProof.verifyCalldata(proof, root, _leaf(account, amount)); 11 | } 12 | 13 | function multiProofVerify( 14 | bytes32[] calldata proof, 15 | bool[] calldata proofFlags, 16 | bytes32 root, 17 | address[] calldata accounts, 18 | uint256[] calldata amounts 19 | ) external pure returns (bool) { 20 | bytes32[] memory leaves = new bytes32[](accounts.length); 21 | for(uint256 i = 0; i < accounts.length; i++) { 22 | leaves[i] = _leaf(accounts[i], amounts[i]); 23 | } 24 | return MerkleProof.multiProofVerifyCalldata(proof, proofFlags, root, leaves); 25 | } 26 | 27 | function _leaf(address account, uint256 amount) internal pure returns (bytes32) { 28 | return keccak256(bytes.concat(keccak256(abi.encode(account, amount)))); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /docs/dump_tree.json: -------------------------------------------------------------------------------- 1 | { 2 | "format": "standard-v1", 3 | "tree": [ 4 | "0xcef9852531f2476330b76131d5de322f616540e5668b46383dd26f96c50d8861", 5 | "0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77", 6 | "0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7", 7 | "0xeb02c421cfa48976e66dfb29120745909ea3a0f843456c263cf8f1253483e283", 8 | "0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc", 9 | "0x6906f9b4ada8fe83b0371d6585849c98a5836a0c81fbb8f87a82008379a9159e", 10 | "0x23cfee851b7629c71ca861a1c79681e9734fa944586795f3ec0a66c1371d382d" 11 | ], 12 | "values": [ 13 | { 14 | "value": [ 15 | "0x1111111111111111111111111111111111111111", 16 | "5000000000000000000" 17 | ], 18 | "treeIndex": 3 19 | }, 20 | { 21 | "value": [ 22 | "0x2222222222222222222222222222222222222222", 23 | "2500000000000000000" 24 | ], 25 | "treeIndex": 4 26 | }, 27 | { 28 | "value": [ 29 | "0x3333333333333333333333333333333333333333", 30 | "1500000000000000000" 31 | ], 32 | "treeIndex": 5 33 | }, 34 | { 35 | "value": [ 36 | "0x4444444444444444444444444444444444444444", 37 | "1000000000000000000" 38 | ], 39 | "treeIndex": 6 40 | } 41 | ], 42 | "leafEncoding": [ 43 | "address", 44 | "uint256" 45 | ] 46 | } -------------------------------------------------------------------------------- /docs/dump_proof.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": "0xcef9852531f2476330b76131d5de322f616540e5668b46383dd26f96c50d8861", 3 | "leafEncoding": [ 4 | "address", 5 | "uint256" 6 | ], 7 | "leafProof": [ 8 | { 9 | "value": [ 10 | "0x1111111111111111111111111111111111111111", 11 | "5000000000000000000" 12 | ], 13 | "proof": [ 14 | "0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc", 15 | "0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7" 16 | ] 17 | }, 18 | { 19 | "value": [ 20 | "0x2222222222222222222222222222222222222222", 21 | "2500000000000000000" 22 | ], 23 | "proof": [ 24 | "0xeb02c421cfa48976e66dfb29120745909ea3a0f843456c263cf8f1253483e283", 25 | "0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7" 26 | ] 27 | }, 28 | { 29 | "value": [ 30 | "0x3333333333333333333333333333333333333333", 31 | "1500000000000000000" 32 | ], 33 | "proof": [ 34 | "0x23cfee851b7629c71ca861a1c79681e9734fa944586795f3ec0a66c1371d382d", 35 | "0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77" 36 | ] 37 | }, 38 | { 39 | "value": [ 40 | "0x4444444444444444444444444444444444444444", 41 | "1000000000000000000" 42 | ], 43 | "proof": [ 44 | "0x6906f9b4ada8fe83b0371d6585849c98a5836a0c81fbb8f87a82008379a9159e", 45 | "0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77" 46 | ] 47 | } 48 | ] 49 | } -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/btcsuite/btcd/btcec/v2 v2.2.0 h1:fzn1qaOt32TuLjFlkzYSsBC35Q3KUjT1SwPxiMSCF5k= 2 | github.com/btcsuite/btcd/btcec/v2 v2.2.0/go.mod h1:U7MHm051Al6XmscBQ0BoNydpOTsFAn707034b5nY8zU= 3 | github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U= 4 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 6 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= 8 | github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= 9 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= 10 | github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= 11 | github.com/ethereum/go-ethereum v1.11.6 h1:2VF8Mf7XiSUfmoNOy3D+ocfl9Qu8baQBrCNbo2CXQ8E= 12 | github.com/ethereum/go-ethereum v1.11.6/go.mod h1:+a8pUj1tOyJ2RinsNQD4326YS+leSoKGiG/uVVb0x6Y= 13 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 14 | github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c h1:DZfsyhDK1hnSS5lH8l+JggqzEleHteTYfutAiVlSUM8= 15 | github.com/holiman/uint256 v1.2.2-0.20230321075855-87b91420868c/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw= 16 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 17 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 18 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= 19 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 20 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 21 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 22 | github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 23 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 24 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 25 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 26 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 27 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 28 | github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= 29 | golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= 30 | golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= 31 | golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= 32 | golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 33 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 34 | -------------------------------------------------------------------------------- /merkle-tree-contracts/test/StandardMerkleTree.ts: -------------------------------------------------------------------------------- 1 | import { time, loadFixture } from "@nomicfoundation/hardhat-network-helpers"; 2 | import { anyValue } from "@nomicfoundation/hardhat-chai-matchers/withArgs"; 3 | import { expect } from "chai"; 4 | import { ethers } from "hardhat"; 5 | import { StandardMerkleTree } from "@openzeppelin/merkle-tree"; 6 | 7 | describe("StandardMerkleTree", function () { 8 | 9 | async function deployFixture() { 10 | const [owner, otherAccount] = await ethers.getSigners(); 11 | const StandardMerkleTree = await ethers.getContractFactory("StandardMerkleTree"); 12 | const standardMerkleTree = await StandardMerkleTree.deploy(); 13 | 14 | return { standardMerkleTree, owner, otherAccount }; 15 | } 16 | 17 | describe("Merkle Tree", function () { 18 | 19 | it("verify", async function () { 20 | 21 | const { standardMerkleTree } = await loadFixture(deployFixture); 22 | 23 | const account = "0x1111111111111111111111111111111111111111"; 24 | const amount = "5000000000000000000"; 25 | const root = "0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77"; 26 | const proof = [ 27 | '0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc', 28 | ]; 29 | 30 | expect(await standardMerkleTree.verify(proof,root,account,amount)).to.equal(true); 31 | }); 32 | 33 | it("verifyMultiProof", async function () { 34 | const { standardMerkleTree } = await loadFixture(deployFixture); 35 | 36 | const proof = [ 37 | "0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7", 38 | ]; 39 | 40 | const proofFlags = [true, false]; 41 | 42 | const root = "0xcef9852531f2476330b76131d5de322f616540e5668b46383dd26f96c50d8861"; 43 | 44 | const accounts = [ 45 | "0x1111111111111111111111111111111111111111", 46 | "0x2222222222222222222222222222222222222222" 47 | ]; 48 | 49 | const amounts = [ 50 | "5000000000000000000", 51 | "2500000000000000000" 52 | ]; 53 | 54 | expect(await standardMerkleTree.multiProofVerify(proof, proofFlags ,root, accounts, amounts)).to.equal(true); 55 | }); 56 | 57 | it("array", async function () { 58 | // const { standardMerkleTree } = await loadFixture(deployFixture) 59 | const values = [ 60 | [ 61 | "0x1111111111111111111111111111111111111111", 62 | "1", 63 | "2", 64 | "3", 65 | // ["1","2","3"] 66 | ], 67 | [ 68 | "0x1111111111111111111111111111111111111111", 69 | "0", 70 | "2", 71 | "1", 72 | // ["0","1","2"] 73 | ], 74 | ]; 75 | const tree = StandardMerkleTree.of(values, [ 76 | "address", 77 | "uint8", 78 | "uint88", 79 | "uint128", 80 | // "uint8[]" 81 | ]) 82 | console.log('Merkle Root:', tree.root); 83 | console.log(tree.dump()) 84 | }) 85 | 86 | it("string", async function () { 87 | const values = [ 88 | [ 89 | "a", 90 | ], 91 | [ 92 | "b", 93 | ], 94 | [ 95 | "c", 96 | ], 97 | [ 98 | "d", 99 | ], 100 | ]; 101 | const tree = StandardMerkleTree.of(values, [ 102 | "string", 103 | ]) 104 | console.log('Merkle Root:', tree.root); 105 | console.log(tree.dump()) 106 | }) 107 | 108 | }); 109 | }); 110 | -------------------------------------------------------------------------------- /docs/main_run.txt: -------------------------------------------------------------------------------- 1 | === (1) Of BEGIN === 2 | Root: 0xcef9852531f2476330b76131d5de322f616540e5668b46383dd26f96c50d8861 3 | === (1) Of END === 4 | 5 | === (2) CreateTree BEGIN === 6 | === (2.2) AddLeaf BEGIN === 7 | 0 AddLeaf: 0xeb02c421cfa48976e66dfb29120745909ea3a0f843456c263cf8f1253483e283 8 | 1 AddLeaf: 0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc 9 | 2 AddLeaf: 0x6906f9b4ada8fe83b0371d6585849c98a5836a0c81fbb8f87a82008379a9159e 10 | 3 AddLeaf: 0x23cfee851b7629c71ca861a1c79681e9734fa944586795f3ec0a66c1371d382d 11 | === (2.2) AddLeaf END === 12 | === (2.3) MakeTree BEGIN === 13 | MakeTree Root: 0xcef9852531f2476330b76131d5de322f616540e5668b46383dd26f96c50d8861 14 | === (2.3) MakeTree END === 15 | 16 | === (3) Dump BEGIN === 17 | {"format":"standard-v1","tree":["0xcef9852531f2476330b76131d5de322f616540e5668b46383dd26f96c50d8861","0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77","0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7","0xeb02c421cfa48976e66dfb29120745909ea3a0f843456c263cf8f1253483e283","0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc","0x6906f9b4ada8fe83b0371d6585849c98a5836a0c81fbb8f87a82008379a9159e","0x23cfee851b7629c71ca861a1c79681e9734fa944586795f3ec0a66c1371d382d"],"values":[{"value":["0x1111111111111111111111111111111111111111","5000000000000000000"],"treeIndex":3},{"value":["0x2222222222222222222222222222222222222222","2500000000000000000"],"treeIndex":4},{"value":["0x3333333333333333333333333333333333333333","1500000000000000000"],"treeIndex":5},{"value":["0x4444444444444444444444444444444444444444","1000000000000000000"],"treeIndex":6}],"leafEncoding":["address","uint256"]} 18 | === (3) Dump END === 19 | 20 | === (4) Load BEGIN === 21 | ValueIndex: 0 , TreeIndex: 3 , Hash: 0xeb02c421cfa48976e66dfb29120745909ea3a0f843456c263cf8f1253483e283 , Value: [0x1111111111111111111111111111111111111111 5000000000000000000] 22 | [0] = 0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc 23 | [1] = 0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7 24 | === (4) Load END === 25 | 26 | === (5) DumpLeafProof BEGIN === 27 | {"root":"0xcef9852531f2476330b76131d5de322f616540e5668b46383dd26f96c50d8861","leafEncoding":["address","uint256"],"leafProof":[{"value":["0x1111111111111111111111111111111111111111","5000000000000000000"],"proof":["0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc","0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7"]},{"value":["0x2222222222222222222222222222222222222222","2500000000000000000"],"proof":["0xeb02c421cfa48976e66dfb29120745909ea3a0f843456c263cf8f1253483e283","0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7"]},{"value":["0x3333333333333333333333333333333333333333","1500000000000000000"],"proof":["0x23cfee851b7629c71ca861a1c79681e9734fa944586795f3ec0a66c1371d382d","0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77"]},{"value":["0x4444444444444444444444444444444444444444","1000000000000000000"],"proof":["0x6906f9b4ada8fe83b0371d6585849c98a5836a0c81fbb8f87a82008379a9159e","0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77"]}]} 28 | === (5) DumpLeafProof END === 29 | 30 | === (6) Verify BEGIN === 31 | Verify: true 32 | === (6) Verify END === 33 | 34 | === (7) VerifyMultiProof BEGIN === 35 | Proof: 36 | [0] = 0x8610c4ddba34d72ee1dabba4f1a813087579d4c6579c495c101530432969efa7 37 | ProofFlags: 38 | [true false] 39 | Values: 40 | [0x1111111111111111111111111111111111111111 5000000000000000000] 41 | [0x2222222222222222222222222222222222222222 2500000000000000000] 42 | Verify: true 43 | === (7) VerifyMultiProof END === -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | smt "github.com/FantasyJony/openzeppelin-merkle-tree-go/standard_merkle_tree" 6 | "github.com/ethereum/go-ethereum/common/hexutil" 7 | ) 8 | 9 | func main() { 10 | 11 | values := [][]interface{}{ 12 | { 13 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 14 | smt.SolNumber("5000000000000000000"), 15 | }, 16 | { 17 | smt.SolAddress("0x2222222222222222222222222222222222222222"), 18 | smt.SolNumber("2500000000000000000"), 19 | }, 20 | { 21 | smt.SolAddress("0x3333333333333333333333333333333333333333"), 22 | smt.SolNumber("1500000000000000000"), 23 | }, 24 | { 25 | smt.SolAddress("0x4444444444444444444444444444444444444444"), 26 | smt.SolNumber("1000000000000000000"), 27 | }, 28 | } 29 | 30 | leafEncodings := []string{ 31 | smt.SOL_ADDRESS, 32 | smt.SOL_UINT256, 33 | } 34 | 35 | fmt.Println("=== (1) Of BEGIN ===") 36 | 37 | // (1) make tree 38 | t1, err := smt.Of(values, leafEncodings) 39 | handleError(err) 40 | fmt.Println("Root: ", hexutil.Encode(t1.GetRoot())) 41 | 42 | fmt.Println("=== (1) Of END ===") 43 | 44 | fmt.Println() 45 | fmt.Println("=== (2) CreateTree BEGIN ===") 46 | 47 | // (2.1) create tree 48 | t2, err := smt.CreateTree(leafEncodings) 49 | 50 | // (2.2) add leaf 51 | fmt.Println("=== (2.2) AddLeaf BEGIN ===") 52 | for k, v := range values { 53 | leafHash0, err := t2.AddLeaf(v) 54 | handleError(err) 55 | fmt.Println(k, " AddLeaf: ", hexutil.Encode(leafHash0)) 56 | } 57 | fmt.Println("=== (2.2) AddLeaf END ===") 58 | 59 | // (2.3) make tree 60 | fmt.Println("=== (2.3) MakeTree BEGIN ===") 61 | r3, err := t2.MakeTree() 62 | fmt.Println("MakeTree Root: ", hexutil.Encode(r3)) 63 | fmt.Println("=== (2.3) MakeTree END ===") 64 | 65 | fmt.Println() 66 | // (3) dump 67 | fmt.Println("=== (3) Dump BEGIN ===") 68 | dump, err := t1.TreeMarshal() 69 | handleError(err) 70 | fmt.Println(string(dump)) 71 | fmt.Println("=== (3) Dump END ===") 72 | 73 | fmt.Println() 74 | // (4) load 75 | fmt.Println("=== (4) Load BEGIN ===") 76 | t3, err := smt.Load(dump) 77 | handleError(err) 78 | 79 | entries := t3.Entries() 80 | for k, v := range entries { 81 | if v.Value[0] == smt.SolAddress("0x1111111111111111111111111111111111111111") { 82 | proof, err := t3.GetProofWithIndex(k) 83 | handleError(err) 84 | fmt.Println(fmt.Sprintf("ValueIndex: %v , TreeIndex: %v , Hash: %v , Value: %v", v.ValueIndex, v.TreeIndex, hexutil.Encode(v.Hash), v.Value)) 85 | for pk, pv := range proof { 86 | fmt.Println(fmt.Sprintf("[%v] = %v", pk, hexutil.Encode(pv))) 87 | } 88 | } 89 | } 90 | fmt.Println("=== (4) Load END ===") 91 | 92 | fmt.Println() 93 | // (5) dump leaf proof 94 | fmt.Println("=== (5) DumpLeafProof BEGIN ===") 95 | 96 | leafProofDump, err := t3.TreeProofMarshal() 97 | handleError(err) 98 | fmt.Println(string(leafProofDump)) 99 | fmt.Println("=== (5) DumpLeafProof END ===") 100 | 101 | fmt.Println() 102 | // (6) verify proof 103 | fmt.Println("=== (6) Verify BEGIN ===") 104 | firstProof, err := t3.GetProofWithIndex(0) 105 | handleError(err) 106 | firstValue := entries[0].Value 107 | 108 | verified, err := t3.Verify(firstProof, firstValue) 109 | handleError(err) 110 | fmt.Println("Verify:", verified) 111 | fmt.Println("=== (6) Verify END ===") 112 | 113 | fmt.Println() 114 | // (7) 115 | fmt.Println("=== (7) VerifyMultiProof BEGIN ===") 116 | mulitProof, err := t3.GetMultiProof([][]interface{}{values[0], values[1]}) 117 | //t3.VerifyMultiProof() 118 | fmt.Println("Proof:") 119 | for k, v := range mulitProof.Proof { 120 | fmt.Println(fmt.Sprintf("[%v] = %v", k, hexutil.Encode(v))) 121 | } 122 | //fmt.Println("=== (7.1) Proof END ===") 123 | //fmt.Println() 124 | fmt.Println("ProofFlags:") 125 | //fmt.Println("=== (7.2) ProofFlags BEGIN ===") 126 | fmt.Println(mulitProof.ProofFlags) 127 | //fmt.Println("=== (7.2) ProofFlags END ===") 128 | //fmt.Println() 129 | 130 | fmt.Println("Values:") 131 | for _, v := range mulitProof.Values { 132 | fmt.Println(v) 133 | } 134 | 135 | verified, err = t3.VerifyMultiProof(mulitProof) 136 | handleError(err) 137 | fmt.Println("Verify:", verified) 138 | 139 | fmt.Println("=== (7) VerifyMultiProof END ===") 140 | } 141 | 142 | func handleError(err error) { 143 | if err != nil { 144 | panic(err) 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /standard_merkle_tree/solidity_types.go: -------------------------------------------------------------------------------- 1 | package standard_merkle_tree 2 | 3 | const SOL_ADDRESS = "address" 4 | const SOL_ADDRESS_ARRAY = "address[]" 5 | 6 | const SOL_BOOL = "bool" 7 | const SOL_BOOL_ARRAY = "bool[]" 8 | 9 | const SOL_BYTES1 = "bytes1" 10 | const SOL_BYTES1_ARRAY = "bytes1[]" 11 | 12 | const SOL_BYTES2 = "bytes2" 13 | const SOL_BYTES2_ARRAY = "bytes2[]" 14 | 15 | const SOL_BYTES3 = "bytes3" 16 | const SOL_BYTES3_ARRAY = "bytes3[]" 17 | 18 | const SOL_BYTES4 = "bytes4" 19 | const SOL_BYTES4_ARRAY = "bytes4[]" 20 | 21 | const SOL_BYTES5 = "bytes5" 22 | const SOL_BYTES5_ARRAY = "bytes5[]" 23 | 24 | const SOL_BYTES6 = "bytes6" 25 | const SOL_BYTES6_ARRAY = "bytes6[]" 26 | 27 | const SOL_BYTES7 = "bytes7" 28 | const SOL_BYTES7_ARRAY = "bytes7[]" 29 | 30 | const SOL_BYTES8 = "bytes8" 31 | const SOL_BYTES8_ARRAY = "bytes8[]" 32 | 33 | const SOL_BYTES9 = "bytes9" 34 | const SOL_BYTES9_ARRAY = "bytes9[]" 35 | 36 | const SOL_BYTES10 = "bytes10" 37 | const SOL_BYTES10_ARRAY = "bytes10[]" 38 | 39 | const SOL_BYTES11 = "bytes11" 40 | const SOL_BYTES11_ARRAY = "bytes11[]" 41 | 42 | const SOL_BYTES12 = "bytes12" 43 | const SOL_BYTES12_ARRAY = "bytes12[]" 44 | 45 | const SOL_BYTES13 = "bytes13" 46 | const SOL_BYTES13_ARRAY = "bytes13[]" 47 | 48 | const SOL_BYTES14 = "bytes14" 49 | const SOL_BYTES14_ARRAY = "bytes14[]" 50 | 51 | const SOL_BYTES15 = "bytes15" 52 | const SOL_BYTES15_ARRAY = "bytes15[]" 53 | 54 | const SOL_BYTES16 = "bytes16" 55 | const SOL_BYTES16_ARRAY = "bytes16[]" 56 | 57 | const SOL_BYTES17 = "bytes17" 58 | const SOL_BYTES17_ARRAY = "bytes17[]" 59 | 60 | const SOL_BYTES18 = "bytes18" 61 | const SOL_BYTES18_ARRAY = "bytes18[]" 62 | 63 | const SOL_BYTES19 = "bytes19" 64 | const SOL_BYTES19_ARRAY = "bytes19[]" 65 | 66 | const SOL_BYTES20 = "bytes20" 67 | const SOL_BYTES20_ARRAY = "bytes20[]" 68 | 69 | const SOL_BYTES21 = "bytes21" 70 | const SOL_BYTES21_ARRAY = "bytes21[]" 71 | 72 | const SOL_BYTES22 = "bytes22" 73 | const SOL_BYTES22_ARRAY = "bytes22[]" 74 | 75 | const SOL_BYTES23 = "bytes23" 76 | const SOL_BYTES23_ARRAY = "bytes23[]" 77 | 78 | const SOL_BYTES24 = "bytes24" 79 | const SOL_BYTES24_ARRAY = "bytes24[]" 80 | 81 | const SOL_BYTES25 = "bytes25" 82 | const SOL_BYTES25_ARRAY = "bytes25[]" 83 | 84 | const SOL_BYTES26 = "bytes26" 85 | const SOL_BYTES26_ARRAY = "bytes26[]" 86 | 87 | const SOL_BYTES27 = "bytes27" 88 | const SOL_BYTES27_ARRAY = "bytes27[]" 89 | 90 | const SOL_BYTES28 = "bytes28" 91 | const SOL_BYTES28_ARRAY = "bytes28[]" 92 | 93 | const SOL_BYTES29 = "bytes29" 94 | const SOL_BYTES29_ARRAY = "bytes29[]" 95 | 96 | const SOL_BYTES30 = "bytes30" 97 | const SOL_BYTES30_ARRAY = "bytes30[]" 98 | 99 | const SOL_BYTES31 = "bytes31" 100 | const SOL_BYTES31_ARRAY = "bytes31[]" 101 | 102 | const SOL_BYTES32 = "bytes32" 103 | const SOL_BYTES32_ARRAY = "bytes32[]" 104 | 105 | const SOL_STRING = "string" 106 | const SOL_STRING_ARRAY = "string[]" 107 | 108 | const SOL_BYTES = "bytes" 109 | const SOL_BYTES_ARRAY = "bytes[]" 110 | 111 | const SOL_INT8 = "int8" 112 | const SOL_INT8_ARRAY = "int8[]" 113 | 114 | const SOL_INT16 = "int16" 115 | const SOL_INT16_ARRAY = "int16[]" 116 | 117 | const SOL_INT24 = "int24" 118 | const SOL_INT24_ARRAY = "int24[]" 119 | 120 | const SOL_INT32 = "int32" 121 | const SOL_INT32_ARRAY = "int32[]" 122 | 123 | const SOL_INT40 = "int40" 124 | const SOL_INT40_ARRAY = "int40[]" 125 | 126 | const SOL_INT48 = "int48" 127 | const SOL_INT48_ARRAY = "int48[]" 128 | 129 | const SOL_INT56 = "int56" 130 | const SOL_INT56_ARRAY = "int56[]" 131 | 132 | const SOL_INT64 = "int64" 133 | const SOL_INT64_ARRAY = "int64[]" 134 | 135 | const SOL_INT72 = "int72" 136 | const SOL_INT72_ARRAY = "int72[]" 137 | 138 | const SOL_INT80 = "int80" 139 | const SOL_INT80_ARRAY = "int80[]" 140 | 141 | const SOL_INT88 = "int88" 142 | const SOL_INT88_ARRAY = "int88[]" 143 | 144 | const SOL_INT96 = "int96" 145 | const SOL_INT96_ARRAY = "int96[]" 146 | 147 | const SOL_INT104 = "int104" 148 | const SOL_INT104_ARRAY = "int104[]" 149 | 150 | const SOL_INT112 = "int112" 151 | const SOL_INT112_ARRAY = "int112[]" 152 | 153 | const SOL_INT120 = "int120" 154 | const SOL_INT120_ARRAY = "int120[]" 155 | 156 | const SOL_INT128 = "int128" 157 | const SOL_INT128_ARRAY = "int128[]" 158 | 159 | const SOL_INT136 = "int136" 160 | const SOL_INT136_ARRAY = "int136[]" 161 | 162 | const SOL_INT144 = "int144" 163 | const SOL_INT144_ARRAY = "int144[]" 164 | 165 | const SOL_INT152 = "int152" 166 | const SOL_INT152_ARRAY = "int152[]" 167 | 168 | const SOL_INT160 = "int160" 169 | const SOL_INT160_ARRAY = "int160[]" 170 | 171 | const SOL_INT168 = "int168" 172 | const SOL_INT168_ARRAY = "int168[]" 173 | 174 | const SOL_INT176 = "int176" 175 | const SOL_INT176_ARRAY = "int176[]" 176 | 177 | const SOL_INT184 = "int184" 178 | const SOL_INT184_ARRAY = "int184[]" 179 | 180 | const SOL_INT192 = "int192" 181 | const SOL_INT192_ARRAY = "int192[]" 182 | 183 | const SOL_INT200 = "int200" 184 | const SOL_INT200_ARRAY = "int200[]" 185 | 186 | const SOL_INT208 = "int208" 187 | const SOL_INT208_ARRAY = "int208[]" 188 | 189 | const SOL_INT216 = "int216" 190 | const SOL_INT216_ARRAY = "int216[]" 191 | 192 | const SOL_INT224 = "int224" 193 | const SOL_INT224_ARRAY = "int224[]" 194 | 195 | const SOL_INT232 = "int232" 196 | const SOL_INT232_ARRAY = "int232[]" 197 | 198 | const SOL_INT240 = "int240" 199 | const SOL_INT240_ARRAY = "int240[]" 200 | 201 | const SOL_INT248 = "int248" 202 | const SOL_INT248_ARRAY = "int248[]" 203 | 204 | const SOL_INT256 = "int256" 205 | const SOL_INT256_ARRAY = "int256[]" 206 | 207 | const SOL_UINT8 = "uint8" 208 | const SOL_UINT8_ARRAY = "uint8[]" 209 | 210 | const SOL_UINT16 = "uint16" 211 | const SOL_UINT16_ARRAY = "uint16[]" 212 | 213 | const SOL_UINT24 = "uint24" 214 | const SOL_UINT24_ARRAY = "uint24[]" 215 | 216 | const SOL_UINT32 = "uint32" 217 | const SOL_UINT32_ARRAY = "uint32[]" 218 | 219 | const SOL_UINT40 = "uint40" 220 | const SOL_UINT40_ARRAY = "uint40[]" 221 | 222 | const SOL_UINT48 = "uint48" 223 | const SOL_UINT48_ARRAY = "uint48[]" 224 | 225 | const SOL_UINT56 = "uint56" 226 | const SOL_UINT56_ARRAY = "uint56[]" 227 | 228 | const SOL_UINT64 = "uint64" 229 | const SOL_UINT64_ARRAY = "uint64[]" 230 | 231 | const SOL_UINT72 = "uint72" 232 | const SOL_UINT72_ARRAY = "uint72[]" 233 | 234 | const SOL_UINT80 = "uint80" 235 | const SOL_UINT80_ARRAY = "uint80[]" 236 | 237 | const SOL_UINT88 = "uint88" 238 | const SOL_UINT88_ARRAY = "uint88[]" 239 | 240 | const SOL_UINT96 = "uint96" 241 | const SOL_UINT96_ARRAY = "uint96[]" 242 | 243 | const SOL_UINT104 = "uint104" 244 | const SOL_UINT104_ARRAY = "uint104[]" 245 | 246 | const SOL_UINT112 = "uint112" 247 | const SOL_UINT112_ARRAY = "uint112[]" 248 | 249 | const SOL_UINT120 = "uint120" 250 | const SOL_UINT120_ARRAY = "uint120[]" 251 | 252 | const SOL_UINT128 = "uint128" 253 | const SOL_UINT128_ARRAY = "uint128[]" 254 | 255 | const SOL_UINT136 = "uint136" 256 | const SOL_UINT136_ARRAY = "uint136[]" 257 | 258 | const SOL_UINT144 = "uint144" 259 | const SOL_UINT144_ARRAY = "uint144[]" 260 | 261 | const SOL_UINT152 = "uint152" 262 | const SOL_UINT152_ARRAY = "uint152[]" 263 | 264 | const SOL_UINT160 = "uint160" 265 | const SOL_UINT160_ARRAY = "uint160[]" 266 | 267 | const SOL_UINT168 = "uint168" 268 | const SOL_UINT168_ARRAY = "uint168[]" 269 | 270 | const SOL_UINT176 = "uint176" 271 | const SOL_UINT176_ARRAY = "uint176[]" 272 | 273 | const SOL_UINT184 = "uint184" 274 | const SOL_UINT184_ARRAY = "uint184[]" 275 | 276 | const SOL_UINT192 = "uint192" 277 | const SOL_UINT192_ARRAY = "uint192[]" 278 | 279 | const SOL_UINT200 = "uint200" 280 | const SOL_UINT200_ARRAY = "uint200[]" 281 | 282 | const SOL_UINT208 = "uint208" 283 | const SOL_UINT208_ARRAY = "uint208[]" 284 | 285 | const SOL_UINT216 = "uint216" 286 | const SOL_UINT216_ARRAY = "uint216[]" 287 | 288 | const SOL_UINT224 = "uint224" 289 | const SOL_UINT224_ARRAY = "uint224[]" 290 | 291 | const SOL_UINT232 = "uint232" 292 | const SOL_UINT232_ARRAY = "uint232[]" 293 | 294 | const SOL_UINT240 = "uint240" 295 | const SOL_UINT240_ARRAY = "uint240[]" 296 | 297 | const SOL_UINT248 = "uint248" 298 | const SOL_UINT248_ARRAY = "uint248[]" 299 | 300 | const SOL_UINT256 = "uint256" 301 | const SOL_UINT256_ARRAY = "uint256[]" 302 | -------------------------------------------------------------------------------- /standard_merkle_tree/openzeppelin_utils.go: -------------------------------------------------------------------------------- 1 | package standard_merkle_tree 2 | 3 | import ( 4 | "bytes" 5 | "github.com/pkg/errors" 6 | "math" 7 | "sort" 8 | ) 9 | 10 | func abiPackLeafHash(leafEncodings []string, values ...interface{}) ([]byte, error) { 11 | data, err := AbiPack(leafEncodings, values...) 12 | if err != nil { 13 | return nil, err 14 | } 15 | hash, err := standardLeafHash(data) 16 | return hash, err 17 | } 18 | 19 | func standardLeafHash(value []byte) ([]byte, error) { 20 | k1, err := Keccak256(value) 21 | if err != nil { 22 | return nil, err 23 | } 24 | k2, err := Keccak256(k1) 25 | return k2, err 26 | } 27 | 28 | func hashPair(a, b []byte) ([]byte, error) { 29 | pairs := [][]byte{a, b} 30 | sort.Slice(pairs, func(i, j int) bool { 31 | return compareBytes(pairs[i], pairs[j]) 32 | }) 33 | var data []byte 34 | for _, v := range pairs { 35 | data = append(data, v...) 36 | } 37 | return Keccak256(data) 38 | } 39 | 40 | func makeMerkleTree(leaves [][]byte) ([][]byte, error) { 41 | if len(leaves) == 0 { 42 | return nil, errors.New("Expected non-zero number of leaves") 43 | } 44 | for _, v := range leaves { 45 | err := checkValidMerkleNode(v) 46 | if err != nil { 47 | return nil, err 48 | } 49 | } 50 | lenTree := 2*len(leaves) - 1 51 | hashTree := make([][]byte, lenTree) 52 | for i, v := range leaves { 53 | hashTree[lenTree-1-i] = v 54 | } 55 | for i := lenTree - 1 - len(leaves); i >= 0; i-- { 56 | hash, err := hashPair(hashTree[leftChildIndex(i)], hashTree[rightChildIndex(i)]) 57 | if err != nil { 58 | return nil, err 59 | } 60 | hashTree[i] = hash 61 | } 62 | return hashTree, nil 63 | } 64 | 65 | func compareBytes(a, b []byte) bool { 66 | n := len(a) 67 | if len(b) < len(a) { 68 | n = len(b) 69 | } 70 | for i := 0; i < n; i++ { 71 | if a[i] != b[i] { 72 | return a[i] < b[i] 73 | } 74 | } 75 | return len(a) < len(b) 76 | } 77 | 78 | func siblingIndex(i int) (int, error) { 79 | if i > 0 { 80 | return i - int(math.Pow(-1, float64(i%2))), nil 81 | } else { 82 | return 0, errors.New("Root has no siblings") 83 | } 84 | } 85 | 86 | func parentIndex(i int) (int, error) { 87 | if i > 0 { 88 | return int(math.Floor(float64(i-1) / 2)), nil 89 | } else { 90 | return 0, errors.New("Root has no siblings") 91 | } 92 | } 93 | 94 | func leftChildIndex(i int) int { 95 | return 2*i + 1 96 | } 97 | 98 | func rightChildIndex(i int) int { 99 | return 2*i + 2 100 | } 101 | 102 | func getProof(tree [][]byte, index int) ([][]byte, error) { 103 | err := checkLeafNode(tree, index) 104 | if err != nil { 105 | return nil, err 106 | } 107 | proof := make([][]byte, 0) 108 | for index > 0 { 109 | treeIndex, err := siblingIndex(index) 110 | if err != nil { 111 | return nil, err 112 | } 113 | proof = append(proof, tree[treeIndex]) 114 | index, err = parentIndex(index) 115 | if err != nil { 116 | return nil, err 117 | } 118 | } 119 | return proof, nil 120 | } 121 | 122 | func verify(rootHash, leafHash []byte, proof [][]byte) (bool, error) { 123 | impliedRoot, err := processProof(leafHash, proof) 124 | if err != nil { 125 | return false, err 126 | } 127 | return bytes.Equal(rootHash, impliedRoot), nil 128 | } 129 | 130 | type MultiProof struct { 131 | Proof [][]byte 132 | ProofFlags []bool 133 | Leaves [][]byte 134 | } 135 | 136 | func getMultiProof(tree [][]byte, indices []int) (*MultiProof, error) { 137 | 138 | for _, v := range indices { 139 | err := checkLeafNode(tree, v) 140 | if err != nil { 141 | return nil, err 142 | } 143 | } 144 | 145 | if someValue(indices) { 146 | return nil, errors.New("Cannot prove duplicated index") 147 | } 148 | 149 | stack := make([]int, len(indices)) 150 | copy(stack, indices) 151 | 152 | proofFlags := make([]bool, 0) 153 | proof := make([][]byte, 0) 154 | 155 | for len(stack) > 0 && stack[0] > 0 { 156 | 157 | j, err := shift(&stack) 158 | if err != nil { 159 | return nil, err 160 | } 161 | 162 | s, err := siblingIndex(j) 163 | if err != nil { 164 | return nil, err 165 | } 166 | 167 | p, err := parentIndex(j) 168 | if err != nil { 169 | return nil, err 170 | } 171 | 172 | if len(stack) > 0 && s == stack[0] { 173 | proofFlags = append(proofFlags, true) 174 | _, err := shift(&stack) 175 | if err != nil { 176 | return nil, err 177 | } 178 | } else { 179 | proofFlags = append(proofFlags, false) 180 | proof = append(proof, tree[s]) 181 | } 182 | 183 | stack = append(stack, p) 184 | } 185 | 186 | if len(indices) == 0 { 187 | proof = append(proof, tree[0]) 188 | } 189 | 190 | leaves := make([][]byte, len(indices)) 191 | for k, v := range indices { 192 | leaves[k] = tree[v] 193 | } 194 | 195 | return &MultiProof{ 196 | Proof: proof, 197 | ProofFlags: proofFlags, 198 | Leaves: leaves, 199 | }, nil 200 | } 201 | 202 | func verifyMultiProof(rootHash []byte, multiProof *MultiProof) (bool, error) { 203 | impliedRoot, err := processMultiProof(multiProof) 204 | if err != nil { 205 | return false, err 206 | } 207 | return bytes.Equal(rootHash, impliedRoot), nil 208 | } 209 | 210 | func processMultiProof(multiProof *MultiProof) ([]byte, error) { 211 | for _, v := range multiProof.Leaves { 212 | err := checkValidMerkleNode(v) 213 | if err != nil { 214 | return nil, err 215 | } 216 | } 217 | 218 | for _, v := range multiProof.Proof { 219 | err := checkValidMerkleNode(v) 220 | if err != nil { 221 | return nil, err 222 | } 223 | } 224 | 225 | unFlagCount := 0 226 | for _, v := range multiProof.ProofFlags { 227 | if v == false { 228 | unFlagCount++ 229 | } 230 | } 231 | 232 | if len(multiProof.Proof) < unFlagCount { 233 | return nil, errors.New("Invalid multiProof format") 234 | } 235 | 236 | if len(multiProof.Leaves)+len(multiProof.Proof) != len(multiProof.ProofFlags)+1 { 237 | return nil, errors.New("Provided leaves and multiProof are not compatible") 238 | } 239 | 240 | stack := make([][]byte, len(multiProof.Leaves)) 241 | copy(stack, multiProof.Leaves) 242 | 243 | proof := make([][]byte, len(multiProof.Proof)) 244 | copy(proof, multiProof.Proof) 245 | 246 | for _, flag := range multiProof.ProofFlags { 247 | 248 | a, err := shift(&stack) 249 | if err != nil { 250 | return nil, err 251 | } 252 | 253 | var b []byte 254 | if flag { 255 | b, err = shift(&stack) 256 | if err != nil { 257 | return nil, err 258 | } 259 | } else { 260 | b, err = shift(&proof) 261 | if err != nil { 262 | return nil, err 263 | } 264 | } 265 | 266 | c, err := hashPair(a, b) 267 | if err != nil { 268 | return nil, err 269 | } 270 | 271 | stack = append(stack, c) 272 | } 273 | 274 | leafProof, err := pop(&stack) 275 | if err == nil { 276 | return leafProof, nil 277 | } 278 | 279 | leafProof, err = shift(&proof) 280 | if err != nil { 281 | return nil, err 282 | } 283 | 284 | return leafProof, nil 285 | } 286 | 287 | func processProof(leaf []byte, proof [][]byte) ([]byte, error) { 288 | err := checkValidMerkleNode(leaf) 289 | if err != nil { 290 | return nil, err 291 | } 292 | for _, v := range proof { 293 | err = checkValidMerkleNode(v) 294 | if err != nil { 295 | return nil, err 296 | } 297 | } 298 | 299 | leafProof := make([]byte, len(leaf)) 300 | copy(leafProof, leaf) 301 | 302 | for _, v := range proof { 303 | hash, err := hashPair(leafProof, v) 304 | if err != nil { 305 | return nil, err 306 | } 307 | leafProof = hash 308 | } 309 | 310 | return leafProof, err 311 | } 312 | 313 | func isTreeNode(tree [][]byte, i int) bool { 314 | return i >= 0 && i < len(tree) 315 | } 316 | 317 | func isInternalNode(tree [][]byte, i int) bool { 318 | return isTreeNode(tree, leftChildIndex(i)) 319 | } 320 | 321 | func isValidMerkleNode(hash []byte) bool { 322 | return len(hash) == 32 323 | } 324 | 325 | func isLeafNode(tree [][]byte, i int) bool { 326 | return isTreeNode(tree, i) && !isInternalNode(tree, i) 327 | } 328 | 329 | func checkValidMerkleNode(hash []byte) error { 330 | if isValidMerkleNode(hash) { 331 | return nil 332 | } 333 | return errors.New("Merkle tree nodes must length 32") 334 | } 335 | 336 | func checkLeafNode(tree [][]byte, i int) error { 337 | if isLeafNode(tree, i) { 338 | return nil 339 | } 340 | return errors.New("Index is not a leaf") 341 | } 342 | 343 | func shift[T any](values *[]T) (T, error) { 344 | if len(*values) == 0 { 345 | var empty T 346 | return empty, errors.New("Values len is zero") 347 | } 348 | firstElement := (*values)[0] 349 | *values = (*values)[1:] 350 | return firstElement, nil 351 | } 352 | 353 | func pop[T any](values *[]T) (T, error) { 354 | if len(*values) == 0 { 355 | var empty T 356 | return empty, errors.New("Values len is zero") 357 | } 358 | lastIdx := len(*values) - 1 359 | lastElement := (*values)[lastIdx] 360 | *values = (*values)[:lastIdx] 361 | return lastElement, nil 362 | } 363 | 364 | func checkBounds[T any](index int, values []T) error { 365 | if index < 0 || index >= len(values) { 366 | return errors.New("Index out of bounds") 367 | } 368 | return nil 369 | } 370 | 371 | func someValue[T comparable](indices []T) bool { 372 | for i := 1; i < len(indices); i++ { 373 | for p := 0; p < i; p++ { 374 | if indices[i] == indices[p] { 375 | return true 376 | } 377 | } 378 | } 379 | return false 380 | } 381 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /standard_merkle_tree/openzeppelin_standard_tree.go: -------------------------------------------------------------------------------- 1 | package standard_merkle_tree 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | "github.com/ethereum/go-ethereum/common/hexutil" 7 | json_iterator "github.com/json-iterator/go" 8 | "github.com/pkg/errors" 9 | "sort" 10 | ) 11 | 12 | var ( 13 | json = json_iterator.ConfigCompatibleWithStandardLibrary 14 | ) 15 | 16 | type StandardTree struct { 17 | leafEncodings []string 18 | leaves []*LeafValue 19 | hashLookup map[string]int 20 | tree [][]byte 21 | } 22 | 23 | type LeafValue struct { 24 | ValueIndex int 25 | TreeIndex int 26 | Hash []byte 27 | Value []interface{} 28 | } 29 | 30 | func (l *LeafValue) getSolValueMarshal(leafEncoding []string) []interface{} { 31 | values := make([]interface{}, len(leafEncoding)) 32 | for k, v := range leafEncoding { 33 | values[k] = ToJsonValue(l.Value[k], v) 34 | } 35 | return values 36 | } 37 | 38 | type ValueMultiProof struct { 39 | Proof [][]byte 40 | ProofFlags []bool 41 | Values [][]interface{} 42 | } 43 | 44 | type StandardValueData struct { 45 | Value []interface{} `json:"value"` 46 | TreeIndex int `json:"treeIndex"` 47 | } 48 | 49 | func (svd *StandardValueData) getSolValueUnmarshal(leafEncoding []string) []interface{} { 50 | values := make([]interface{}, len(svd.Value)) 51 | for k, v := range svd.Value { 52 | values[k] = ToSolValue(v, leafEncoding[k]) 53 | } 54 | return values 55 | } 56 | 57 | type StandardMerkleTreeData struct { 58 | Format string `json:"format"` 59 | Tree []string `json:"tree"` 60 | Values []*StandardValueData `json:"values"` 61 | LeafEncoding []string `json:"leafEncoding"` 62 | } 63 | 64 | type StandardMerkleLeafProofData struct { 65 | Value []interface{} `json:"value"` 66 | Proof []string `json:"proof"` 67 | } 68 | 69 | func (lpd *StandardMerkleLeafProofData) getSolValueUnmarshal(leafEncoding []string) []interface{} { 70 | values := make([]interface{}, len(leafEncoding)) 71 | for k, v := range leafEncoding { 72 | values[k] = ToSolValue(lpd.Value[k], v) 73 | } 74 | return values 75 | } 76 | 77 | type StandardMerkleTreeProofData struct { 78 | Root string `json:"root"` 79 | LeafEncoding []string `json:"leafEncoding"` 80 | Proofs []*StandardMerkleLeafProofData `json:"leafProof"` 81 | } 82 | 83 | func (l *LeafValue) ToString() string { 84 | return fmt.Sprintf("ValueIndex: %v, TreeIndex: %v , Hash:%v", l.ValueIndex, l.TreeIndex, hexutil.Encode(l.Hash)) 85 | } 86 | 87 | func CreateTree(leafEncodings []string) (*StandardTree, error) { 88 | return &StandardTree{ 89 | leafEncodings: leafEncodings, 90 | }, nil 91 | } 92 | 93 | func Of(leaves [][]interface{}, leafEncodings []string) (*StandardTree, error) { 94 | tree, err := CreateTree(leafEncodings) 95 | if err != nil { 96 | return nil, err 97 | } 98 | for _, v := range leaves { 99 | _, err := tree.AddLeaf(v) 100 | if err != nil { 101 | return nil, err 102 | } 103 | } 104 | _, err = tree.MakeTree() 105 | if err != nil { 106 | return nil, err 107 | } 108 | return tree, nil 109 | } 110 | 111 | func LeafHash(leafEncodings []string, values []interface{}) ([]byte, error) { 112 | return abiPackLeafHash(leafEncodings, values...) 113 | } 114 | 115 | func Verify(rootHash []byte, leaf []byte, proof [][]byte) (bool, error) { 116 | return verify(rootHash, leaf, proof) 117 | } 118 | 119 | func VerifyMultiProof(rootHash []byte, multiProof *MultiProof) (bool, error) { 120 | return verifyMultiProof(rootHash, multiProof) 121 | } 122 | 123 | func (st *StandardTree) checkLeafEncodings() error { 124 | if st.leafEncodings == nil || len(st.leafEncodings) == 0 { 125 | return errors.New("LeafEncodings is not in StandardTree") 126 | } 127 | return nil 128 | } 129 | 130 | func (st *StandardTree) validateValue(valueIndex int) ([]byte, error) { 131 | err := checkBounds(valueIndex, st.leaves) 132 | if err != nil { 133 | return nil, err 134 | } 135 | leafValue, err := st.getLeafValue(valueIndex) 136 | if err != nil { 137 | return nil, err 138 | } 139 | treeIndex := leafValue.TreeIndex 140 | err = checkBounds(treeIndex, st.tree) 141 | if err != nil { 142 | return nil, err 143 | } 144 | value := leafValue.Value 145 | leaf, err := st.LeafHash(value) 146 | if err != nil { 147 | return nil, err 148 | } 149 | if bytes.Equal(leaf, st.tree[treeIndex]) == false { 150 | return nil, errors.New("Merkle tree does not contain the expected value") 151 | } 152 | return leaf, nil 153 | } 154 | 155 | func (st *StandardTree) getLeafValue(valueIndex int) (*LeafValue, error) { 156 | err := checkBounds(valueIndex, st.leaves) 157 | if err != nil { 158 | return nil, err 159 | } 160 | for _, v := range st.leaves { 161 | if v.ValueIndex == valueIndex { 162 | return v, nil 163 | } 164 | } 165 | return nil, errors.New("valueIndex is not in leaves") 166 | } 167 | 168 | func (st *StandardTree) getValueIndexWithLeafHash(leafHash []byte) (int, error) { 169 | value, ok := st.hashLookup[hexutil.Encode(leafHash)] 170 | if ok == false { 171 | return 0, errors.New("Leaf is not in tree") 172 | } 173 | return value, nil 174 | } 175 | 176 | func (st *StandardTree) leafLookup(values []interface{}) (int, error) { 177 | leafHash, err := st.LeafHash(values) 178 | if err != nil { 179 | return 0, err 180 | } 181 | return st.getValueIndexWithLeafHash(leafHash) 182 | } 183 | 184 | func (st *StandardTree) LeafHash(values []interface{}) ([]byte, error) { 185 | return LeafHash(st.leafEncodings, values) 186 | } 187 | 188 | func (st *StandardTree) LeafHashWithIndex(index int) ([]byte, error) { 189 | return st.validateValue(index) 190 | } 191 | 192 | func (st *StandardTree) GetProof(leaf []interface{}) ([][]byte, error) { 193 | valueIndex, err := st.leafLookup(leaf) 194 | if err != nil { 195 | return nil, err 196 | } 197 | return st.GetProofWithIndex(valueIndex) 198 | } 199 | 200 | func (st *StandardTree) GetProofWithIndex(valueIndex int) ([][]byte, error) { 201 | _, err := st.validateValue(valueIndex) 202 | if err != nil { 203 | return nil, err 204 | } 205 | 206 | leafValue, err := st.getLeafValue(valueIndex) 207 | if err != nil { 208 | return nil, err 209 | } 210 | 211 | treeIndex := leafValue.TreeIndex 212 | proof, err := getProof(st.tree, treeIndex) 213 | 214 | if err != nil { 215 | return nil, err 216 | } 217 | verifyResult, err := verify(st.GetRoot(), st.tree[treeIndex], proof) 218 | if err != nil { 219 | return nil, err 220 | } 221 | if !verifyResult { 222 | return nil, errors.New("unable to prove value") 223 | } 224 | return proof, nil 225 | } 226 | 227 | func (st *StandardTree) Verify(proof [][]byte, leaf []interface{}) (bool, error) { 228 | leafHash, err := st.LeafHash(leaf) 229 | if err != nil { 230 | return false, err 231 | } 232 | return verify(st.GetRoot(), leafHash, proof) 233 | } 234 | 235 | func (st *StandardTree) VerifyWithIndex(proof [][]byte, index int) (bool, error) { 236 | leafHash, err := st.LeafHashWithIndex(index) 237 | if err != nil { 238 | return false, err 239 | } 240 | return verify(st.GetRoot(), leafHash, proof) 241 | } 242 | 243 | func (st *StandardTree) GetMultiProof(leaves [][]interface{}) (*ValueMultiProof, error) { 244 | valueIndices := make([]int, len(leaves)) 245 | for k, v := range leaves { 246 | index, err := st.leafLookup(v) 247 | if err != nil { 248 | return nil, err 249 | } 250 | valueIndices[k] = index 251 | } 252 | return st.GetMultiProofWithIndices(valueIndices) 253 | } 254 | 255 | func (st *StandardTree) GetMultiProofWithIndices(indices []int) (*ValueMultiProof, error) { 256 | for _, v := range indices { 257 | _, err := st.validateValue(v) 258 | if err != nil { 259 | return nil, err 260 | } 261 | } 262 | treeIndices := make([]int, len(indices)) 263 | for k, v := range indices { 264 | leaf, err := st.getLeafValue(v) 265 | if err != nil { 266 | return nil, err 267 | } 268 | treeIndices[k] = leaf.TreeIndex 269 | } 270 | proof, err := getMultiProof(st.tree, treeIndices) 271 | if err != nil { 272 | return nil, err 273 | } 274 | verifyResult, err := verifyMultiProof(st.GetRoot(), proof) 275 | if verifyResult == false { 276 | return nil, errors.New("Unable to prove values") 277 | } 278 | leaves := make([][]interface{}, len(proof.Leaves)) 279 | for k, v := range proof.Leaves { 280 | valueIndex, err := st.getValueIndexWithLeafHash(v) 281 | if err != nil { 282 | return nil, err 283 | } 284 | leaf, err := st.getLeafValue(valueIndex) 285 | if err != nil { 286 | return nil, err 287 | } 288 | leaves[k] = leaf.Value 289 | } 290 | 291 | return &ValueMultiProof{ 292 | Values: leaves, 293 | Proof: proof.Proof, 294 | ProofFlags: proof.ProofFlags, 295 | }, nil 296 | } 297 | 298 | func (st *StandardTree) VerifyMultiProof(multiProof *ValueMultiProof) (bool, error) { 299 | leaves := make([][]byte, len(multiProof.Values)) 300 | for k, v := range multiProof.Values { 301 | leafHash, err := st.LeafHash(v) 302 | if err != nil { 303 | return false, err 304 | } 305 | leaves[k] = leafHash 306 | } 307 | proof := &MultiProof{ 308 | Proof: multiProof.Proof, 309 | ProofFlags: multiProof.ProofFlags, 310 | Leaves: leaves, 311 | } 312 | return verifyMultiProof(st.GetRoot(), proof) 313 | } 314 | 315 | func (st *StandardTree) AddLeaf(values []interface{}) ([]byte, error) { 316 | 317 | err := st.checkLeafEncodings() 318 | if err != nil { 319 | return nil, err 320 | } 321 | 322 | if len(st.leafEncodings) != len(values) { 323 | return nil, errors.New("Length mismatch") 324 | } 325 | 326 | leafHash, err := st.LeafHash(values) 327 | if err != nil { 328 | return nil, err 329 | } 330 | 331 | leafValue := &LeafValue{ 332 | Value: values, 333 | ValueIndex: len(st.leaves), 334 | Hash: leafHash, 335 | } 336 | 337 | st.leaves = append(st.leaves, leafValue) 338 | return leafHash, nil 339 | } 340 | 341 | func (st *StandardTree) MakeTree() ([]byte, error) { 342 | 343 | if len(st.leaves) == 0 { 344 | return nil, errors.New("Expected non-zero number of leaves") 345 | } 346 | 347 | // sort hash 348 | leafValues := make([]*LeafValue, len(st.leaves)) 349 | for k, v := range st.leaves { 350 | leafValues[k] = v 351 | } 352 | sort.Slice(leafValues, func(i, j int) bool { 353 | return compareBytes(leafValues[i].Hash, leafValues[j].Hash) 354 | }) 355 | leaves := make([][]byte, len(leafValues)) 356 | for k, v := range leafValues { 357 | leaves[k] = v.Hash 358 | } 359 | 360 | // make tree 361 | tree, err := makeMerkleTree(leaves) 362 | if err != nil { 363 | return nil, err 364 | } 365 | 366 | hashLookup := make(map[string]int) 367 | for leafIndex, v := range leafValues { 368 | treeIndex := len(tree) - leafIndex - 1 369 | v.TreeIndex = treeIndex 370 | hashLookup[hexutil.Encode(v.Hash)] = v.ValueIndex 371 | } 372 | 373 | st.hashLookup = hashLookup 374 | st.tree = tree 375 | return st.GetRoot(), nil 376 | } 377 | 378 | func (st *StandardTree) Entries() []*LeafValue { 379 | return st.leaves 380 | } 381 | 382 | func (st *StandardTree) GetRoot() []byte { 383 | return st.tree[0] 384 | } 385 | 386 | func (st *StandardTree) Dump() *StandardMerkleTreeData { 387 | tree := make([]string, len(st.tree)) 388 | for k, v := range st.tree { 389 | tree[k] = hexutil.Encode(v) 390 | } 391 | valueData := make([]*StandardValueData, len(st.leaves)) 392 | for k, v := range st.leaves { 393 | valueData[k] = &StandardValueData{ 394 | TreeIndex: v.TreeIndex, 395 | Value: v.getSolValueMarshal(st.leafEncodings), 396 | } 397 | } 398 | return &StandardMerkleTreeData{ 399 | Format: "standard-v1", 400 | LeafEncoding: st.leafEncodings, 401 | Tree: tree, 402 | Values: valueData, 403 | } 404 | } 405 | 406 | func (st *StandardTree) TreeMarshal() ([]byte, error) { 407 | treeData := st.Dump() 408 | return json.Marshal(treeData) 409 | } 410 | 411 | func TreeUnmarshal(value []byte) (*StandardTree, error) { 412 | var std StandardMerkleTreeData 413 | err := json.Unmarshal(value, &std) 414 | if err != nil { 415 | return nil, err 416 | } 417 | values := make([][]interface{}, len(std.Values)) 418 | for k, v := range std.Values { 419 | values[k] = v.getSolValueUnmarshal(std.LeafEncoding) 420 | } 421 | tree, err := Of(values, std.LeafEncoding) 422 | return tree, err 423 | } 424 | 425 | func Load(value []byte) (*StandardTree, error) { 426 | return TreeUnmarshal(value) 427 | } 428 | 429 | func (st *StandardTree) DumpLeafProof() (*StandardMerkleTreeProofData, error) { 430 | leafProofData := make([]*StandardMerkleLeafProofData, len(st.leaves)) 431 | for k, v := range st.leaves { 432 | values := v.getSolValueMarshal(st.leafEncodings) 433 | leafProof, err := st.GetProof(v.Value) 434 | if err != nil { 435 | return nil, err 436 | } 437 | proof := make([]string, len(leafProof)) 438 | for a, b := range leafProof { 439 | proof[a] = hexutil.Encode(b) 440 | } 441 | leafProofData[k] = &StandardMerkleLeafProofData{ 442 | Value: values, 443 | Proof: proof, 444 | } 445 | } 446 | return &StandardMerkleTreeProofData{ 447 | Root: hexutil.Encode(st.GetRoot()), 448 | Proofs: leafProofData, 449 | LeafEncoding: st.leafEncodings, 450 | }, nil 451 | } 452 | 453 | func (st *StandardTree) TreeProofMarshal() ([]byte, error) { 454 | treeData, err := st.DumpLeafProof() 455 | if err != nil { 456 | return nil, err 457 | } 458 | return json.Marshal(treeData) 459 | } 460 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Openzeppelin Standard Tree Go 2 | 3 | Fork [@openzeppelin/merkle-tree](https://github.com/OpenZeppelin/merkle-tree) 4 | 5 | A Go library to generate merkle trees and merkle proofs. 6 | 7 | ![GitHub tag (latest SemVer pre-release)](https://img.shields.io/github/v/tag/FantasyJony/openzeppelin-merkle-tree-go) 8 | ![GitHub issues](https://img.shields.io/github/issues/FantasyJony/openzeppelin-merkle-tree-go) 9 | ![GitHub closed issues](https://img.shields.io/github/issues-closed/FantasyJony/openzeppelin-merkle-tree-go) 10 | ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/FantasyJony/openzeppelin-merkle-tree-go/main) 11 | 12 | ![GitHub go.mod Go version (branch & subdirectory of monorepo)](https://img.shields.io/github/go-mod/go-version/FantasyJony/openzeppelin-merkle-tree-go/main) 13 | [![Go Reference](https://pkg.go.dev/badge/github.com/FantasyJony/openzeppelin-merkle-tree-go.svg)](https://pkg.go.dev/github.com/FantasyJony/openzeppelin-merkle-tree-go) 14 | [![GitHub](https://img.shields.io/github/license/FantasyJony/openzeppelin-merkle-tree-go)](https://opensource.org/licenses/Apache-2.0) 15 | 16 | 17 | ## Installation 18 | ``` 19 | go get github.com/FantasyJony/openzeppelin-merkle-tree-go@v1.1.3 20 | ``` 21 | 22 | ``` 23 | go mod tidy 24 | ``` 25 | 26 | ## Example 27 | 28 | ```go 29 | package main 30 | 31 | import ( 32 | "fmt" 33 | smt "github.com/FantasyJony/openzeppelin-merkle-tree-go/standard_merkle_tree" 34 | "github.com/ethereum/go-ethereum/common/hexutil" 35 | ) 36 | 37 | func main() { 38 | 39 | values := [][]interface{}{ 40 | { 41 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 42 | smt.SolNumber("5000000000000000000"), 43 | }, 44 | { 45 | smt.SolAddress("0x2222222222222222222222222222222222222222"), 46 | smt.SolNumber("2500000000000000000"), 47 | }, 48 | { 49 | smt.SolAddress("0x3333333333333333333333333333333333333333"), 50 | smt.SolNumber("1500000000000000000"), 51 | }, 52 | { 53 | smt.SolAddress("0x4444444444444444444444444444444444444444"), 54 | smt.SolNumber("1000000000000000000"), 55 | }, 56 | } 57 | 58 | leafEncodings := []string{ 59 | smt.SOL_ADDRESS, 60 | smt.SOL_UINT256, 61 | } 62 | 63 | fmt.Println("=== (1) Of BEGIN ===") 64 | 65 | // (1) make tree 66 | t1, err := smt.Of(values, leafEncodings) 67 | handleError(err) 68 | fmt.Println("Root: ", hexutil.Encode(t1.GetRoot())) 69 | 70 | fmt.Println("=== (1) Of END ===") 71 | 72 | fmt.Println() 73 | fmt.Println("=== (2) CreateTree BEGIN ===") 74 | 75 | // (2.1) create tree 76 | t2, err := smt.CreateTree(leafEncodings) 77 | 78 | // (2.2) add leaf 79 | fmt.Println("=== (2.2) AddLeaf BEGIN ===") 80 | for k, v := range values { 81 | leafHash0, err := t2.AddLeaf(v) 82 | handleError(err) 83 | fmt.Println(k, " AddLeaf: ", hexutil.Encode(leafHash0)) 84 | } 85 | fmt.Println("=== (2.2) AddLeaf END ===") 86 | 87 | // (2.3) make tree 88 | fmt.Println("=== (2.3) MakeTree BEGIN ===") 89 | r3, err := t2.MakeTree() 90 | fmt.Println("MakeTree Root: ", hexutil.Encode(r3)) 91 | fmt.Println("=== (2.3) MakeTree END ===") 92 | 93 | fmt.Println() 94 | // (3) dump 95 | fmt.Println("=== (3) Dump BEGIN ===") 96 | dump, err := t1.TreeMarshal() 97 | handleError(err) 98 | fmt.Println(string(dump)) 99 | fmt.Println("=== (3) Dump END ===") 100 | 101 | fmt.Println() 102 | // (4) load 103 | fmt.Println("=== (4) Load BEGIN ===") 104 | t3, err := smt.Load(dump) 105 | handleError(err) 106 | 107 | entries := t3.Entries() 108 | for k, v := range entries { 109 | if v.Value[0] == smt.SolAddress("0x1111111111111111111111111111111111111111") { 110 | proof, err := t3.GetProofWithIndex(k) 111 | handleError(err) 112 | fmt.Println(fmt.Sprintf("ValueIndex: %v , TreeIndex: %v , Hash: %v , Value: %v", v.ValueIndex, v.TreeIndex, hexutil.Encode(v.Hash), v.Value)) 113 | for pk, pv := range proof { 114 | fmt.Println(fmt.Sprintf("[%v] = %v", pk, hexutil.Encode(pv))) 115 | } 116 | } 117 | } 118 | 119 | fmt.Println("=== (4) Load END ===") 120 | 121 | fmt.Println() 122 | // (5) dump leaf proof 123 | fmt.Println("=== (5) DumpLeafProof BEGIN ===") 124 | 125 | leafProofDump, err := t3.TreeProofMarshal() 126 | handleError(err) 127 | fmt.Println(string(leafProofDump)) 128 | fmt.Println("=== (5) DumpLeafProof END ===") 129 | 130 | fmt.Println() 131 | // (6) verify proof 132 | fmt.Println("=== (6) Verify BEGIN ===") 133 | firstProof, err := t3.GetProofWithIndex(0) 134 | handleError(err) 135 | firstValue := entries[0].Value 136 | 137 | verified, err := t3.Verify(firstProof, firstValue) 138 | handleError(err) 139 | fmt.Println("Verify:", verified) 140 | fmt.Println("=== (6) Verify END ===") 141 | 142 | fmt.Println() 143 | // (7) 144 | fmt.Println("=== (7) VerifyMultiProof BEGIN ===") 145 | mulitProof, err := t3.GetMultiProof([][]interface{}{values[0], values[1]}) 146 | 147 | fmt.Println("Proof:") 148 | for k, v := range mulitProof.Proof { 149 | fmt.Println(fmt.Sprintf("[%v] = %v", k, hexutil.Encode(v))) 150 | } 151 | 152 | fmt.Println("ProofFlags:") 153 | fmt.Println(mulitProof.ProofFlags) 154 | 155 | fmt.Println("Values:") 156 | for _, v := range mulitProof.Values { 157 | fmt.Println(v) 158 | } 159 | 160 | verified, err = t3.VerifyMultiProof(mulitProof) 161 | handleError(err) 162 | fmt.Println("Verify:", verified) 163 | 164 | fmt.Println("=== (7) VerifyMultiProof END ===") 165 | } 166 | 167 | func handleError(err error) { 168 | if err != nil { 169 | panic(err) 170 | } 171 | } 172 | ``` 173 | 174 | Run: [main_run.txt](https://github.com/FantasyJony/openzeppelin-merkle-tree-go/blob/main/docs/main_run.txt) 175 | 176 | ## Dump 177 | 178 | TreeMarshal: [dump_tree.json](https://github.com/FantasyJony/openzeppelin-merkle-tree-go/blob/main/docs/dump_tree.json) 179 | 180 | TreeProofMarshal: [dump_proof.json](https://github.com/FantasyJony/openzeppelin-merkle-tree-go/blob/main/docs/dump_proof.json) 181 | 182 | 183 | ## Solidity 184 | 185 | [![@openzeppelin/contracts](https://img.shields.io/github/package-json/dependency-version/FantasyJony/openzeppelin-merkle-tree-go/@openzeppelin/merkle-tree?filename=merkle-tree-contracts%2Fpackage.json)](https://github.com/OpenZeppelin/openzeppelin-contracts) 186 | [![@openzeppelin/merkle-tree](https://img.shields.io/github/package-json/dependency-version/FantasyJony/openzeppelin-merkle-tree-go/@openzeppelin/contracts?filename=merkle-tree-contracts%2Fpackage.json)](https://github.com/OpenZeppelin/merkle-tree) 187 | 188 | Example [merkle-tree-contracts](https://github.com/FantasyJony/openzeppelin-merkle-tree-go/tree/main/merkle-tree-contracts) 189 | 190 | ### Hardhat 191 | 192 | ``` 193 | cd merkle-tree-contracts 194 | npm install 195 | npx hardhat test 196 | ``` 197 | 198 | ## Go API 199 | 200 | ### `import smt` 201 | 202 | ```go 203 | import ( 204 | smt "github.com/FantasyJony/openzeppelin-merkle-tree-go/standard_merkle_tree" 205 | "github.com/ethereum/go-ethereum/common/hexutil" 206 | ) 207 | ``` 208 | 209 | ### `smt.Of` 210 | 211 | ```go 212 | // Of 213 | tree, err := smt.Of( 214 | [][]interface{}{ 215 | { 216 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 217 | smt.SolNumber("5000000000000000000"), 218 | }, 219 | { 220 | smt.SolAddress("0x2222222222222222222222222222222222222222"), 221 | smt.SolNumber("2500000000000000000"), 222 | }, 223 | }, 224 | []string { 225 | smt.SOL_ADDRESS, 226 | smt.SOL_UINT256, 227 | }, 228 | ) 229 | ``` 230 | 231 | ### `smt.CreateTree` 232 | 233 | ```go 234 | tree, err := smt.CreateTree([]string{smt.SOL_ADDRESS, smt.SOL_UINT256}) 235 | ``` 236 | 237 | ### `smt.Verify` 238 | 239 | ```go 240 | // root 241 | rootHash, err := hexutil.Decode("0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77") 242 | if err != nil { 243 | fmt.Println(err) 244 | } 245 | 246 | // proof 247 | pv, err := hexutil.Decode("0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc") 248 | proof := [][]byte{ 249 | pv, 250 | } 251 | 252 | 253 | // leafEncodings 254 | leafEncodings := []string { 255 | smt.SOL_ADDRESS, 256 | smt.SOL_UINT256, 257 | } 258 | 259 | // value 260 | value := []interface{}{ 261 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 262 | smt.SolNumber("5000000000000000000"), 263 | } 264 | 265 | // leaf 266 | leafHah, err := LeafHash(leafEncodings, value) 267 | if err != nil { 268 | fmt.Println(err) 269 | } 270 | 271 | // Verify 272 | verified, err := smt.Verify(rootHash, leafHah, proof) 273 | ``` 274 | 275 | ### `smt.VerifyMultiProof` 276 | 277 | ```go 278 | // root 279 | root, err := hexutil.Decode("0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77") 280 | if err != nil { 281 | fmt.Println(err) 282 | } 283 | 284 | leafEncodings := []string{ 285 | smt.SOL_ADDRESS, 286 | smt.SOL_UINT256, 287 | } 288 | 289 | value := []interface{}{ 290 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 291 | smt.SolNumber("5000000000000000000"), 292 | } 293 | 294 | // leaf 295 | leaf1, err := smt,LeafHash(leafEncodings, value) 296 | if err != nil { 297 | fmt.Println(err) 298 | } 299 | 300 | leaves := [][]byte{ 301 | leaf1, 302 | } 303 | 304 | // proof 305 | proofValue01, err := hexutil.Decode("0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc") 306 | if err != nil { 307 | fmt.Println(err) 308 | } 309 | proof := [][]byte{ 310 | proofValue01, 311 | } 312 | 313 | // proofFlags 314 | proofFlags := []bool{ 315 | false, 316 | } 317 | 318 | // multiProof 319 | multiProof := &smt.MultiProof{ 320 | Proof: proof, 321 | ProofFlags: proofFlags, 322 | Leaves: leaves, 323 | } 324 | 325 | // VerifyMultiProof 326 | verified, err := smt.VerifyMultiProof(root, multiProof) 327 | ``` 328 | 329 | ### `smt.Load` 330 | 331 | ```go 332 | value := "{\"format\":\"standard-v1\",\"tree\":[\"0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77\",\"0xeb02c421cfa48976e66dfb29120745909ea3a0f843456c263cf8f1253483e283\",\"0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc\"],\"values\":[{\"value\":[\"0x1111111111111111111111111111111111111111\",\"5000000000000000000\"],\"treeIndex\":1},{\"value\":[\"0x2222222222222222222222222222222222222222\",\"2500000000000000000\"],\"treeIndex\":2}],\"leafEncoding\":[\"address\",\"uint256\"]}" 333 | tree , err := smt.Load([]byte(value)) 334 | ``` 335 | 336 | ### `tree.AddLeaf` 337 | 338 | ```go 339 | value := []interface{}{ 340 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 341 | smt.SolNumber("5000000000000000000"), 342 | } 343 | leafHash, err := tree.AddLeaf(value) 344 | ``` 345 | 346 | ### `tree.MakeTree` 347 | ```go 348 | rootHash, err := tree.MakeTree() 349 | ``` 350 | 351 | ### `tree.GetRoot` 352 | 353 | ```go 354 | rootHash := tree.GetRoot() 355 | rootHashValue , err := hexutil.Encode(rootHash) 356 | ``` 357 | 358 | ### `tree.Dump` or `tree.TreeMarshal` 359 | ```go 360 | treeData := tree.Dump() 361 | jsonValue, err := json.Marshal(treeData) 362 | ``` 363 | or 364 | ```go 365 | jsonValue, err := tree.TreeMarshal() 366 | ``` 367 | 368 | ### `tree.GetProof` 369 | ```go 370 | value := []interface{}{ 371 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 372 | smt.SolNumber("5000000000000000000"), 373 | } 374 | proof, err := tree.GetProof(value) 375 | ``` 376 | ### `tree.GetProofWithIndex` 377 | ```go 378 | proof, err := tree.GetProofWithIndex(0) 379 | ``` 380 | 381 | ### `tree.GetMultiProof` 382 | 383 | ```go 384 | value := []interface{}{ 385 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 386 | smt.SolNumber("5000000000000000000"), 387 | } 388 | 389 | leaves := [][]interface{}{ 390 | value, 391 | } 392 | 393 | multiProof, err := tree.GetMultiProof(leaves) 394 | ``` 395 | 396 | ### `tree.GetMultiProofWithIndices` 397 | ```go 398 | indices := []int{ 399 | 0, 400 | } 401 | multiProof, err := tree.GetMultiProofWithIndices(indices) 402 | ``` 403 | 404 | ### `tree.Verify` 405 | 406 | ```go 407 | value := []interface{}{ 408 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 409 | smt.SolNumber("5000000000000000000"), 410 | } 411 | verified, err := tree.Verify(proof, value) 412 | ``` 413 | 414 | ### `tree.VerifyWithIndex` 415 | ```go 416 | verified, err := tree.VerifyWithIndex(proof, 0) 417 | ``` 418 | 419 | ### `tree.VerifyMultiProof` 420 | ```go 421 | verified, err := tree.VerifyMultiProof(multiProof) 422 | ``` 423 | 424 | ### `tree.Entries` 425 | ```go 426 | entries := tree.Entries() 427 | for k, v := range entries { 428 | fmt.Println("ValueIndex:", v.ValueIndex, " TreeIndex:", v.TreeIndex, " Hash:", hexutil.Encode(v.Hash), " Value:", v.Value) 429 | proof, err := tree.GetProofWithIndex(k) 430 | for pk, pv := range proof { 431 | fmt.Println("Proof k:", pk, " v:", hexutil.Encode(pv)) 432 | } 433 | } 434 | ``` 435 | 436 | ### `tree.LeafHash` 437 | 438 | ```go 439 | value := []interface{}{ 440 | smt.SolAddress("0x1111111111111111111111111111111111111111"), 441 | smt.SolNumber("5000000000000000000"), 442 | } 443 | leafHash, err := tree.LeafHash(value) 444 | ``` 445 | -------------------------------------------------------------------------------- /standard_merkle_tree/openzeppelin_standard_tree_test.go: -------------------------------------------------------------------------------- 1 | package standard_merkle_tree 2 | 3 | import ( 4 | "fmt" 5 | "github.com/ethereum/go-ethereum/common/hexutil" 6 | "testing" 7 | ) 8 | 9 | func TestSMTCreateTree(t *testing.T) { 10 | 11 | tree, err := CreateTree([]string{SOL_ADDRESS, SOL_UINT256}) 12 | if err != nil { 13 | fmt.Println("CreateTree ERR: ", err) 14 | } 15 | 16 | leaf1 := []interface{}{ 17 | SolAddress("0x1111111111111111111111111111111111111111"), 18 | SolNumber("5000000000000000000"), 19 | } 20 | 21 | hash1, err := tree.AddLeaf(leaf1) 22 | if err != nil { 23 | fmt.Println("AddLeaf ERR: ", err) 24 | } 25 | fmt.Println("01 AddLeaf Hash: ", hexutil.Encode(hash1)) 26 | 27 | leaf2 := []interface{}{ 28 | SolAddress("0x2222222222222222222222222222222222222222"), 29 | SolNumber("2500000000000000000"), 30 | } 31 | 32 | hash2, err := tree.AddLeaf(leaf2) 33 | if err != nil { 34 | fmt.Println("AddLeaf ERR: ", err) 35 | } 36 | fmt.Println("02 AddLeaf Hash: ", hexutil.Encode(hash2)) 37 | 38 | root, err := tree.MakeTree() 39 | if err != nil { 40 | fmt.Println("MakeTree ERR: ", err) 41 | } 42 | fmt.Println("03 Merkle Root: ", hexutil.Encode(root)) 43 | } 44 | 45 | func TestSMTOf(t *testing.T) { 46 | 47 | leaf1 := []interface{}{ 48 | SolAddress("0x1111111111111111111111111111111111111111"), 49 | SolNumber("5000000000000000000"), 50 | } 51 | 52 | leaf2 := []interface{}{ 53 | SolAddress("0x2222222222222222222222222222222222222222"), 54 | SolNumber("2500000000000000000"), 55 | } 56 | 57 | leaves := [][]interface{}{ 58 | leaf1, 59 | leaf2, 60 | } 61 | 62 | tree, err := Of( 63 | leaves, 64 | []string{ 65 | SOL_ADDRESS, 66 | SOL_UINT256, 67 | }) 68 | 69 | if err != nil { 70 | fmt.Println("Of ERR", err) 71 | } 72 | 73 | root := hexutil.Encode(tree.GetRoot()) 74 | fmt.Println("Merkle Root: ", root) 75 | 76 | proof, err := tree.GetProof(leaf1) 77 | strProof := make([]string, len(proof)) 78 | if err != nil { 79 | fmt.Println("GetProof ERR", err) 80 | } 81 | for _, v := range proof { 82 | strProof = append(strProof, hexutil.Encode(v)) 83 | } 84 | fmt.Println("02 proof: ", strProof) 85 | } 86 | 87 | func TestSMTVerify(t *testing.T) { 88 | 89 | root, err := hexutil.Decode("0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77") 90 | if err != nil { 91 | fmt.Println(err) 92 | } 93 | 94 | leafEncodings := []string{ 95 | SOL_ADDRESS, 96 | SOL_UINT256, 97 | } 98 | 99 | value := []interface{}{ 100 | SolAddress("0x1111111111111111111111111111111111111111"), 101 | SolNumber("5000000000000000000"), 102 | } 103 | 104 | proofValue01, err := hexutil.Decode("0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc") 105 | if err != nil { 106 | fmt.Println(err) 107 | } 108 | proof := [][]byte{ 109 | proofValue01, 110 | } 111 | 112 | leaf, err := LeafHash(leafEncodings, value) 113 | if err != nil { 114 | fmt.Println(err) 115 | } 116 | 117 | verified, err := Verify(root, leaf, proof) 118 | if err != nil { 119 | fmt.Println(err) 120 | } 121 | 122 | fmt.Println(verified) 123 | } 124 | 125 | func TestSMTVerifyMultiProof(t *testing.T) { 126 | 127 | root, err := hexutil.Decode("0xd4dee0beab2d53f2cc83e567171bd2820e49898130a22622b10ead383e90bd77") 128 | if err != nil { 129 | fmt.Println(err) 130 | } 131 | 132 | leafEncodings := []string{ 133 | SOL_ADDRESS, 134 | SOL_UINT256, 135 | } 136 | 137 | value := []interface{}{ 138 | SolAddress("0x1111111111111111111111111111111111111111"), 139 | SolNumber("5000000000000000000"), 140 | } 141 | 142 | leaf1, err := LeafHash(leafEncodings, value) 143 | if err != nil { 144 | fmt.Println(err) 145 | } 146 | 147 | proofValue01, err := hexutil.Decode("0xb92c48e9d7abe27fd8dfd6b5dfdbfb1c9a463f80c712b66f3a5180a090cccafc") 148 | if err != nil { 149 | fmt.Println(err) 150 | } 151 | proof := [][]byte{ 152 | proofValue01, 153 | } 154 | 155 | proofFlags := []bool{ 156 | false, 157 | } 158 | 159 | leaves := [][]byte{ 160 | leaf1, 161 | } 162 | 163 | multiProof := &MultiProof{ 164 | Proof: proof, 165 | ProofFlags: proofFlags, 166 | Leaves: leaves, 167 | } 168 | 169 | verified, err := VerifyMultiProof(root, multiProof) 170 | if err != nil { 171 | fmt.Println(err) 172 | } 173 | 174 | fmt.Println(verified) 175 | } 176 | 177 | func TestGetProofAndVerify(t *testing.T) { 178 | 179 | leaf1 := []interface{}{ 180 | SolAddress("0x1111111111111111111111111111111111111111"), 181 | SolNumber("5000000000000000000"), 182 | } 183 | 184 | leaf2 := []interface{}{ 185 | SolAddress("0x2222222222222222222222222222222222222222"), 186 | SolNumber("2500000000000000000"), 187 | } 188 | 189 | leaves := [][]interface{}{ 190 | leaf1, 191 | leaf2, 192 | } 193 | 194 | tree, err := Of( 195 | leaves, 196 | []string{ 197 | SOL_ADDRESS, 198 | SOL_UINT256, 199 | }) 200 | 201 | if err != nil { 202 | fmt.Println("Of ERR", err) 203 | } 204 | 205 | root := hexutil.Encode(tree.GetRoot()) 206 | fmt.Println("01 Merkle Root: ", root) 207 | 208 | proof, err := tree.GetProof(leaf1) 209 | strProof := make([]string, len(proof)) 210 | if err != nil { 211 | fmt.Println("GetProof ERR", err) 212 | } 213 | 214 | for _, v := range proof { 215 | strProof = append(strProof, hexutil.Encode(v)) 216 | } 217 | fmt.Println("02 proof: ", strProof) 218 | 219 | proof2, err := tree.GetProofWithIndex(0) 220 | strProof2 := make([]string, len(proof2)) 221 | if err != nil { 222 | fmt.Println("GetProof ERR", err) 223 | } 224 | 225 | for _, v := range proof2 { 226 | strProof2 = append(strProof2, hexutil.Encode(v)) 227 | } 228 | fmt.Println("03 proof index: ", strProof2) 229 | 230 | isVerify, err := tree.Verify(proof, leaf1) 231 | if err != nil { 232 | fmt.Println(err) 233 | } 234 | fmt.Println("04 verify: ", isVerify) 235 | 236 | isIndexVerify, err := tree.VerifyWithIndex(proof, 0) 237 | if err != nil { 238 | fmt.Println(err) 239 | } 240 | fmt.Println("05 verifyWithIndex: ", isIndexVerify) 241 | 242 | } 243 | 244 | func TestGetMultiProofAndVerify(t *testing.T) { 245 | 246 | leaf1 := []interface{}{ 247 | SolAddress("0x1111111111111111111111111111111111111111"), 248 | SolNumber("5000000000000000000"), 249 | } 250 | 251 | leaf2 := []interface{}{ 252 | SolAddress("0x2222222222222222222222222222222222222222"), 253 | SolNumber("2500000000000000000"), 254 | } 255 | 256 | leaves := [][]interface{}{ 257 | leaf1, 258 | leaf2, 259 | } 260 | 261 | tree, err := Of( 262 | leaves, 263 | []string{ 264 | SOL_ADDRESS, 265 | SOL_UINT256, 266 | }) 267 | 268 | if err != nil { 269 | fmt.Println("Of ERR", err) 270 | } 271 | 272 | root := hexutil.Encode(tree.GetRoot()) 273 | fmt.Println("01 Merkle Root: ", root) 274 | 275 | proof, err := tree.GetMultiProof([][]interface{}{leaf1}) 276 | if err != nil { 277 | fmt.Println(err) 278 | } 279 | fmt.Println("02 leaf1 proof: ", proof) 280 | 281 | proof02, err := tree.GetMultiProofWithIndices([]int{0}) 282 | fmt.Println("03 leaf1 proof: ", proof02) 283 | 284 | multiValue, err := tree.VerifyMultiProof(proof) 285 | if err != nil { 286 | fmt.Println(err) 287 | } 288 | fmt.Println("04 VerifyMultiProof: ", multiValue) 289 | } 290 | 291 | func TestDumpOf(t *testing.T) { 292 | 293 | leaf1 := []interface{}{ 294 | SolAddress("0x1111111111111111111111111111111111111111"), 295 | SolNumber("5000000000000000000"), 296 | } 297 | 298 | leaf2 := []interface{}{ 299 | SolAddress("0x2222222222222222222222222222222222222222"), 300 | SolNumber("2500000000000000000"), 301 | } 302 | 303 | leaves := [][]interface{}{ 304 | leaf1, 305 | leaf2, 306 | } 307 | 308 | tree, err := Of( 309 | leaves, 310 | []string{ 311 | SOL_ADDRESS, 312 | SOL_UINT256, 313 | }) 314 | 315 | if err != nil { 316 | fmt.Println("Of ERR", err) 317 | } 318 | 319 | root := hexutil.Encode(tree.GetRoot()) 320 | fmt.Println("01 Merkle Root: ", root) 321 | 322 | fmt.Println("02 TreeMarshal") 323 | value, err := tree.TreeMarshal() 324 | if err != nil { 325 | fmt.Println(err) 326 | } 327 | fmt.Println(string(value)) 328 | 329 | fmt.Println("03 TreeUnmarshal") 330 | tree2, err := TreeUnmarshal(value) 331 | value2, err := tree2.TreeMarshal() 332 | if err != nil { 333 | fmt.Println(err) 334 | } 335 | fmt.Println(string(value2)) 336 | 337 | fmt.Println("04 Load") 338 | tree3, err := Load([]byte(string(value2))) 339 | if err != nil { 340 | fmt.Println(err) 341 | } 342 | fmt.Println(hexutil.Encode(tree3.GetRoot())) 343 | } 344 | 345 | func TestDumpLeafProof(t *testing.T) { 346 | 347 | leaf1 := []interface{}{ 348 | SolAddress("0x1111111111111111111111111111111111111111"), 349 | //SolNumber("5000000000000000000"), 350 | SolNumber("500"), 351 | } 352 | 353 | leaf2 := []interface{}{ 354 | SolAddress("0x2222222222222222222222222222222222222222"), 355 | //SolNumber("2500000000000000000"), 356 | SolNumber("250"), 357 | } 358 | 359 | leaves := [][]interface{}{ 360 | leaf1, 361 | leaf2, 362 | } 363 | 364 | tree, err := Of( 365 | leaves, 366 | []string{ 367 | SOL_ADDRESS, 368 | SOL_UINT8, 369 | }) 370 | 371 | if err != nil { 372 | fmt.Println("Of ERR", err) 373 | } 374 | 375 | root := hexutil.Encode(tree.GetRoot()) 376 | fmt.Println("01 Merkle Root: ", root) 377 | 378 | fmt.Println("02 DumpLeafProof") 379 | proof, err := tree.DumpLeafProof() 380 | if err != nil { 381 | fmt.Println(err) 382 | } 383 | 384 | for k, v := range proof.Proofs { 385 | bProof := make([][]byte, len(v.Proof)) 386 | for a, b := range v.Proof { 387 | bProof[a], _ = hexutil.Decode(b) 388 | } 389 | r, err := tree.Verify(bProof, v.getSolValueUnmarshal(proof.LeafEncoding)) 390 | if err != nil { 391 | fmt.Println("Verify ERR: ", err) 392 | return 393 | } 394 | fmt.Println("03 Verify Proof ", k, " :", r) 395 | } 396 | 397 | fmt.Println("04 TreeProofMarshal") 398 | proofJson, err := tree.TreeProofMarshal() 399 | if err != nil { 400 | fmt.Println("TreeProofMarshal ERR: ", err) 401 | } 402 | fmt.Println(string(proofJson)) 403 | } 404 | 405 | func TestArrayArg(t *testing.T) { 406 | 407 | values := [][]interface{}{ 408 | { 409 | SolAddress("0x1111111111111111111111111111111111111111"), 410 | SolNumberArray([]interface{}{ 411 | "5000000000000000000", "2500000000000000000", 412 | }), 413 | SolBoolArray([]interface{}{ 414 | true, 415 | false, 416 | }), 417 | }, 418 | { 419 | SolAddress("0x2222222222222222222222222222222222222222"), 420 | SolNumberArray([]interface{}{ 421 | "2500000000000000000", "5000000000000000000", 422 | }), 423 | SolBoolArray([]interface{}{ 424 | false, 425 | true, 426 | }), 427 | }, 428 | } 429 | 430 | tree, err := Of( 431 | values, 432 | []string{ 433 | SOL_ADDRESS, 434 | SOL_UINT256_ARRAY, 435 | SOL_BOOL_ARRAY, 436 | }) 437 | 438 | if err != nil { 439 | fmt.Println("Of ERR: ", err) 440 | } 441 | 442 | root := hexutil.Encode(tree.GetRoot()) 443 | fmt.Println("01 Merkle Root: ", root) 444 | 445 | proof, err := tree.GetProof(values[0]) 446 | strProof := make([]string, len(proof)) 447 | if err != nil { 448 | fmt.Println("GetProof ERR", err) 449 | } 450 | for _, v := range proof { 451 | strProof = append(strProof, hexutil.Encode(v)) 452 | } 453 | fmt.Println("02 proof: ", strProof) 454 | 455 | fmt.Println("03 TreeMarshal") 456 | value, err := tree.TreeMarshal() 457 | if err != nil { 458 | fmt.Println(err) 459 | } 460 | fmt.Println(string(value)) 461 | 462 | fmt.Println("04 TreeUnmarshal") 463 | tree2, err := TreeUnmarshal(value) 464 | value2, err := tree2.TreeMarshal() 465 | if err != nil { 466 | fmt.Println(err) 467 | } 468 | fmt.Println(string(value2)) 469 | } 470 | 471 | func TestAbiArg(t *testing.T) { 472 | values := [][]interface{}{ 473 | { 474 | SolAddress("0x1111111111111111111111111111111111111111"), 475 | SolNumber("1"), 476 | SolNumber("2"), 477 | SolNumber("3"), 478 | //SolNumberArray([]interface{}{ 479 | // "1", "2", "3", 480 | //}), 481 | }, 482 | { 483 | SolAddress("0x1111111111111111111111111111111111111111"), 484 | SolNumber("0"), 485 | SolNumber("2"), 486 | SolNumber("1"), 487 | //SolNumberArray([]interface{}{ 488 | // "0", "1", "2", 489 | //}), 490 | }, 491 | } 492 | 493 | leafEncodings := []string{ 494 | SOL_ADDRESS, 495 | SOL_UINT8, 496 | SOL_UINT88, 497 | SOL_UINT128, 498 | //SOL_UINT8_ARRAY, 499 | } 500 | 501 | tree, err := Of( 502 | values, 503 | leafEncodings) 504 | 505 | if err != nil { 506 | fmt.Println("Of ERR: ", err) 507 | } 508 | 509 | root := hexutil.Encode(tree.GetRoot()) 510 | fmt.Println("01 Merkle Root: ", root) 511 | 512 | proof, err := tree.GetProof(values[0]) 513 | strProof := make([]string, len(proof)) 514 | if err != nil { 515 | fmt.Println("GetProof ERR", err) 516 | } 517 | for _, v := range proof { 518 | strProof = append(strProof, hexutil.Encode(v)) 519 | } 520 | fmt.Println("02 proof: ", strProof) 521 | 522 | fmt.Println("03 TreeMarshal") 523 | value, err := tree.TreeMarshal() 524 | if err != nil { 525 | fmt.Println(err) 526 | } 527 | fmt.Println(string(value)) 528 | 529 | fmt.Println("04 TreeUnmarshal") 530 | tree2, err := TreeUnmarshal(value) 531 | value2, err := tree2.TreeMarshal() 532 | if err != nil { 533 | fmt.Println(err) 534 | } 535 | fmt.Println(string(value2)) 536 | } 537 | 538 | func TestStringArg(t *testing.T) { 539 | 540 | values := [][]interface{}{ 541 | { 542 | SolString("a"), 543 | }, 544 | { 545 | SolString("b"), 546 | }, 547 | { 548 | SolString("c"), 549 | }, 550 | { 551 | SolString("d"), 552 | }, 553 | } 554 | 555 | leafEncodings := []string{ 556 | SOL_STRING, 557 | } 558 | 559 | t1, err := Of(values, leafEncodings) 560 | if err != nil { 561 | println("error:", err.Error()) 562 | return 563 | } 564 | fmt.Println("Root: ", hexutil.Encode(t1.GetRoot())) 565 | } 566 | -------------------------------------------------------------------------------- /standard_merkle_tree/solidity_value.go: -------------------------------------------------------------------------------- 1 | package standard_merkle_tree 2 | 3 | import ( 4 | "encoding/hex" 5 | "github.com/ethereum/go-ethereum/common" 6 | "math/big" 7 | ) 8 | 9 | func SolAddress(value string) common.Address { 10 | return common.HexToAddress(value) 11 | } 12 | 13 | func SolAddressArray(value []interface{}) []common.Address { 14 | list := make([]common.Address, len(value)) 15 | for k, v := range value { 16 | list[k] = SolAddress(v.(string)) 17 | } 18 | return list 19 | } 20 | 21 | func SolNumber(value string) *big.Int { 22 | bigNumber := big.NewInt(0) 23 | bigNumber.SetString(value, 10) 24 | return bigNumber 25 | } 26 | 27 | func SolNumberArray(value []interface{}) []*big.Int { 28 | list := make([]*big.Int, len(value)) 29 | for k, v := range value { 30 | list[k] = SolNumber(v.(string)) 31 | } 32 | return list 33 | } 34 | 35 | func SolBytes(value string) []byte { 36 | r, _ := hex.DecodeString(value) 37 | return r 38 | } 39 | 40 | func SolBytesArray(value []interface{}) [][]byte { 41 | list := make([][]byte, len(value)) 42 | for k, v := range value { 43 | list[k] = SolBytes(v.(string)) 44 | } 45 | return list 46 | } 47 | 48 | func SolString(value string) string { 49 | return value 50 | } 51 | 52 | func SolStringArray(value []interface{}) []string { 53 | list := make([]string, len(value)) 54 | for k, v := range value { 55 | list[k] = SolString(v.(string)) 56 | } 57 | return list 58 | } 59 | 60 | func SolBool(value bool) bool { 61 | return value 62 | } 63 | 64 | func SolBoolArray(value []interface{}) []bool { 65 | list := make([]bool, len(value)) 66 | for k, v := range value { 67 | list[k] = v.(bool) 68 | } 69 | return list 70 | } 71 | 72 | func ToSolValue(value interface{}, leafEncoding string) interface{} { 73 | 74 | switch leafEncoding { 75 | case SOL_ADDRESS: 76 | { 77 | instance, ok := value.(string) 78 | if ok { 79 | return SolAddress(instance) 80 | } 81 | } 82 | case SOL_ADDRESS_ARRAY: 83 | { 84 | instance, ok := value.([]interface{}) 85 | if ok { 86 | return SolAddressArray(instance) 87 | } 88 | } 89 | 90 | case SOL_INT8, SOL_INT16, SOL_INT24, SOL_INT32, SOL_INT40, SOL_INT48, SOL_INT56, SOL_INT64, SOL_INT72, SOL_INT80, SOL_INT88, SOL_INT96, SOL_INT104, SOL_INT112, SOL_INT120, SOL_INT128, SOL_INT136, SOL_INT144, SOL_INT152, SOL_INT160, SOL_INT168, SOL_INT176, SOL_INT184, SOL_INT192, SOL_INT200, SOL_INT208, SOL_INT216, SOL_INT224, SOL_INT232, SOL_INT240, SOL_INT248, SOL_INT256: 91 | { 92 | instance, ok := value.(string) 93 | if ok { 94 | return SolNumber(instance) 95 | } 96 | } 97 | case SOL_INT8_ARRAY, SOL_INT16_ARRAY, SOL_INT24_ARRAY, SOL_INT32_ARRAY, SOL_INT40_ARRAY, SOL_INT48_ARRAY, SOL_INT56_ARRAY, SOL_INT64_ARRAY, SOL_INT72_ARRAY, SOL_INT80_ARRAY, SOL_INT88_ARRAY, SOL_INT96_ARRAY, SOL_INT104_ARRAY, SOL_INT112_ARRAY, SOL_INT120_ARRAY, SOL_INT128_ARRAY, SOL_INT136_ARRAY, SOL_INT144_ARRAY, SOL_INT152_ARRAY, SOL_INT160_ARRAY, SOL_INT168_ARRAY, SOL_INT176_ARRAY, SOL_INT184_ARRAY, SOL_INT192_ARRAY, SOL_INT200_ARRAY, SOL_INT208_ARRAY, SOL_INT216_ARRAY, SOL_INT224_ARRAY, SOL_INT232_ARRAY, SOL_INT240_ARRAY, SOL_INT248_ARRAY, SOL_INT256_ARRAY: 98 | { 99 | instance, ok := value.([]interface{}) 100 | if ok { 101 | return SolNumberArray(instance) 102 | } 103 | } 104 | case SOL_UINT8, SOL_UINT16, SOL_UINT24, SOL_UINT32, SOL_UINT40, SOL_UINT48, SOL_UINT56, SOL_UINT64, SOL_UINT72, SOL_UINT80, SOL_UINT88, SOL_UINT96, SOL_UINT104, SOL_UINT112, SOL_UINT120, SOL_UINT128, SOL_UINT136, SOL_UINT144, SOL_UINT152, SOL_UINT160, SOL_UINT168, SOL_UINT176, SOL_UINT184, SOL_UINT192, SOL_UINT200, SOL_UINT208, SOL_UINT216, SOL_UINT224, SOL_UINT232, SOL_UINT240, SOL_UINT248, SOL_UINT256: 105 | { 106 | instance, ok := value.(string) 107 | if ok { 108 | return SolNumber(instance) 109 | } 110 | } 111 | case SOL_UINT8_ARRAY, SOL_UINT16_ARRAY, SOL_UINT24_ARRAY, SOL_UINT32_ARRAY, SOL_UINT40_ARRAY, SOL_UINT48_ARRAY, SOL_UINT56_ARRAY, SOL_UINT64_ARRAY, SOL_UINT72_ARRAY, SOL_UINT80_ARRAY, SOL_UINT88_ARRAY, SOL_UINT96_ARRAY, SOL_UINT104_ARRAY, SOL_UINT112_ARRAY, SOL_UINT120_ARRAY, SOL_UINT128_ARRAY, SOL_UINT136_ARRAY, SOL_UINT144_ARRAY, SOL_UINT152_ARRAY, SOL_UINT160_ARRAY, SOL_UINT168_ARRAY, SOL_UINT176_ARRAY, SOL_UINT184_ARRAY, SOL_UINT192_ARRAY, SOL_UINT200_ARRAY, SOL_UINT208_ARRAY, SOL_UINT216_ARRAY, SOL_UINT224_ARRAY, SOL_UINT232_ARRAY, SOL_UINT240_ARRAY, SOL_UINT248_ARRAY, SOL_UINT256_ARRAY: 112 | { 113 | instance, ok := value.([]interface{}) 114 | if ok { 115 | return SolNumberArray(instance) 116 | } 117 | } 118 | case SOL_BYTES1, SOL_BYTES2, SOL_BYTES3, SOL_BYTES4, SOL_BYTES5, SOL_BYTES6, SOL_BYTES7, SOL_BYTES8, SOL_BYTES9, SOL_BYTES10, SOL_BYTES11, SOL_BYTES12, SOL_BYTES13, SOL_BYTES14, SOL_BYTES15, SOL_BYTES16, SOL_BYTES17, SOL_BYTES18, SOL_BYTES19, SOL_BYTES20, SOL_BYTES21, SOL_BYTES22, SOL_BYTES23, SOL_BYTES24, SOL_BYTES25, SOL_BYTES26, SOL_BYTES27, SOL_BYTES28, SOL_BYTES29, SOL_BYTES30, SOL_BYTES31, SOL_BYTES32: 119 | { 120 | instance, _ := value.(string) 121 | return SolBytes(instance) 122 | } 123 | case SOL_BYTES1_ARRAY, SOL_BYTES2_ARRAY, SOL_BYTES3_ARRAY, SOL_BYTES4_ARRAY, SOL_BYTES5_ARRAY, SOL_BYTES6_ARRAY, SOL_BYTES7_ARRAY, SOL_BYTES8_ARRAY, SOL_BYTES9_ARRAY, SOL_BYTES10_ARRAY, SOL_BYTES11_ARRAY, SOL_BYTES12_ARRAY, SOL_BYTES13_ARRAY, SOL_BYTES14_ARRAY, SOL_BYTES15_ARRAY, SOL_BYTES16_ARRAY, SOL_BYTES17_ARRAY, SOL_BYTES18_ARRAY, SOL_BYTES19_ARRAY, SOL_BYTES20_ARRAY, SOL_BYTES21_ARRAY, SOL_BYTES22_ARRAY, SOL_BYTES23_ARRAY, SOL_BYTES24_ARRAY, SOL_BYTES25_ARRAY, SOL_BYTES26_ARRAY, SOL_BYTES27_ARRAY, SOL_BYTES28_ARRAY, SOL_BYTES29_ARRAY, SOL_BYTES30_ARRAY, SOL_BYTES31_ARRAY, SOL_BYTES32_ARRAY: 124 | { 125 | instance, ok := value.([]interface{}) 126 | if ok { 127 | return SolBytesArray(instance) 128 | } 129 | } 130 | case SOL_STRING, SOL_BYTES: 131 | { 132 | instance, ok := value.(string) 133 | if ok { 134 | return SolBytes(instance) 135 | } 136 | } 137 | case SOL_STRING_ARRAY, SOL_BYTES_ARRAY: 138 | { 139 | instance, ok := value.([]interface{}) 140 | if ok { 141 | return SolBytesArray(instance) 142 | } 143 | } 144 | case SOL_BOOL: 145 | { 146 | instance, ok := value.(bool) 147 | if ok { 148 | return SolBool(instance) 149 | } 150 | } 151 | case SOL_BOOL_ARRAY: 152 | { 153 | instance, ok := value.([]interface{}) 154 | if ok { 155 | return SolBoolArray(instance) 156 | } 157 | } 158 | } 159 | 160 | return nil 161 | } 162 | 163 | func ToJsonValue(value interface{}, leafEncoding string) interface{} { 164 | switch leafEncoding { 165 | case SOL_ADDRESS: 166 | { 167 | instance, ok := value.(common.Address) 168 | if ok { 169 | return instance.Hex() 170 | } 171 | } 172 | case SOL_ADDRESS_ARRAY: 173 | { 174 | instance, ok := value.([]common.Address) 175 | if ok { 176 | list := make([]string, len(instance)) 177 | for k, v := range instance { 178 | list[k] = v.Hex() 179 | } 180 | return list 181 | } 182 | } 183 | case SOL_INT8, SOL_INT16, SOL_INT24, SOL_INT32, SOL_INT40, SOL_INT48, SOL_INT56, SOL_INT64, SOL_INT72, SOL_INT80, SOL_INT88, SOL_INT96, SOL_INT104, SOL_INT112, SOL_INT120, SOL_INT128, SOL_INT136, SOL_INT144, SOL_INT152, SOL_INT160, SOL_INT168, SOL_INT176, SOL_INT184, SOL_INT192, SOL_INT200, SOL_INT208, SOL_INT216, SOL_INT224, SOL_INT232, SOL_INT240, SOL_INT248, SOL_INT256: 184 | { 185 | instance, ok := value.(*big.Int) 186 | if ok { 187 | return instance.String() 188 | } 189 | } 190 | case SOL_INT8_ARRAY, SOL_INT16_ARRAY, SOL_INT24_ARRAY, SOL_INT32_ARRAY, SOL_INT40_ARRAY, SOL_INT48_ARRAY, SOL_INT56_ARRAY, SOL_INT64_ARRAY, SOL_INT72_ARRAY, SOL_INT80_ARRAY, SOL_INT88_ARRAY, SOL_INT96_ARRAY, SOL_INT104_ARRAY, SOL_INT112_ARRAY, SOL_INT120_ARRAY, SOL_INT128_ARRAY, SOL_INT136_ARRAY, SOL_INT144_ARRAY, SOL_INT152_ARRAY, SOL_INT160_ARRAY, SOL_INT168_ARRAY, SOL_INT176_ARRAY, SOL_INT184_ARRAY, SOL_INT192_ARRAY, SOL_INT200_ARRAY, SOL_INT208_ARRAY, SOL_INT216_ARRAY, SOL_INT224_ARRAY, SOL_INT232_ARRAY, SOL_INT240_ARRAY, SOL_INT248_ARRAY, SOL_INT256_ARRAY: 191 | { 192 | instance, ok := value.([]*big.Int) 193 | if ok { 194 | list := make([]string, len(instance)) 195 | for k, v := range instance { 196 | list[k] = v.String() 197 | } 198 | return list 199 | } 200 | 201 | } 202 | case SOL_UINT8, SOL_UINT16, SOL_UINT24, SOL_UINT32, SOL_UINT40, SOL_UINT48, SOL_UINT56, SOL_UINT64, SOL_UINT72, SOL_UINT80, SOL_UINT88, SOL_UINT96, SOL_UINT104, SOL_UINT112, SOL_UINT120, SOL_UINT128, SOL_UINT136, SOL_UINT144, SOL_UINT152, SOL_UINT160, SOL_UINT168, SOL_UINT176, SOL_UINT184, SOL_UINT192, SOL_UINT200, SOL_UINT208, SOL_UINT216, SOL_UINT224, SOL_UINT232, SOL_UINT240, SOL_UINT248, SOL_UINT256: 203 | { 204 | instance, ok := value.(*big.Int) 205 | if ok { 206 | return instance.String() 207 | } 208 | } 209 | case SOL_UINT8_ARRAY, SOL_UINT16_ARRAY, SOL_UINT24_ARRAY, SOL_UINT32_ARRAY, SOL_UINT40_ARRAY, SOL_UINT48_ARRAY, SOL_UINT56_ARRAY, SOL_UINT64_ARRAY, SOL_UINT72_ARRAY, SOL_UINT80_ARRAY, SOL_UINT88_ARRAY, SOL_UINT96_ARRAY, SOL_UINT104_ARRAY, SOL_UINT112_ARRAY, SOL_UINT120_ARRAY, SOL_UINT128_ARRAY, SOL_UINT136_ARRAY, SOL_UINT144_ARRAY, SOL_UINT152_ARRAY, SOL_UINT160_ARRAY, SOL_UINT168_ARRAY, SOL_UINT176_ARRAY, SOL_UINT184_ARRAY, SOL_UINT192_ARRAY, SOL_UINT200_ARRAY, SOL_UINT208_ARRAY, SOL_UINT216_ARRAY, SOL_UINT224_ARRAY, SOL_UINT232_ARRAY, SOL_UINT240_ARRAY, SOL_UINT248_ARRAY, SOL_UINT256_ARRAY: 210 | { 211 | instance, ok := value.([]*big.Int) 212 | if ok { 213 | list := make([]string, len(instance)) 214 | for k, v := range instance { 215 | list[k] = v.String() 216 | } 217 | return list 218 | } 219 | } 220 | case SOL_BYTES1, SOL_BYTES2, SOL_BYTES3, SOL_BYTES4, SOL_BYTES5, SOL_BYTES6, SOL_BYTES7, SOL_BYTES8, SOL_BYTES9, SOL_BYTES10, SOL_BYTES11, SOL_BYTES12, SOL_BYTES13, SOL_BYTES14, SOL_BYTES15, SOL_BYTES16, SOL_BYTES17, SOL_BYTES18, SOL_BYTES19, SOL_BYTES20, SOL_BYTES21, SOL_BYTES22, SOL_BYTES23, SOL_BYTES24, SOL_BYTES25, SOL_BYTES26, SOL_BYTES27, SOL_BYTES28, SOL_BYTES29, SOL_BYTES30, SOL_BYTES31, SOL_BYTES32: 221 | { 222 | instance, ok := value.(string) 223 | if ok { 224 | return SolBytes(instance) 225 | } 226 | } 227 | case SOL_BYTES1_ARRAY, SOL_BYTES2_ARRAY, SOL_BYTES3_ARRAY, SOL_BYTES4_ARRAY, SOL_BYTES5_ARRAY, SOL_BYTES6_ARRAY, SOL_BYTES7_ARRAY, SOL_BYTES8_ARRAY, SOL_BYTES9_ARRAY, SOL_BYTES10_ARRAY, SOL_BYTES11_ARRAY, SOL_BYTES12_ARRAY, SOL_BYTES13_ARRAY, SOL_BYTES14_ARRAY, SOL_BYTES15_ARRAY, SOL_BYTES16_ARRAY, SOL_BYTES17_ARRAY, SOL_BYTES18_ARRAY, SOL_BYTES19_ARRAY, SOL_BYTES20_ARRAY, SOL_BYTES21_ARRAY, SOL_BYTES22_ARRAY, SOL_BYTES23_ARRAY, SOL_BYTES24_ARRAY, SOL_BYTES25_ARRAY, SOL_BYTES26_ARRAY, SOL_BYTES27_ARRAY, SOL_BYTES28_ARRAY, SOL_BYTES29_ARRAY, SOL_BYTES30_ARRAY, SOL_BYTES31_ARRAY, SOL_BYTES32_ARRAY: 228 | { 229 | instance, ok := value.([]interface{}) 230 | if ok { 231 | return SolBytesArray(instance) 232 | } 233 | } 234 | case SOL_STRING, SOL_BYTES: 235 | { 236 | instance, ok := value.(string) 237 | if ok { 238 | return SolBytes(instance) 239 | } 240 | } 241 | case SOL_STRING_ARRAY, SOL_BYTES_ARRAY: 242 | { 243 | instance, ok := value.([]interface{}) 244 | if ok { 245 | return SolBytesArray(instance) 246 | } 247 | } 248 | case SOL_BOOL: 249 | { 250 | instance, ok := value.(bool) 251 | if ok { 252 | return instance 253 | } 254 | } 255 | case SOL_BOOL_ARRAY: 256 | { 257 | instance, ok := value.([]bool) 258 | if ok { 259 | return instance 260 | } 261 | } 262 | } 263 | return "" 264 | } 265 | 266 | // https://github.com/ethereum/go-ethereum/blob/master/accounts/abi/type_test.go 267 | func abiArgConvert(types []string, values ...interface{}) []interface{} { 268 | //convertValue := make([]interface{}, len(values)) 269 | for k, v := range types { 270 | switch v { 271 | case SOL_UINT8: 272 | { 273 | instance, ok := values[k].(*big.Int) 274 | if ok { 275 | values[k] = uint8(instance.Uint64()) 276 | } 277 | } 278 | break 279 | case SOL_UINT16: 280 | { 281 | instance, ok := values[k].(*big.Int) 282 | if ok { 283 | values[k] = uint16(instance.Uint64()) 284 | } 285 | } 286 | break 287 | case SOL_UINT32: 288 | { 289 | instance, ok := values[k].(*big.Int) 290 | if ok { 291 | values[k] = uint32(instance.Uint64()) 292 | } 293 | } 294 | break 295 | case SOL_UINT64: 296 | { 297 | instance, ok := values[k].(*big.Int) 298 | if ok { 299 | values[k] = instance.Uint64() 300 | } 301 | } 302 | break 303 | case SOL_INT8: 304 | { 305 | instance, ok := values[k].(*big.Int) 306 | if ok { 307 | values[k] = int8(instance.Int64()) 308 | } 309 | } 310 | break 311 | case SOL_INT16: 312 | { 313 | instance, ok := values[k].(*big.Int) 314 | if ok { 315 | values[k] = int16(instance.Int64()) 316 | } 317 | } 318 | break 319 | case SOL_INT32: 320 | { 321 | instance, ok := values[k].(*big.Int) 322 | if ok { 323 | values[k] = int32(instance.Int64()) 324 | } 325 | } 326 | break 327 | case SOL_INT64: 328 | { 329 | instance, ok := values[k].(*big.Int) 330 | if ok { 331 | values[k] = instance.Int64() 332 | } 333 | } 334 | break 335 | case SOL_UINT8_ARRAY: 336 | { 337 | instance, ok := values[k].([]*big.Int) 338 | if ok { 339 | list := make([]uint8, len(instance)) 340 | for ik, iv := range instance { 341 | list[ik] = uint8(iv.Uint64()) 342 | } 343 | values[k] = list 344 | } 345 | } 346 | break 347 | case SOL_UINT16_ARRAY: 348 | { 349 | instance, ok := values[k].([]*big.Int) 350 | if ok { 351 | list := make([]uint16, len(instance)) 352 | for ik, iv := range instance { 353 | list[ik] = uint16(iv.Uint64()) 354 | } 355 | values[k] = list 356 | } 357 | } 358 | break 359 | case SOL_UINT32_ARRAY: 360 | { 361 | instance, ok := values[k].([]*big.Int) 362 | if ok { 363 | list := make([]uint32, len(instance)) 364 | for ik, iv := range instance { 365 | list[ik] = uint32(iv.Uint64()) 366 | } 367 | values[k] = list 368 | } 369 | } 370 | break 371 | case SOL_UINT64_ARRAY: 372 | { 373 | instance, ok := values[k].([]*big.Int) 374 | if ok { 375 | list := make([]uint64, len(instance)) 376 | for ik, iv := range instance { 377 | list[ik] = uint64(iv.Uint64()) 378 | } 379 | values[k] = list 380 | } 381 | } 382 | break 383 | case SOL_INT8_ARRAY: 384 | { 385 | instance, ok := values[k].([]*big.Int) 386 | if ok { 387 | list := make([]int8, len(instance)) 388 | for ik, iv := range instance { 389 | list[ik] = int8(iv.Int64()) 390 | } 391 | values[k] = list 392 | } 393 | } 394 | break 395 | case SOL_INT16_ARRAY: 396 | { 397 | instance, ok := values[k].([]*big.Int) 398 | if ok { 399 | list := make([]int16, len(instance)) 400 | for ik, iv := range instance { 401 | list[ik] = int16(iv.Int64()) 402 | } 403 | values[k] = list 404 | } 405 | } 406 | break 407 | case SOL_INT32_ARRAY: 408 | { 409 | instance, ok := values[k].([]*big.Int) 410 | if ok { 411 | list := make([]int32, len(instance)) 412 | for ik, iv := range instance { 413 | list[ik] = int32(iv.Int64()) 414 | } 415 | values[k] = list 416 | } 417 | } 418 | break 419 | case SOL_INT64_ARRAY: 420 | { 421 | instance, ok := values[k].([]*big.Int) 422 | if ok { 423 | list := make([]int64, len(instance)) 424 | for ik, iv := range instance { 425 | list[ik] = int64(iv.Int64()) 426 | } 427 | values[k] = list 428 | } 429 | } 430 | break 431 | } 432 | } 433 | return values 434 | } 435 | --------------------------------------------------------------------------------